Programlama yapalım ve Öğrenelim. - Delphi Eğitim98
  Ana Sayfa
  .NET Eğitim Notları
  Visual C# .NET Örnek Kodları
  VisualBasic.NET Örnek Kodları
  J# Örnekleri
  ASP.NET Örnek Kodları
  Delphi Eğitim
  => Delphi Eğitim1
  => Delphi Eğitim2
  => Delphi Eğitim3
  => Delphi Eğitim4
  => Delphi Eğitim5
  => Delphi Eğitim6
  => Delphi Eğitim7
  => Delphi Eğitim8
  => Delphi Eğitim9
  => Delphi Eğitim10
  => Delphi Eğitim11
  => Delphi Eğitim13
  => Delphi Eğitim14
  => Delphi Eğitim15
  => Delphi Eğitim16
  => Delphi Eğitim17
  => Delphi Eğitim18
  => Delphi Eğitim19
  => Delphi Eğitim20
  => Delphi Eğitim21
  => Delphi Eğitim22
  => Delphi Eğitim23
  => Delphi Eğitim24
  => Delphi Eğitim25
  => Delphi Eğitim26
  => Delphi Eğitim27
  => Delphi Eğitim28
  => Delphi Eğitim29
  => Delphi Eğitim30
  => Delphi Eğtim31
  => Delphi Eğitim32
  => Delphi Eğitim33
  => Delphi Eğitim34
  => Delphi Eğitim35
  => Delphi Eğitim36
  => Delphi Eğitim37
  => Delphi Eğitim38
  => Delphi Eğitim39
  => Delphi Eğitim40
  => Delphi Eğitim41
  => Delphi Eğitim42
  => Delphi Eğitim43
  => Delphi Eğitim44
  => Delphi Eğitim45
  => Delphi Eğitim46
  => Delphi Eğitim47
  => Delphi Eğitim48
  => Delphi Eğitim49
  => Delphi Eğitim50
  => Delphi Eğitim51
  => Delphi Eğitim52
  => Delphi Eğitim53
  => Delphi Eğitim54
  => Delphi Eğitim55
  => Delphi Eğitim56
  => Delphi Eğitim57
  => Delphi Eğitim58
  => Delphi Eğitim59
  => Delphi Eğitim60
  => Delphi Eğitim61
  => Delphi Eğitim62
  => Delphi Eğitim63
  => Delphi Eğitim64
  => Delphi Eğitim65
  => Delphi Eğitim66
  => Delphi Eğitim67
  => Delphi Eğitim68
  => Delphi Eğitim69
  => Delphi Eğitim70
  => Delphi Eğitim71
  => Delphi Eğitim72
  => Delphi Eğitim73
  => Delphi Eğitim74
  => Delphi Eğitim75
  => Delphi Eğitim76
  => Delphi Eğitim77
  => Delphi Eğitim78
  => Delphi Eğitim79
  => Delphi Eğitim80
  => Delphi Eğitim81
  => Delphi Eğitim82
  => Delphi Eğitim83
  => Delphi Eğitim84
  => Delphi Eğitim85
  => Delphi Eğitim86
  => Delphi Eğitim87
  => Delphi Eğitim88
  => Delphi Eğitim89
  => Delphi Eğitim90
  => Delphi Eğitim91
  => Delphi Eğitim92
  => Delphi Eğitim93
  => Delphi Eğitim94
  => Delphi Eğitim95
  => Delphi Eğitim96
  => Delphi Eğitim97
  => Delphi Eğitim98
  => Delphi Eğitim99
  => Delphi Eğitim100
  => Delphi Eğitim101
  => Delphi Eğitim102
  => Delphi Eğitim103
  => Delphi Eğitim104
  => Delphi Eğitim105
  => Delphi Eğitim106
  => Delphi Eğitim107
  => Delphi Eğitim108
  => Delphi Eğitim109
  => Delphi Eğitim110
  => Delphi Eğitim111
  => Delphi Eğitim112
  => Delphi Eğitim113
  => Delphi Eğitim114
  => Delphi Eğitim115
  => Delphi Eğitim116
  => Delphi Eğitim117
  => Delphi Eğitim118
  => Delphi Eğitim119
  => Delphi Eğitim120
  => Delphi Eğitim121
  => Delphi Eğitim122
  => Delphi Eğitim123
  => Delphi Eğitim124
  => Delphi Eğitim125
  => Delphi Eğitim126
  => Delphi Eğitim127
  => Delphi Eğitim128
  => Delphi Eğitim129
  => Delphi Eğitim130
  => Delphi Eğitim131
  => Delphi Eğitim132
  => Delphi Eğitim133
  => Delphi Eğitim134
  => Delphi Eğitim135
  => Delphi Eğitim136
  => Delphi Eğitim137
  => Delphi Eğitim138
  => Delphi Eğitim139
  => Delphi Eğitim140
  => Delphi Eğitim141
  => Delphi Eğitim142
  => Delphi Eğitim143
  => Delphi Eğitim144
  => Delphi Eğitim145
  => Delphi Eğitim146
  => Delphi eğitim147
  => Delphi Eğitim148
  => Delphi Eğitim149
  => Delphi Eğitim150
  => Delphi Eğitim151
  => Delphi Eğitim152
  => Delphi Eğitim153
  => Delphi Eğitim154
  => Delphi Eğitim155
  => Delphi Eğitim156
  => Delphi Eğitim157
  => Delphi Eğitim158
  => Delphi Eğitim159
  => Delphi Eğitim160
  => Delphi Eğitim161
  => Delphi Eğitim162
  => Delphi Eğitim164
  => Delphi Eğitim165
  => Delphi Eğitim166
  => Delphi Eğitim167
  => Delphi Eğitim168
  => Delphi Eğitim169
  => Delphi Eğitim170
  => Delphi Eğitim171
  => Delphi Eğitim172
  => Delphi Eğitim173
  => Delphi Eğitim174
  => Delphi Eğitim175
  => Delphi Eğitim176
  => Delphi Eğitim177
  => Delphi Eğitim178
  => Delphi Eğitim179
  => Delphi Eğitim180
  => Delphi Eğitim181
  => Delphi Eğitim182
  => Delphi Eğitim183
  => Delphi Eğitim184
  => Delphi Eğitim185
  => Delphi Eğitim186
  => Delphi Eğitim187
  => Delphi Eğitim188
  => Delphi Eğitim189
  => Delphi Eğitim190
  => Delphi Eğitim191
  => Delphi Eğitim192
  => Delphi Eğitim193
  => Delphi Eğitim194
  => Delphi Eğitim195
  => Delphi Eğitim196
  => Delphi Eğitim197
  => Delphi Eğitim198
  => Delphi Eğitim199
  => Delphi Eğitim200
  => Delphi Eğitim201
  => Delphi Eğitim202
  => Delphi Eğitim203
  => Delphi Eğitim204
  => Delphi Eğitim205
  => Delphi Eğitim206
  => Delphi Eğitim207
  => Delphi Eğitim208
  => Delphi Eğitim209
  => Delphi Eğitim210
  => Delphi Eğitim211
  => Delphi Eğitim212
  => Delphi Eğitim213
  => Delphi Eğitim214
  => Delphi Eğitim215
  => Delphi Eğitim216
  => Delphi Eğitim217
  => Delphi Eğitim218
  => Delphi Eğitim219
  => Delphi Eğitim220
  => Delphi Eğitim221
  => Delphi Eğitim222
  => Delphi Eğitim223
  => Delphi Eğitim224
  => Delphi Eğitim225
  => Delphi Eğitim226
  => Delphi Eğitim227
  => Delphi Eğitim228
  => Delphi Eğitim229
  => Delphi Eğitim230
  => Delphi Eğitim231
  => Delphi Eğitim232
  => Delphi Eğitim233
  => Delphi Eğitim234
  => Delphi Eğitim235
  => Delphi Eğitim236
  => Delphi Eğitim237
  => Delphi Eğitim238
  => Delphi Eğitim239
  => Delphi Eğitim240
  => Delphi Eğitim241
  => Delphi Eğitim242
  İletişim

