;--------------------------------------------------------------------------------------
;
DLLSkeleton.asm
;--------------------------------------------------------------------------------------
.386
.model
flat,stdcall
option
casemap:none
include
\masm32\include\windows.inc
include
\masm32\include\user32.inc
include
\masm32\include\kernel32.inc
includelib
\masm32\lib\user32.lib
includelib
\masm32\lib\kernel32.lib
.data
.code
DllEntry
proc hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD
mov eax,TRUE
ret
DllEntry
Endp
;---------------------------------------------------------------------------------------------------
;
This is a dummy function
;
It does nothing. I put it here to show where you can insert functions
into
;
a DLL.
;----------------------------------------------------------------------------------------------------
TestFunction
proc
ret
TestFunction
endp
End DllEntry
;-------------------------------------------------------------------------------------
;
DLLSkeleton.def
;-------------------------------------------------------------------------------------
LIBRARY
DLLSkeleton
EXPORTS
TestFunction
The above program is the DLL skeleton. Every DLL must have an entrypoint function. Windows will call the entrypoint function everytime that:
You can name the entrypoint
function anything you wish so long as you have a matching END <Entrypoint
function name>. This function takes three parameters, only the first two
of which are important.
hInstDLL
is the module handle of the DLL. It's not the same as the instance handle
of the process. You should keep this value if you need to use it later.
You can't obtain it again easily.
reason
can be one of the four values:
LIBRARY
DLLSkeleton
EXPORTS
TestFunction
Normally you must have the
first line.The LIBRARY statement defines
the internal module name of the DLL. You should match it with the filename
of the DLL.
The EXPORTS
statement tells the linker which functions in the DLL are exported, that
is, callable from other programs. In the example, we want other modules
to be able to call TestFunction, so we put its name in the EXPORTS
statement.
Another change is in the
linker switch. You must put /DLL switch
and /DEF:<your def filename> in
your linker switches like this:
link /DLL /SUBSYSTEM:WINDOWS /DEF:DLLSkeleton.def /LIBPATH:c:\masm32\lib DLLSkeleton.obj
The
assembler switches are the same, namely /c /coff /Cp. So after you link
the object file, you will get .dll and .lib. The .lib is the import library
which you can use to link to other programs that use the functions in the
DLL.
Next
I'll show you how to use LoadLibrary to load a DLL.
;---------------------------------------------------------------------------------------------
;
UseDLL.asm
;----------------------------------------------------------------------------------------------
.386
.model
flat,stdcall
option
casemap:none
include
\masm32\include\windows.inc
include
\masm32\include\user32.inc
include
\masm32\include\kernel32.inc
includelib
\masm32\lib\kernel32.lib
includelib
\masm32\lib\user32.lib
.data
LibName
db "DLLSkeleton.dll",0
FunctionName
db "TestHello",0
DllNotFound
db "Cannot load library",0
AppName
db "Load Library",0
FunctionNotFound
db "TestHello function not found",0
.data?
hLib
dd ?
; the handle of the library (DLL)
TestHelloAddr
dd ?
; the address of the TestHello function
.code
start:
invoke LoadLibrary,addr LibName
;---------------------------------------------------------------------------------------------------------
;
Call LoadLibrary with the name of the desired DLL. If the call is successful
;
it will return the handle to the library (DLL). If not, it will return
NULL
;
You can pass the library handle to GetProcAddress or any function that
requires
;
a library handle as a parameter.
;------------------------------------------------------------------------------------------------------------
.if eax==NULL
invoke MessageBox,NULL,addr DllNotFound,addr AppName,MB_OK
.else
mov hLib,eax
invoke GetProcAddress,hLib,addr FunctionName
;-------------------------------------------------------------------------------------------------------------
;
When you get the library handle, you pass it to GetProcAddress with the
address
;
of the name of the function in that DLL you want to call. It returns the
address
;
of the function if successful. Otherwise, it returns NULL
;
Addresses of functions don't change unless you unload and reload the library.
;
So you can put them in global variables for future use.
;-------------------------------------------------------------------------------------------------------------
.if eax==NULL
invoke MessageBox,NULL,addr FunctionNotFound,addr AppName,MB_OK
.else
mov TestHelloAddr,eax
call [TestHelloAddr]
;-------------------------------------------------------------------------------------------------------------
;
Next, you can call the function with a simple call with the variable containing
;
the address of the function as the operand.
;-------------------------------------------------------------------------------------------------------------
.endif
invoke FreeLibrary,hLib
;-------------------------------------------------------------------------------------------------------------
;
When you don't need the library anymore, unload it with FreeLibrary.
;-------------------------------------------------------------------------------------------------------------
.endif
invoke ExitProcess,NULL
end
start
So
you can see that using LoadLibrary is a little more involved but it's also
more flexible.