LoadLibrary proto lpDLLName:DWORDElle ne prend seulement qu'un paramètre : l'adresse du nom du DLL que vous voulez charger en mémoire. Si l'appel est couronné de succès, il renvoie l'handle du DLL, sinon elle renvoie un NULL.
FreeLibrary proto hLib:DWORDIl ne prend aussi qu'un seul paramètre : l'handle du DLL que vous souhaitez décharger. Normalement, vous avez obtenu cet handle grâce à LoadLibrary.
SetTimer proto hWnd:DWORD, TimerID:DWORD, uElapse:DWORD, lpTimerFunc:DWORDVous pouvez créer un Timer de deux façons :hWnd is the hest l'handle de la fenêtre qui recevra le message d'avis du Timer. Ce paramètre peut être NULL pour spécifier qu'il n'y a aucune fenêtre étant associée au Timer.
TimerID est une valeur définie par l'utilisateur, laquelle est employée en tant qu'ID du Timer.
uElapse est la valeur du temps d'attente en millisecondes.
lpTimerFunc est l'adresse de la fonction qui traitera les messages d'avis du Timer. Si vous passez un NULL, les messages du Timer seront envoyés à la fenêtre indiquée par le paramètre hWnd.SetTimer renvoie l'ID du Timer en cas de succès. Autrement il renvoie un NULL. Donc il est préférable de ne pas mettre l'ID du Timer à 0.
KillTimer proto hWnd:DWORD, TimerID:DWORD
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
.data
ClassName db "SplashDemoWinClass",0
AppName db "Splash Screen Example",0
Libname db "splash.dll",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
.code
start:
invoke LoadLibrary,addr Libname
.if eax!=NULL
invoke FreeLibrary,eax
.endif
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.while TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.break .if (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.endw
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
;--------------------------------------------------------------------
;
Et voici le DLL contenant le Bitmap:
;--------------------------------------------------------------------
.386
.model flat, stdcall
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib
.data
BitmapName db "MySplashBMP",0
ClassName db "SplashWndClass",0
hBitMap dd 0
TimerID dd 0
.data
hInstance dd ?
.code
DllEntry proc hInst:DWORD, reason:DWORD, reserved1:DWORD
.if reason==DLL_PROCESS_ATTACH ; Quand le dll est chargé.
push hInst
pop hInstance
call ShowBitMap
.endif
mov eax,TRUE
ret
DllEntry Endp
ShowBitMap proc
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF
WNDCLASSEX
mov wc.style, CS_HREDRAW
or CS_VREDRAW
mov wc.lpfnWndProc,
OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET
ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,0
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr
wc
INVOKE CreateWindowEx,NULL,ADDR
ClassName,NULL,\
WS_POPUP,CW_USEDEFAULT,\
CW_USEDEFAULT,250,250,NULL,NULL,\
hInstance,NULL
mov hwnd,eax
INVOKE ShowWindow, hwnd,SW_SHOWNORMAL
.WHILE TRUE
INVOKE GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
ShowBitMap endp
WndProc proc hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
LOCAL ps:PAINTSTRUCT
LOCAL hdc:HDC
LOCAL hMemoryDC:HDC
LOCAL hOldBmp:DWORD
LOCAL bitmap:BITMAP
LOCAL DlgHeight:DWORD
LOCAL DlgWidth:DWORD
LOCAL DlgRect:RECT
LOCAL DesktopRect:RECT
.if uMsg==WM_DESTROY
.if hBitMap!=0
invoke DeleteObject,hBitMap
.endif
invoke PostQuitMessage,NULL
.elseif uMsg==WM_CREATE
invoke GetWindowRect,hWnd,addr DlgRect
invoke GetDesktopWindow
mov ecx,eax
invoke GetWindowRect,ecx,addr DesktopRect
push 0
mov eax,DlgRect.bottom
sub eax,DlgRect.top
mov DlgHeight,eax
push eax
mov eax,DlgRect.right
sub eax,DlgRect.left
mov DlgWidth,eax
push eax
mov eax,DesktopRect.bottom
sub eax,DlgHeight
shr eax,1
push eax
mov eax,DesktopRect.right
sub eax,DlgWidth
shr eax,1
push eax
push hWnd
call MoveWindow
invoke LoadBitmap,hInstance,addr BitmapName
mov hBitMap,eax
invoke SetTimer,hWnd,1,2000,NULL
mov TimerID,eax
.elseif uMsg==WM_TIMER
invoke SendMessage,hWnd,WM_LBUTTONDOWN,NULL,NULL
invoke KillTimer,hWnd,TimerID
.elseif uMsg==WM_PAINT
invoke BeginPaint,hWnd,addr ps
mov hdc,eax
invoke CreateCompatibleDC,hdc
mov hMemoryDC,eax
invoke SelectObject,eax,hBitMap
mov hOldBmp,eax
invoke GetObject,hBitMap,sizeof BITMAP,addr bitmap
invoke StretchBlt,hdc,0,0,250,250,\
hMemoryDC,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY
invoke SelectObject,hMemoryDC,hOldBmp
invoke DeleteDC,hMemoryDC
invoke EndPaint,hWnd,addr ps
.elseif uMsg==WM_LBUTTONDOWN
invoke DestroyWindow,hWnd
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
WndProc endp
End DllEntry
invoke LoadLibrary,addr LibnameNous appelons LoadLibrary pour charger le DLL nommé "splash.DLL". Et après ça, déchargez-le de la mémoire avec FreeLibrary. LoadLibrary ne retournera rien avant que le DLL n'en ait fini avec son initialisation..
.if eax!=NULL
invoke FreeLibrary,eax
.endif
.if reason==DLL_PROCESS_ATTACH ; Quand le dll est chargé.
push hInst
pop hInstance
call ShowBitMap
Lorsque le DLL est chargé, Windows appelle son entrypoint avec le flag DLL_PROCESS_ATTACH. Nous en profitons pour afficher le Splash screen. En premier lieu, nous stockons l'instance handle du DLL pour pouvoir l'utiliser plus tard. On appelle donc une fonction nommée ShowBitMap pour faire ce travail. ShowBitMap enregistre (une Window Class) une classe de fenêtre, et on crée la fenêtre puis on entre dans la boucle de message comme d'habitude. La partie intéressante est dans l'appel de CreateWindowEx :
INVOKE CreateWindowEx,NULL,ADDR
ClassName,NULL,\
WS_POPUP,CW_USEDEFAULT,\
CW_USEDEFAULT,250,250,NULL,NULL,\
hInstance,NULL
Notez que le style de fenêtre est seulement WS_POPUP ce qui fera qu'on obtiendra une fenêtre sans bords et sans titre. Nous limitons aussi la largeur et la hauteur de la fenêtre à 250x250 pixels.
Maintenant que la fenêtre est créée, avec le message WM_CREATE nous plaçons la fenêtre au centre de l'écran grâce au code suivant.
invoke GetWindowRect,hWnd,addr DlgRect
invoke GetDesktopWindow
mov ecx,eax
invoke GetWindowRect,ecx,addr DesktopRect
push 0
mov eax,DlgRect.bottom
sub eax,DlgRect.top
mov DlgHeight,eax
push eax
mov eax,DlgRect.right
sub eax,DlgRect.left
mov DlgWidth,eax
push eax
mov eax,DesktopRect.bottom
sub eax,DlgHeight
shr eax,1
push eax
mov eax,DesktopRect.right
sub eax,DlgWidth
shr eax,1
push eax
push hWnd
call MoveWindow
Ceci retrouve les dimensions de notre bureau (qui vont servir de référence) puis celles de la fenêtre en calculant les coordonnées appropriées du coin supérieur gauche de la fenêtre pour pouvoir la placer au centre.
invoke LoadBitmap,hInstance,addr BitmapName
mov hBitMap,eax
invoke SetTimer,hWnd,1,2000,NULL
mov TimerID,eax
Ensuite on charge le 'bitmap ressource' avec LoadBitmap et on crée un minuteur (un Timer) avec l'ID du Timer ayant la valeur de '1', et un intervalle de temps de 2 secondes. Le Timer enverra des messages WM_TIMER à la fenêtre toutes les 2 secondes.
.elseif uMsg==WM_PAINT
invoke BeginPaint,hWnd,addr ps
mov hdc,eax
invoke CreateCompatibleDC,hdc
mov hMemoryDC,eax
invoke SelectObject,eax,hBitMap
mov hOldBmp,eax
invoke GetObject,hBitMap,sizeof BITMAP,addr bitmap
invoke StretchBlt,hdc,0,0,250,250,\
hMemoryDC,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY
invoke SelectObject,hMemoryDC,hOldBmp
invoke DeleteDC,hMemoryDC
invoke EndPaint,hWnd,addr ps
Quand la fenêtre reçoit le message WM_PAINT, elle crée une mémoire DC, choisit le bitmap dans la mémoire DC, obtient la taille du bitmap avec GetObject et met ensuite le bitmap sur la fenêtre en appelant StretchBlt, lequel se comporte comme BitBlt (il recopie le bitpam sur notre fenêtre) mais il en plus est capable de compresser ou de décompresser le bitmap à la dimension désirée. Dans notre cas, nous voulons que le bitmap s'accorde aux dimensions de la fenêtre, c'est pourquoi nous utilisons StretchBlt au lieu de BitBlt. Nous supprimons la mémoire DC après ça.
.elseif uMsg==WM_LBUTTONDOWN
invoke DestroyWindow,hWnd
Ce serait frustrant pour l'utilisateur qu'il soit obligé d'attendre que le Splash screen disparaisse. On aimerait que l'utilisateur ait le choix. Quand il clique sur Splash screen, il faudrait qu'il disparaisse. C'est pourquoi nous avons besoin de traiter le message WM_LBUTTONDOWN dans le DLL. En recevant ce message, la fenêtre est détruite par l'appel de DestroyWindow.
.elseif uMsg==WM_TIMER
invoke SendMessage,hWnd,WM_LBUTTONDOWN,NULL,NULL
invoke KillTimer,hWnd,TimerID
Si l'utilisateur attend, le Splash screen disparaîtra lorsque le temps indiqué se sera écoulé (dans notre exemple, au bout de 2 secondes). On fait ça en traitant le message WM_TIMER. Après avoir reçu ce message, nous fermons la fenêtre en lui envoyant le message WM_LBUTTONDOWN. Ça permet d'éviter la duplication du code. Puisque nous n'avons plus besoin d'utiliser le Timer, nous le détruisons avec KillTimer.
Après que la fenêtre soit fermée, le DLL renverra le contrôle au programme principal.