windows apileri_ingilizce

//bende yeni yeni delphi ogrenmeye basladim ve buldugum dokumanlari sizlerle

//paylasmak istedim.maalesef tamamen c/p ama onemli olan dokumanlarin artmasi

 

Windows API calls are just calls to dynamic link libraries

 

Back in the early days of Windows, PCs had much less memory available than today.

The first version of Windows required only 256k of memory and two floppy drives...

amazingly little by today's standards. The designers of windows had to fit a lot

of code and resources into that 256k of memory, and still leave room for multiple

programs to run.

 

This feat was achieved by allowing multiple programs to share commonly used code

and resources. The vehicle used to provide this magic is the dynamic link library.

 

 

Functions and resources contained in dynamic link libraries can be shared by

multiple applications.  The code and resources contained in a dynamic link

library are generally not loaded until needed, and can be freed when not in

use.

 

 

Most of the Windows system is comprised of dynamic link libraries. Usually dynamic

link libraries have the extension of  ".DLL" , but this is not a requirement.

An example would be in the heart of Windows itself : GDI.EXE, GDI32.DLL, USER.EXE,

USER32.DLL, KERNEL.EXE, KERNEL32.DLL, printer drivers (.drv), system drivers(.drv),

and some fonts(.fon).

 

An example of a resource only dynamic link library is contained in the  MORICONS.DLL

file that ships with Windows. It contains a variety of extra icons for Windows users

to brighten their desktops with.

 

 

Some of the other advantages of placing code and resources in a dynamic link library

are:

 

 

 Disk space is saved if multiple applications use a dynamic link library. This can

 sometimes make a drastic difference in the cost of deploying your applications

 since you can place common functions and resources in a single .DLL file, reducing

 the size of your executables.

 

 The ability to upgrade and replace parts of the program without shipping a whole

 new executable.

 

 The ability to load and execute different resources and code based on some specific

 criteria available only at runtime. A good example would be " PlugIn "

 applets that can be dynamically loaded by your application at runtime, without

 knowing what " PlugIns " might be available at compile time.

 

 This can make your program automatically extendible with after-market products.

 

 

Loading a dynamic link library

 

Your compiler most likely includes interface files to most of the Windows system

functions.  You simply link to the interface files, and any dynamic link libraries

that are used by your program are automatically loaded when your program is started.

In 16 Bit Windows, the actual function code is not added to your program, but

rather a pointer to the module name of the dynamic link library and the name of

the function (or its exported index number) is added.

 

In Win32, the DLL is mapped into the process' address space.  The dynamic link

library's file must exist at runtime or an error will occur.

 

 

If your compiler does not include an interface to the function or dynamic link

library you want to use, you are going to have to declare a function prototype,

and a linking interface, to let your compiler know about the function you are

dynamically linking to. The instructions to do this should be included with your

compiler's documentation.

 

A short example of a function prototype in  Pascal  for a dynamic link library

would be:

 

 {$IFDEF Win32}

 function MessageBeep(BeepType: Integer):Bool stdcall; external 'USER32';

{$ELSE}

 procedure MessageBeep(BeepType: Integer); far; external 'USER';

{$ENDIF}

 

This prototype tells the compiler to link to a function named " MessageBeep "

located in USER32.DLL (if compiling under 32 bits), or a procedure named " MessageBeep "

located in USER.EXE (if compiling under 16 bits). The compiler is also made aware

that " MessageBeep " takes a integer size parameter, and uses the " stdcall "

passing convention (if compiling under 32 bits).

 

When declaring an interface to a dynamic link library, you must be careful to

specify the way that the function expects to have its parameters and return value

passed, and who will maintain the stack. There are various calling techniques used

including:  PASCAL, CDECL, STDCALL,  and  FASTCALL .

 

In 16 bit Windows, most functions are exported using the  PASCAL  calling convention.

In 32 bit Windows,  STDCALL  is preferred since this should be compatible w/most

other languages.

 

Most API functions are declared with " C " prototypes. If you are wanting

to port an interface to a  Pascal  based language, and you are not familiar with " C ",

your best bet is to get  Alain Tadros's  technical paper --

"Using Borland's Delphi and C++ Together" .

 

It is available from Borland's World Wide Web site, Compuserve, and the Borland

BBS system and has some excellent additions by  Eric Uber .

 

 

Dynamic loading at runtime

 

Loading a dynamic link library at runtime allows you to load dynamic link libraries

that are not known at compile time,   or load a library for only a short time.

Printer drivers are a good example: You don't know what printer drivers will be

available on a users system until runtime, and you would only want to load a printer

driver during the printing phase of your program.

 

One of the advantages to loading libraries dynamically is that you don't use up

resources (memory) until you actually load the library and the function you wish

to call.

 

You load a dynamic link library at runtime by calling the Windows API function

LoadLibrary() .  Then you can search for a given function within the library

using the Windows API function  GetProcAddress() . Once you have the address of

the function you want, you can call it from your code.

 

One thing to remember: Always call the Windows API function  FreeLibrary()  when

you are done using the dynamic link library.

 

 Example:

 

 procedure Win31LoadUserAndCallBeepFn;

var

 DllHandle: THandle;

 BeepFn: procedure(BeepType: Integer);

begin

 DllHandle := LoadLibrary('USER');

 if DllHandle >= 32 then begin

   @BeepFn := GetProcAddress(DllHandle, 'MessageBeep');

   if @BeepFn <> nil then

     BeepFn(-1);

   FreeLibrary(DllHandle);

 end;

end;

 

 

procedure Win32LoadUserAndCallBeepFn;

var

 DllHandle: THandle;

 BeepFn: function(BeepType: Integer): Bool stdcall;

begin

 DllHandle := LoadLibrary('USER32');

 if DllHandle <> 0 then begin

   @BeepFn := GetProcAddress(DllHandle, 'MessageBeep');

   if @BeepFn <> nil then

     BeepFn($FFFFFFFF);

   FreeLibrary(DllHandle);

 end;

end;

 

 

Here we have two code snippets showing the differences between loading a library

under 16 and 32 bit Windows. In this case, we must mark the function we are calling

as using the " stdcall " calling convention under 32 bit Windows, where

under 16 bit windows the " pascal " calling convention is assumed. Note

that the 16 bit version of  MessageBeep()  is a procedure, and the 32 bit version

is a function.

 

The  LoadLibrary()  function takes a null-terminated string that names the library

file to be loaded. If the string does not contain a path, Windows searches for the

library in this order: the current directory; the Windows directory; the Windows

system directory; the directory containing the executable file for the current

task; the directories listed in the PATH environment variable; and finally, the

list of directories mapped in a network. If no extension is used, the extension

of " .DLL " is assumed. We check the value of the handle returned by

LoadLibrary()  for an error.

 

Under 16 bit Windows, the return value will be less than 32 if an error occurs,

and under 32 bit Windows, the return value will be 0 if an error occurs. We then

call the  GetProcAddress()  function to get the address of the  MessageBeep()

function.  The spelling of the function name is critical, and can be case sensitive

under different environments. If GetProcAddress()  successfully returns the address

of the function, then we can safely call the function. Finally we unload the

library to free up memory.

 

 

Resource only dynamic link libraries

 

As mentioned, dynamic link libraries can hold resources as well. To use resources

contained in a dynamic link library, you simply make a call to  LoadLibrary() ,

then you can load resources from the library using one of the Windows API resource

functions such as  LoadBitmap() , passing the handle to the dynamic link library

that you received from the  LoadLibrary()  call. Just don't forget to free your

resources and the library when you are done.

 

You can use the snipit from the above section " Loading dynamic link libraries

at runtime " to load a dynamic link library, and then load a resource from the

library.

 

 Example:

 

 LoadBitmap(DllHandle,'SOMEBMP');

 

 

Stack usage and dynamic link libraries

 

When you call a function in a dynamic link library, the library generally uses the

stack of the calling application. Applications running under 16 Bit Windows had much

less stack space available (<64k) than what is available under 32 bit Windows

(1 MB). Since functions in a dynamic link library can call functions in other

dynamic link libraries as well as making callbacks, you should always thoroughly

test your program to make sure you have setup adequate stack space.

 

 

Callback functions

 

Callback functions are a really wonderful feature of the Windows environment.

Callback functions allow you to send the " instanced " address of a

function in your application to a function contained in a dynamic link library.

The dynamic link library function can then call back to the function in your

application to pass back information.

 

A good example of a Windows API function that utilizes callbacks is the  EnumFonts()

function. The  EnumFonts()  function enumerates fonts available to a given device

context. For each font enumerated, the  EnumFonts()  function will call back to a

function in your application, passing back information about that font. This

process continues as long as their are more fonts to enumerate, or until your

function returns zero, meaning that you wish to stop further enumerations.

 

Most Windows API functions that accept a callback function as a parameter will

also accept an  lpData  parameter. This  lpData  parameter is used for " application

defined data ". You are free to define what this parameter is used for. The

lpData  parameter is usually passed to the dynamic link library as a longint, and

rarely as a far pointer. It is likely you will want to send something besides a

longint. You can always typecast a pointer to a data structure in your application

to a longint when calling dynamically linked functions, and typecast the longint

passed back to your callback function to a pointer so your may access your data

structure.

 

As mentioned, when your callback function is called by the Windows API function,

the  lpData  parameter you originally passed to the Windows API function will be

passed back to your callback function for your use. This avoids having to declare

a global variable in your program. A good example of how this works would be if

you were to create a program containing a dialog box to show all the available

fonts in a drop-down listbox.  When you process the  WM_INITDIALOG  message, you

call the EnumFonts()  function, passing the instanced address of your callback

function that will process the font information.

 

Your callback function will perform the work to add each font's name to the

listbox. The only problem: your callback function does not have a handle to the

listbox. You could create a global variable to hold the listbox handle, but

instead, you should pass the handle of the listbox to your callback function

through the lpData  parameter, and let the dynamically linked function pass the

handle of the listbox back to your callback function.

 

While it is always nice to keep global variables to a minimum, having the ability

to pass user defined data to the callback function becomes critically important

when you create callback functions inside a 16-bit dynamic link library.

 

Generally, under 16-bit Windows, a dynamic link library has only one data segment.

Since multiple applications can use a single dynamic link library, and, since a

16-bit dynamic Link Library has a single data segment, any global variables

defined in the dynamic link library exist in memory only once.

 

If you create a callback function in a dynamic link library, and use a global

variable to store data used during the callback, you run the risk of data

corruption.  Consider the following scenario: You have written several applications

that use your font dialog box. Rather than include your font dialog in each

application, you opt to store the dialog in a dynamic link library.

 

Suppose that you use a global variable in the dynamic link library to store the

listbox handle for your callback function.  Now suppose that more than one

application loads the dialog box at the same time. Each "copy" of your

font dialog box contains a different handle to it's listbox. Clearly, using a

global variable to hold the listbox handle will not work since the listbox handle

will be different for each dialog, and the global variable used to hold this

handle will get trashed. The way around this, is to pass the listbox handle to

the  EnumFonts()  function using the  lpData  parameter. This is not a problem,

when writing 32-bit dynamic link libraries for use under  Windows 95  and

Windows NT , as under both environments, dynamic link libraries have a separate

data area for each application that loads them.

 

None the less, it is still a good practice to always keep global variables to

a minimum.

 

 

The Hook functions

 

A " hook " function is a callback function that can be inserted in the

Windows message system so an application can access the message stream before

other processing of the message takes place. Often times, there will be other

hooks already installed in the messaging system, so there will be times you will

need to call the next hook in the " Hook Chain " to allow the other

hooks in the chain to access the messages as well.

 

When you install a hook function using the Windows API function  SetWindowsHookEx(),

you will receive a 32 bit handle to your installed hook function.  You will use

this handle to both remove the hook when you are done via the Windows API function

UnHookWindowsHookEx() , and when calling the next hook in the " Hook Chain " via

the Windows API function  CallNextHookEx() .  We have chosen to use the Windows " Ex "

hook functions since we want to be able to port to 32 bit Windows.

 

System wide hooks require that your hook filter function reside in a dynamic link

library.  The filter function for an application specific hook may reside either

in the application or a dynamic link library.

 

 

Different types of Windows Hooks:

 

Windows defines the following types of hook functions:

 

  WH_CALLWNDPROC - A window procedure hook called whenever the  SendMessage()

   function is called.

  WH_CBT    - A computer based training hook called before activating, creating,

   destroying, minimizing, maximizing, moving, or sizing a window; before completing

   a system command; before removing a mouse or keyboard event; before setting

   input focus; and before synchronizing the system message queue.

  WH_DEBUG -A debugging hook called before any other filter installed by the

   SetWindowsHookEx()  function is called.

  WH_GETMESSAGE   - A message hook called whenever the  GetMessage()  function

   has retrieved a message from an application queue.

  WH_HARDWARE     - A nonstandard hardware message hook called whenever the

   application calls the  GetMessage()  or  PeekMessage()  function and there is

   a hardware event (other than a mouse or keyboard event) to process.

  WH_JOURNALRECORD      - A journaling record hook called when the system removes

   messages from the system message queue.

  WH_JOURNALPLAYBACK    - A journaling playback hook used to insert mouse and

   keyboard messages into the system message queue.

  WH_KEYBOARD     - A keyboard hook called whenever the application calls the

   GetMessage()  or  PeekMessage()  function and there is a  WM_KEYUP  or

   WM_KEYDOWN  keyboard message to process.

  WH_MOUSE - A mouse message hook called whenever the application calls the

   GetMessage()  or  PeekMessage()  function and there is a mouse message to

   process.

  WH_MSGFILTER    - An application message hook called after a dialog box, message

   box, or menu has retrieved a message, but before the message isprocessed.

  WH_SHELL - A shell application hook called when notification messages from

   the system have been made.

  WH_SYSMSGFILTER       - A system wide message hook called after a dialog box, message

   box, or menu has retrieved a message, but before the message is processed.

 

Note: Debugging Windows hooks can be very difficult. The documentation has much

to be desired, so before you make the jump, always consult the  Microsoft Knowledge

Base  for any additional information regarding the hook you are designing for. If

your hook hangs the system, pressing  CTRL+ESC  or  CTRL+AlT+DEL  should unhook

any system wide hooks that are in effect.

 

 

Data storage in dynamic link libraries

 

Under 16 bit Windows, a dynamic link library is only loaded once no matter how

many applications request the library to be loaded, generally contains a single

data segment, and all global variables in the dynamic link library exist across

all applications that load the dynamic link library.  If any process causes

corruption in the data segment of the dynamic link library, other applications

using the dynamic link library can be affected. Many argue that sharing data

between applications through a 16 bit dynamic link library is considered a very

bad practice.

 

Under  Windows 95 , the code for a dynamic link library is only loaded once no

matter how many applications request the library to be loaded, and the link to a

running application gets its own data storage area.  This provides some additional

crash protection to other applications, since any corrupted global variables in a

dynamic link library caused by one application will not adversely affect other

applications using that dynamic link library.

 

Under  Windows NT , a separate copy of both the dynamic link library's data and

code is linked to the calling application.  If we think about how the DLL is loaded,

we can still realize a memory saving when we talk about physical memory usage.

Each process does indeed gets its own copy of the DLL and the DLL data.  However,

it obtains this through a memory mapping of the DLL. That is, the DLL code is

mapped to each processes address space. In physical memory (as seen by the system)

the DLL is loaded only once.

 

 

Instanced addresses and thunking

 

As already mentioned, 16-bit dynamic link libraries have only one data segment.

When you call a function in a dynamic link library, the data segment must be

switched from your application's data segment to that of the dynamic link library's

data segment, and back again after the function returns. If the dynamically linked

function happens to make a callback to a function in your application, the data

segment must be switched back to your application's data segment during the callback,

and back again to the dynamic link library's data segment when your function returns.

 

When making a call to a dynamically linked function, the fixup code to switch the

data segment is transparent. In the case of a callback, additional magic is needed

by your application. The magic is made possible by using the Windows API function

MakeProcInstance()  to receive an " instance thunk " to your callback

procedure. This " instance thunk " is the glue that holds your callback

function and your data segment together during the callback. The procedure address

passed to the  MakeProcInstance()  function needs to be marked with both the " far "

and " exported " attributes. After the dynamic link library is through

using your callback function, and returns, you should always call the Windows API

FreeProcInstance()  function to free the instance thunk.

 

Using the  MakeProcInstance()  function is not necessary in 32 bit applications,

or any dynamic link library (16 or 32 bit). It is, however, safe to use under these

conditions, so any code you have that uses these functions can be safely ported

to dynamic link libraries and 32 bit versions of Windows.

 

 

The example:

 

We will now present an example of using Windows API functions by creating an

application that serves the useful function of hooking into the Windows messaging

system, and recording any keyboard and mouse input to be used for later playback.

We will call our macro recording application "  Hookit!  ". Our " Hookit! "

application is a great starting place for a full featured Windows macro recorder,

reminiscent of the early days of DOS and my favorite " Sidekick's Sidekick ",

Borland's highly successful TSR program " SuperKey "! It's worth noting

that unlike 16 bit Windows, neither  Windows 95  or  Windows NT  shipped with a

macro recording feature.

 

Since " Hookit! " will use system wide Windows hook functions for

JournalRecord  and  JournalPlayback , we will also create a Windows dynamic link

library along the way! Both the application and the dynamic link library will

perform callbacks.

 

Pascal  was originally designed to be a teaching language, thus the code example

presented was written in  Pascal , and can easily be ported to other languages such

as " C ". Note that the code cannot be ported to  Visual Basic,  since,

as of this writing,  Visual Basic  does not support creating dynamic link libraries

or callback functions.

 

The code presented may also be directly ported between 16 and 32 bit compilers,

and will successfully compile with Borland's  Turbo Pascal for Windows 1.5, Borland

Pascal for Windows 7.0 / 7.01, Delphi 1.0 / 1.02, and Delphi 2.0 .  To make it easy

to port to other languages, no Pascal or  Delphi  specific features are used. The

code also serves as a model for creating a " traditional " Windows program

in  Delphi , and utilizing a dialog box template for the main window of a program.

 

Although " Hookit! " uses features designed to run on Windows 3.1 or above,

the example code can be adapted to run on earlier versions of Windows ( 2.x and 3.0 ).

 

 

The Journal Hooks: JournalRecord and JournalPlayback

 

The Journal hook functions provide a easy way to record keyboard and mouse events

on a system-wide basis, and play the events back at some later date.

 

You can install a  JournalRecord  or  JournalPlayback  hook callback function by

calling the Windows API function  SetWindowsHookEx() , and passing the address of

your hook callback function. An instanced address is not needed, as both the

JournalRecord  and  JournalPlayback  callback functions are system wide hooks,

and must reside in a dynamic link library. Calling  SetWindowHookEx()  will

return a 32 bit handle to your hook callback function for you to identify yourself

to other hook functions already in the " Hook Chain ", and to remove

your hook from the chain when you are done recording.

 

When you call  SetWindowsHookEx()  with the address of your  JournalRecord  callback

function, Windows will return immediately, and the recording begins. Your  JournalRecord

callback function will get called with a code indicating the following conditions:

 

  There is a keyboard

or mouse event to record.

  The system is entering

a modal state.

  The system leaving

a modal state.

  The system wants you

to call the next hook in the hook chain.

 

If there is a keyboard or mouse event, the code will equal " HC_ACTION ",

and you are free to record the event. A pointer to an  EVENTMSG  is passed to you

in the lParam parameter of your  JournalRecord  callback function. The system time

that the event was originally fired is contained in time parameter of the  EVENTMSG

structure.  For playback purposes, you will need to make a copy of the  EVENTMSG

and change the time in the copy to reflect the net time into the recording, since

you will need to synchronize the playback of the message to the system time at

playback. This is done by getting the system time when you start the recording,

and subtracting it from the message time.

 

If the system enters a modal state, the code will equal " HC_SYSMODALON ",

indicating something bad has happened to the system, and you should temporarily

stop recording, and call the next message hook in the " Hook Chain ",

so hooks further down the chain will know what is going on. When the system

returns from a modal state, the code will equal " HC_SYSMODALOFF" ,

and you may resume recording.

 

Finally, if the code is less than zero, the system is asking you to call the next

hook in the chain, and you should do so without further processing. When you are

through recording, you can simply call the Windows API function

UnHookWindowsHookEx()  passing back the 32 bit handle given to you when you

originally called the  SetWindowsHookEx()  function, and Windows will remove your

hook callback function from the " Hook Chain ".

 

When you are ready to playback your recording, you will call  SetWindowsHookEx()

again, passing the address of your  JournalPlayback  callback function.  Windows

will return immediately, and the playback begins. During playback, normal mouse

and keyboard input is automatically disabled by the system.

 

Your JournalPlayback callback function will get called with a code indicating one

the following conditions:

 

  HC_SKIP   - You should retrieve the next message. If there are no more messages

   to play, then you may safely call the Windows API function  UnHookWindowsHookEx() ,

   passing the handle to your hook function to end the playback.

  HC_GETNEXT      - You should play the current message.

  HC_SYSMODALON   - The system is entering a modal state. This indicates something

   bad has happened. You should call the next hook in the hook chain, so other hooks

   will know something is up.

  HC_SYSMODALOFF - The system leaving a modal state, and Windows has unhooked

   your JournalPlayback callback procedure right out from under you. You are done.

   As your last act, you should call the next hook in the hook chain, so other

   hooks will know they are hosed as well.

  Code < 0 - The system wants you to call the next hook in the hook chain

   without further processing.

 

You should go ahead and retrieve the first message before you call the SetWindowsHookEx()

 function, since the system will ask you to play the first message before requesting

 the next message. You will also need to get the system time, since you will need

 to " fix up " the playback time of each of your recorded messages to synchronize

 with the system time at playback.

 

Windows may ask you to play the same message more than once. The first time Windows

asks you to play the current message, your  JournalPlayback  callback function

should return the difference between the current time and the time the message is

scheduled to play.

 

If the difference between the current time and the time the message is scheduled

to play is negative, your  JournalPlayback callback function should return zero.

The  JournalPlayback  callback function must also return zero if the same message

is requested to be played more than once.

 

 

How HOOKIT! works

 

Our application ( HOOKIT.EXE ) will contain four buttons:

 

 Start Recording

 Stop Recording

 Playback

 Done

 

and one callback function:

 

 PlaybackFinished()

 

Our dynamic link library ( HOOKLIB.DLL ) will contain three functions that our

calling application will use:

 

 StartRecording()

 StopRecording()

 Playback()

 

and two hook functions that Windows will use:

 

 JournalRecordProc()

 JournalPlaybackProc()

 

 

HOOKIT! application logic:

 

Allow the program to start only if the version of Windows is equal or greater

than Window's 3.1.

 

We will need to supply a callback function to be called whenever a macro's playback

has finished, since the  Playback()  function will return immediately, and our

application will continue to execute during playback.  We will need to call

MakeProcInstance()  to get the instanced address of our callback function

PlaybackFinished()  to pass to the  Playback()  function. Since we cannot call

FreeProcInstance()  in the middle of the callback, we must declare a global

variable to hold the instanced address of  PlaybackFinished()  on program startup,

and free it on exit from the program.

 

 

Create a main window from a Dialog Box template.

 

Upon creation of our main window, we will enable the " Start Recording " and " Done "

button. We will disable the  "Stop Recording " and " Playback " button,

since we have no recording to stop or playback.

 

When the " Done " button is selected we will free the instanced address

of our callback function  PlaybackFinished()  and exit the program.

 

When the " Start Recording " button is selected, we will disable the "

Start Recording " and " Done " button, since we don't want to allow

more than one recording at a time, and we don't want to allow the user to quit in

the middle of recording.

 

We will enable the " Stop Recording " button and call our  StartRecording()  function.

If the  StartRecoding()  function returns an error, we will announce the error to

the user, and reset the buttons to their default state before the " Start

Recording " button was pressed.

 

When the " End Recoding " button is pressed, We will call the  StopRecording()

function passing it the filename to store the macro in. Then we will enable both the " Done "

and " StartRecording " buttons, since we can now allow the user to quit,

and we want the user to have the option to record or rerecord the session.  We

will enable " Playback " button only if anything has successfully been

recorded.

 

When the " Playback " button is selected, we will disable all of our buttons,

and call the  Playback()  function, passing it the filename of the macro to play, the

instanced address of our callback function  PlaybackFinished() , and a handle to

our main window to be passed back to us as application defined data. When the

macro playback is done, our hook function will callback to our program's

PlaybackFinished()  function, letting us know it has finished, and passing us back

the handle to our main window as application data. We must do this since the

Playback()  function will return immediately, causing our program to continue to

run during the macro's playback.

 

This will allow us to know when it safe to enable our program's buttons again.

If the  Playback()  function returns an error, we will reset the buttons to their

default state before the " Playback " button was pressed.

 

When our callback function  PlaybackFininshed()  is called, we can enable the

" Start Recording ", " Playback " and " Done " buttons.

 

 

HOOKLIB dynamic link library logic:

 

If an error occurs during the call to  StartRecord() , or, we are already recording

or playing, we will return zero without further processing.

 

During the recording process, we will save keyboard and mouse events to an array.

For the sake of simplicity, we will limit the number of recorded events to what

will fit in a 64k memory block.

 

When  StopRecording()  is called, if any events have been recorded, we will write

the recorded events to the disk for later playback. We will then unhook our

JournalRecordProc()  from the hook chain. We will return an error code of -1 if

nothing is currently recording or -2 if there was trouble unhooking from the " Hook Chain ".

Otherwise we will return the number of messages recorded.

 

When the  Playback()  function is called, we will start the playback. If an error

occurs or their is nothing to playback, we will return zero without further

processing.

 

When the playback is finished, we will callback to the application announcing we

are done playing back the macro.

 

Since the  SetWindowsHookEx()  function does not allow us an appdata parameter

for application defined data, we must declare several global variables for our

hook callback functions, and avoid letting more than one application invoke

either the  StartRecord()  and  Playback()  functions at any given time under

Windows 3.1.

 

We will define a global pointer called " PMsgBuff  "that will point to

an array of  EventMsg  structures to record to and playback from.  Upon library

startup, we will initialize this pointer to nil.  Only when we are recording or

playing a macro will this pointer actually point to a memory block, otherwise it

will be nil. This will give us a way to determine whether or not we are in the

process of recording or playing a macro.

 

We will also need to define global variables for:

 

" TheHook "- A 32 bit handle to our hook proc.

" StartTime "- The starting time of the recording or playback.

" MsgCount "- The total number of messages recorded.

" CurrentMsg "- The current message playing.

" ReportDelayTime "- If we should report a delay time.

" SysModalOn "- If the system is currently in a " modal " state.

" cbPlaybackFinishedProc "- The instanced address of the application's

 PlaybackFinished() callback function.

" cbAppData "- The user defined application data parameter passed to our

 Playback()  function.

 

 

Got-Ya's!

 

JournalRecordProc()  is incorrectly documented as receiving a  MSG  structure.

JournalRecordProc()  actually receives the same  EVENTMSG  structure that is

documented by  JournalPlaybackProc() .

 

The  JournalRecordProc()  and  JournalPlaybackProc()  hook procedures do not

provide a user defined lpData parameter, so you must use global variables in

your dynamic link library.

 

Mouse events recorded with  JournalRecord  may not play back correctly if the

display resolution has changed, or a window's position has changed.

 

Keyboard events recorded with  JournalRecord  on a Windows system other than Windows

NT  will not play back correctly under  Windows NT . Under Windows 3.1, the keyboard

repeat count is stored in the ParamH parameter of the  EVENTMSG  structure. Under

Windows NT , this parameter is always 1.  The size of the  EVENTMSG  structure

also changes under Win32.

 

Your  JournalPlaybackProc  may be called many times with the  HC_GETNEXT message.

The system expects you to continue providing the same event to play until you

receive a  HC_SKIP  message.

 

Be sure to return a non-zero delay time only once for each unique event you process

in your JournalPlaybackProc , else  Windows NT  may hang due to timing differences.

If your  JournalPlaybackProc()  gets called with a code of  HC_GETNEXT  more than

once for the same event, return zero from your  JournalPlaybackProc .

 

Interactive debugging of a journal hook cannot be done on a single machine. A

Windows NT  or  Win32  application has an advantage that the system will send a

WM_CANCELJOURNAL  message to all applications when the system pulls the hook out

from under the application when the user presses  CTRL+ESC  or  CTRL+ALT+DEL.

" HOOKIT! " handles this event gracefully.

 

The  SetWindowsHookEx()  function will return immediately. This can be a problem

if your program needs to know when the playback has finished.

 

Since you will most likely use the Windows API function  GetTickCount()  for

calculating messaging times, you always run the risk that the system time will

wrap if windows has not been restarted in the last 49 days.  If you account for

the fact that not all compilers support unsigned 32 bit integers, the system time

will appear to go negative sometime into the 24th day.

 

The " handle " passed back from  SetWindowsHookEx()  is 32 bits wide,

even in 16 bit environments.

 

You may need to set your compiler's link buffer to compile to disk when building

dynamic link libraries. If the file image is only created in memory, it will not

be available to the program that uses it.

 

JournalRecordProc()  does not get along well with the new  Windows 95  " StartKey "

contained on some new keyboards.

 

 

Source code for HOOKLIB.DLL

 

Note: Save the source as  HOOKLIB.PAS  for Pascal or HOOKLIB.DPR for Delphi .

 

{$C FIXED PRELOAD PERMANENT}

 

library HOOKLIB;

 

{$IFDEF Win32}

 

uses

  Windows;

 

type

  TwMsg = Longint;

  TwParam = Longint;

  TlParam = Longint;

 

{$ELSE}

 

uses

 {$IFDEF VER15}

  WinTypes, WinProcs, Win31;

 {$ELSE}

 {$IFDEF VER70}

  WinTypes, WinProcs, Win31;

 {$ELSE}

  WinTypes, WinProcs;

 {$ENDIF}

 {$ENDIF}

 

type

  TwMsg = Word;

  TwParam = Word;

  TlParam = Longint;

 

{$ENDIF}

 

const

  MAXMSG = 6500;

 

type

  PEventMsg = ^TEventMsg;

  TMsgBuff = Array[0..MAXMSG]

of TEventMsg;

  TcbPlaybackFinishedProc

= Procedure(AppData: Longint)

 

 {$IFDEF Win32} stdcall; {$ELSE} ; {$ENDIF}

 

var

  PMsgBuff: ^TMsgBuff;

  TheHook: HHook;

  StartTime: Longint;

  MsgCount: Longint;

  CurrentMsg: Longint;

  ReportDelayTime: Bool;

  SysModalOn: Bool;

  cbPlaybackFinishedProc:

TcbPlaybackFinishedProc;

  cbAppData: Longint;

 

 

{ ************************* }

{ function JournalRecordProc(Code: Integer; }

{  wParam: TwParam;                         }

{  lParam: TlParam): Longint;               }

{ Parameters: action to perform and message data. }

{ Returns: zero unless code < 0, in which case return the result }

{          from CallNextHookEx(). }

{ ************************* }

function JournalRecordProc(Code:

Integer;

 

 wParam: TwParam;

 

 lParam: TlParam): Longint

 

{$IFDEF Win32} stdcall; {$ELSE} ; export; {$ENDIF}

begin

  JournalRecordProc := 0;

  case Code of

 

    HC_ACTION: begin

      if SysModalOn then exit;

      if MsgCount > MAXMSG

then exit;

     {record the message}

      PMsgBuff^[MsgCount]

:= PEventMsg(lParam)^;

     {set the delta time of

the message}

      Dec(PMsgBuff^[MsgCount].Time,StartTime);

      Inc(MsgCount);

      exit;

    end;

 

    HC_SYSMODALON: begin

      SysModalOn := True;

      CallNextHookEx(TheHook,

Code, wParam, lParam);

      exit;

    end;

 

    HC_SYSMODALOFF: begin

      SysModalOn := False;

      CallNextHookEx(TheHook,

Code, wParam, lParam);

      exit;

    end;

 

  end;

  if code < 0 then

    JournalRecordProc := CallNextHookEx(TheHook,

              Code,

              wParam,

              lParam);

end;

 

 

{ ************************* }

{ function StartRecording: Integer;}

{ Parameters: none. }

{ Returns: non zero if successful. }

{ ************************* }

function StartRecording: Integer

                      {$IFDEF

Win32} stdcall; {$ELSE} ; export; {$ENDIF}

begin

  StartRecording := 0;

  if pMsgBuff <> nil

then exit;

  GetMem(PMsgBuff, Sizeof(TMsgBuff));

  if PMsgBuff = nil then exit;

  SysModalOn := False;

  MsgCount := 0;

  StartTime := GetTickCount;

  TheHook := SetWindowsHookEx(WH_JOURNALRECORD,

    JournalRecordProc,

    hInstance,

    0);

  if TheHook <> 0 then

begin

    StartRecording := 1;

    exit;

  end else begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

  end;

end;

 

 

{ ************************* }

{ function StopRecording(lpFileName: PChar): Integer; }

{ Parameters: pointer to filename to save to. }

{ Returns: number of records written. }

{          -1 if not recording. }

{          -2 unable to unhook. }

{ ************************* }

function StopRecording(lpFileName:

PChar): Longint

                      {$IFDEF

Win32} stdcall; {$ELSE} ; export; {$ENDIF}

 

var TheFile: File;

begin

  if PMsgBuff = nil then begin

    StopRecording := -1;

    exit;

  end;

  if UnHookWindowsHookEx(TheHook)

= False then begin

    StopRecording := -2;

    exit;

  end;

  TheHook := 0;

  if MsgCount > 0 then

begin

    Assign(TheFile, lpFileName);

   {$I-}

    Rewrite(TheFile, Sizeof(TEventMsg));

   {$I+}

    if IOResult <> 0

then begin

      FreeMem(PMsgBuff, Sizeof(TMsgBuff));

      PMsgBuff := nil;

      StopRecording := 0;

      exit;

    end;

   {$I-}

    Blockwrite(TheFile, PMsgBuff^,

MsgCount);

   {$I+}

    if IOResult <> 0

then begin

      FreeMem(PMsgBuff, Sizeof(TMsgBuff));

      PMsgBuff := nil;

      StopRecording := 0;

     {$I-}

      Close(TheFile);

     {$I+}

      if IOResult <>

0 then exit;

      exit;

    end;

   {$I-}

    Close(TheFile);

   {$I+}

    if IOResult <> 0

then begin

      FreeMem(PMsgBuff, Sizeof(TMsgBuff));

      PMsgBuff := nil;

      StopRecording := 0;

      exit;

    end;

  end;

  FreeMem(PMsgBuff, Sizeof(TMsgBuff));

  PMsgBuff := nil;

  StopRecording := MsgCount;

end;

 

 

{ ************************* }

{ function JournalPlaybackProc(Code: Integer; }

{  wParam: TwParam; }

{  lParam: TlParam): Longint; }

{ Parameters: action to perform and message data. }

{ Returns:  if Code < 0, returns the result from CallNextHookEx(), }

{            otherwise returns the requested time to wait to fire }

{            the next event or zero. }

{ ************************* }

function JournalPlaybackProc(Code:

Integer;

   wParam: TwParam;

   lParam: TlParam): Longint

  {$IFDEF Win32} stdcall; {$ELSE} ; export; {$ENDIF}

var

  TimeToFire: Longint;

begin

  JournalPlaybackProc := 0;

  case Code of

    HC_SKIP: begin

     {get the next message}

      Inc(CurrentMsg);

      ReportDelayTime := True;

     {are we finished?}

      if CurrentMsg >=

(MsgCount-1) then

        if TheHook <>

0 then

          if UnHookWindowsHookEx(TheHook)

= True then begin

            TheHook := 0;

            FreeMem(PMsgBuff,

Sizeof(TMsgBuff));

            PMsgBuff := nil;

           {callback to the

application announcing we are finished}

            cbPlaybackFinishedProc(cbAppData);

          end;

      exit;

    end;

 

    HC_GETNEXT: begin

     {play the current message}

      PEventMsg(lParam)^ :=

PMsgBuff^[CurrentMsg];

      PEventMsg(lParam)^.Time

:= StartTime + PMsgBuff^[CurrentMsg].Time;

     {if first time this message

has played - report the delay time}

      if ReportDelayTime then

begin

        ReportDelayTime :=

False;

        TimeToFire := PEventMsg(lParam)^.Time

- GetTickCount;

        if TimeToFire >

0 then JournalPlaybackProc := TimeToFire;

      end;

      exit;

    end;

 

    HC_SYSMODALON:begin

     {something is wrong}

      SysModalOn := True;

      CallNextHookEx(TheHook,

Code, wParam, lParam);

      exit;

    end;

 

    HC_SYSMODALOFF:begin

     {we have been hosed by

the system - our hook has been pulled!}

      SysModalOn := False;

      TheHook := 0;

      FreeMem(PMsgBuff, Sizeof(TMsgBuff));

      PMsgBuff := nil;

     {callback to the application

announcing we are finished}

      cbPlaybackFinishedProc(cbAppData);

      CallNextHookEx(TheHook,

Code, wParam, lParam);

      exit;

    end;

 

  end;

  If code < 0  then

    JournalPlaybackProc :=

CallNextHookEx(TheHook,

                Code,

                wParam,

                lParam);

end;

 

{ ************************* }

{ function Playback(lpFileName: PChar; }

{                    EndPlayProc: TcbPlaybackFinishedProc; }

{                    AppData: Longint): Integer; }

{ Parameters: pointer to filename to play. }

{             application's EndPlay callback function. }

{             application's defined data. }

{ Returns: non zero if successful. }

{ ************************* }

function Playback(lpFileName:

PChar;

                   EndPlayProc:

TcbPlaybackFinishedProc;

                   AppData:

Longint): Integer

                  {$IFDEF

Win32} stdcall; {$ELSE} ; export; {$ENDIF}

var

  TheFile: File;

begin

  Playback := 0;

  If PMsgBuff <> nil

then exit;

  GetMem(PMsgBuff, Sizeof(TMsgBuff));

  If PMsgBuff = nil then exit;

  Assign(TheFile, lpFileName);

 {$I-}

  Reset(TheFile, Sizeof(TEventMsg));

 {$I+}

  if IOResult <> 0 then

begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

    exit;

  end;

 {$I-}

  MsgCount := FileSize(TheFile);

 {$I+}

  if IOResult <> 0 then

begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

   {$I-}

    Close(TheFile);

   {$I+}

    if IOResult <> 0

then exit;

    exit;

  end;

  if MsgCount = 0 then begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

   {$I-}

    Close(TheFile);

   {$I+}

    if IOResult <> 0

then exit;

    exit;

  end;

 {$I-}

  Blockread(TheFile, PMsgBuff^,

MsgCount);

 {$I+}

  if IOResult <> 0 then

begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

   {$I-}

    Close(TheFile);

   {$I+}

    if IOResult <> 0

then exit;

    exit;

  end;

 {$I-}

  Close(TheFile);

 {$I+}

  if IOResult <> 0 then

begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

    exit;

  end;

  CurrentMsg := 0;

  ReportDelayTime := True;

  SysModalOn := False;

 {save the application's callback

procedure}

  cbPlaybackFinishedProc :=

EndPlayProc;

 {save the application's defined

data parameter}

  cbAppData := AppData;

  StartTime := GetTickCount;

  TheHook := SetWindowsHookEx(WH_JOURNALPLAYBACK,

    JournalPlayBackProc,

    hInstance,

    0);

  if TheHook = 0 then begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

    exit;

  end;

  Playback := 1;

end;

 

exports

  JournalRecordProc index

1 name 'JOURNALRECORDPROC' resident,

  StartRecording index 2 name

'STARTRECORDING' resident,

  StopRecording index 3 name

'STOPRECORDING' resident,

  JournalPlayBackProc index

4 name 'JOURNALPLAYBACKPROC' resident,

  Playback index 5 name 'PLAYBACK'

resident;

 

begin

  PMsgBuff := nil;

end.

 

Resource statements to build:

HOOKIT16.RES and HOOKIT32.RES

 

Note: Save the source as  HOOKIT16.RC  for 16 bit environments

or  HOOKIT32.RC  for 32 bit environments.  Use the  Borland Resource

Command Line Compiler BRCC.EXE  to compile a 16 bit resource file and

BRCC32.EXE  to compile a 32 bit resource file.

 

 HOOKIT DIALOG 15, 15, 63, 60

STYLE WS_OVERLAPPED | WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX

CLASS "HOOKITDIALOGCLASS"

CAPTION "HookIt!"

BEGIN

  CONTROL "Start Recording",

101, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE

| WS_GROUP | WS_TABSTOP, 0, 0, 63, 15

  CONTROL "Stop Recording",

102, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE

| WS_GROUP | WS_TABSTOP, 0, 15, 63, 15

  CONTROL "PlayBack",

103, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE

| WS_GROUP | WS_TABSTOP, 0, 30, 63, 15

  CONTROL "Done!",

1, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE |

WS_GROUP | WS_TABSTOP, 0, 45, 63, 15

END

 

Source code for HOOKIT.EXE

 

Note: Save the source as  HOOKIT.PAS  for  Pascal  or  HOOKIT.DPR  for  Delphi .

 

 program HookIt;

 

{$D HookIt!}

 

{$C MOVEABLE PRELOAD PERMANENT}

 

{$IFDEF Win32}

 

{$R HOOKIT32.RES}

 

uses

  Windows, Messages;

 

type

  TwMsg = Longint;

  TwParam = Longint;

  TlParam = Longint;

 

{$ELSE}

 

{$R HOOKIT16.RES}

 

uses

 {$IFDEF VER15}

  WinTypes, WinProcs, Win31;

 {$ELSE}

 {$IFDEF VER70}

  WinTypes, WinProcs, Win31;

 {$ELSE}

  WinTypes, WinProcs, Messages;

 {$ENDIF}

 {$ENDIF}

 

type

  TwMsg = Word;

  TwParam = Word;

  TlParam = Longint;

 

{$ENDIF}

 

type

  TWinVersion = record

   WinMajor : Byte;

   WinMinor : Byte;

   DosMajor : Byte;

   DosMinor : Byte;

  end;

 

  TcbPlaybackFinishedProc = Procedure(AppData: Longint)

                          {$IFDEF Win32} stdcall; {$ELSE} ; {$ENDIF}

 

const

  APPNAME = 'HookIt!';

  CLASSNAME ='HOOKITDIALOGCLASS';

  ID_BTN_START_RECORDING =

101;

  ID_BTN_STOP_RECORDING =

102;

  ID_BTN_PLAYBACK = 103;

  ID_BTN_DONE = IDOK;

  FILENAME = 'HOOKIT.MAC';

 

var

  PlaybackFinishedProc :TcbPlaybackFinishedProc;

 

function StartRecording: Integer

                       {$IFDEF

Win32} stdcall; {$ELSE} ; far; {$ENDIF}

                        external

'HOOKLIB' index 2;

 

 

function StopRecording(lpFileName:

PChar): Integer

                      {$IFDEF

Win32} stdcall; {$ELSE} ; far; {$ENDIF}

                       external

'HOOKLIB' index 3;

 

 

function Playback(lpFileName:

PChar;

                  EndPlayProc:

TcbPlaybackFinishedProc;

                  AppData:

Longint): Integer

                 {$IFDEF Win32}

stdcall; {$ELSE} ; far; {$ENDIF}

                  external

'HOOKLIB' index 5;

 

 

procedure PlaybackFinished(AppData:

Longint)

 

{$IFDEF Win32} stdcall; {$ELSE} ; export; {$ENDIF}

 

begin

  EnableWindow(GetDlgItem(hWnd(AppData),

ID_BTN_START_RECORDING), True);

  EnableWindow(GetDlgItem(hWnd(AppData),

ID_BTN_STOP_RECORDING), False);

  EnableWindow(GetDlgItem(hWnd(AppData),

ID_BTN_PLAYBACK), True);

  EnableWindow(GetDlgItem(hWnd(AppData),

ID_BTN_DONE), True);

  SetFocus(GetDlgItem(hWnd(AppData),

ID_BTN_PLAYBACK));

end;

 

 

function HookitDialogProc(Dialog:

HWnd;

 

Msg: TwMsg;

 

WParam: TwParam;

 

LParam: TlParam): Longbool

                         {$IFDEF

Win32} stdcall; {$ELSE} ; export; {$ENDIF}

begin

  HookitDialogProc := True;

 {do any default class handling

here for HookItDlg}

  HookitDialogProc := Longbool(DefDlgProc(Dialog,

Msg, WParam, LParam));

end;

 

 

function MainDlgProc(Dialog: HWnd;

                     Msg:TwMsg;

                     WParam:TwParam;

                     LParam:TlParam): Bool

                    {$IFDEF Win32} stdcall; {$ELSE} ; export; {$ENDIF}

begin

  MainDlgProc := True;

  case Msg Of

 

    WM_INITDIALOG: begin

      EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), True);

      EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), False);

      EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), False);

      EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), True);

      exit;

    end;

 

    WM_COMMAND: begin

 

      case WParam of

 

        ID_BTN_START_RECORDING:

begin

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), True);

            SetFocus(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING));

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), False);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), False);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), False);

            if StartRecording

= 0 then begin

              EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), True);

              SetFocus(GetDlgItem(Dialog,

ID_BTN_START_RECORDING));

              EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), False);

              EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), False);

              EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), True);

              Messagebox(Dialog,

                         'Unable

to start recording!',

                         APPNAME,

                         MB_OK);

            end;

          exit;

        end;

 

        ID_BTN_STOP_RECORDING:

begin

          if StopRecording(FILENAME)

> 0 then begin

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), True);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), True);

            SetFocus(GetDlgItem(Dialog,

ID_BTN_PLAYBACK));

          end else begin

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), True);

            SetFocus(GetDlgItem(Dialog,

ID_BTN_START_RECORDING));

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), False);

          end;

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), False);

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), True);

          exit;

        end;

 

        ID_BTN_PLAYBACK: begin

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), False);

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), False);

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), False);

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), False);

          if PlayBack(FILENAME,

PlaybackFinishedProc, Dialog) = 0 then begin

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), True);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), False);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), True);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), True);

            SetFocus(GetDlgItem(hWnd(Dialog),

ID_BTN_PLAYBACK));

          end;

          exit;

        end;

 

        ID_BTN_DONE: begin

          EndDialog(Dialog,

ID_BTN_DONE);

          exit;

        end;

 

      end; {wParam}

 

    end; {WM_COMMAND}

 

    WM_CLOSE: begin

      FreeProcInstance(@PlaybackFinishedProc);

      EndDialog(Dialog, IDOK);

      exit;

    end;

 

  end;

  MainDlgProc := False;

end;

 

 

procedure Init;

var

  WindowClass: TWndClass;

  WinVer: TWinVersion;

begin

  Longint(WinVer) := GetVersion;

  if ((WinVer.WinMajor <

3) OR

      ((WinVer.WinMajor =

3) AND

       (WinVer.WinMinor <

10)) ) then begin

    Messagebox(0,

               'Microsoft

Windows 3.10 or greater required!',

               APPNAME,

               MB_OK);

    halt;

  end;

  @PlaybackFinishedProc :=

MakeProcInstance(@PlaybackFinished, hInstance);

  If @PlaybackFinishedProc

= nil then begin

    Messagebox(0,

               'Cannot create

instance thunk!',

               APPNAME,

               MB_OK);

    halt;

  end;

 

  if FindWindow(CLASSNAME,

APPNAME) <> 0 then begin

    Messagebox(0,

               'Multiple Sessions

not allowed',

               APPNAME,

               MB_OK);

    halt;

  end else begin

    WindowClass.Style

    := CS_BYTEALIGNWINDOW;

    WindowClass.lpfnWndProc

  := @HookItDialogProc;

    WindowClass.cbClsExtra

   := 0;

    WindowClass.cbWndExtra

   := DLGWINDOWEXTRA;

    WindowClass.hInstance

    := hInstance;

    WindowClass.hIcon

    := LoadIcon(0, IDI_APPLICATION);

    WindowClass.hCursor

    := LoadCursor(0, IDC_ARROW);

    WindowClass.hbrBackground

:= GetStockObject(WHITE_BRUSH);

    WindowClass.lpszMenuName

 := nil;

    WindowClass.lpszClassName

:= CLASSNAME;

    if not Bool(RegisterClass(WindowClass))

then begin

      Messagebox(0,

                 'RegisterClass

Failed!',

                 APPNAME,

                 MB_OK);

      halt;

    end;

  end;

end;

 

procedure MyWinMain;

var

  WindowProc:TFarProc;

begin

  WindowProc:=MakeProcInstance(@MainDlgProc,

hInstance);

  DialogBox(hInstance, 'HOOKIT',

0, WindowProc);

  FreeProcInstance(WindowProc);

end;

 

 

{WinMain}

begin

  Init;

  MyWinMain;

end.

 

 

Conclusion:

 

While writing Windows applications gets easier as development tools get more

sophisticated, there will be times when you must "bite the bullet" and a interface

to new functions that are not handled by your current tools.

 

Remember... before you explore unchartered paths, check available resources for

documentation that may help to make your journey a pleasant and rewarding

experience.

 

 

 

//bunu http://www.delphi.about.com dan kopyaladim cok uzun o yuden ceviremiyecegim ama

//ingilizce bilenler icin yararli bir kaynak

 

Delphi - .....................................

 

delphi cok basit bi soru

acil ihtiyacım war delphi de yeniyim atıyorum x.exe çalısıyorsa formda x exe calısıyor diye bir uyarı nasıl werebiliris

 

Delphi - .....................................

 

Bu web sitesi ücretsiz olarak Bedava-Sitem.com ile oluşturulmuştur. Siz de kendi web sitenizi kurmak ister misiniz?
Ücretsiz kaydol