LoadLibrary proto lpDLLName:DWORDIt takes only one parameter: the address of the name of the DLL you want to load into memory. If the call is successful, it returns the module handle of the DLL else it returns NULL.
FreeLibrary proto hLib:DWORDIt takes one parameter: the module handle of the DLL you want to unload. Normally, you got that handle from LoadLibrary
SetTimer proto hWnd:DWORD, TimerID:DWORD, uElapse:DWORD, lpTimerFunc:DWORDYou can create a timer in two ways:hWnd is the handle of a window that will receive the timer notification message. This parameter can be NULL to specify that there is no window that's associated with the timer.
TimerID is a user-defined value that is used as the ID of the timer.
uElapse is the time-out value in milliseconds.
lpTimerFunc is the address of a function that will process the timer notification messages. If you pass NULL, the timer messages will be sent to the window specified by hWnd parameter.SetTimer returns the ID of the timer if successful. Otherwise it returns NULL. So it's best not to use the timer ID of 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
;--------------------------------------------------------------------
;                        
The Bitmap DLL
;--------------------------------------------------------------------
.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  ; When the dll is loaded 
  
        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 LibnameWe call LoadLibrary to load the DLL named "splash.dll". And after that, unload it from memory with FreeLibrary. LoadLibrary will not return until the DLL is finished with its initialization.
.if eax!=NULL
invoke FreeLibrary,eax
.endif
   .if reason==DLL_PROCESS_ATTACH  ; When the dll
is loaded
      push hInst
      pop hInstance
      call ShowBitMap
When the DLL is loaded, Windows calls its entrypoint function with DLL_PROCESS_ATTACH flag. We take this opportunity to display the splash screen. First we store the instance handle of the DLL for future use. Then call a function named ShowBitMap to do the real job. ShowBitMap registers a window class, creates a window and enters the message loop as usual. The interesting part is in the CreateWindowEx call:
        INVOKE CreateWindowEx,NULL,ADDR
ClassName,NULL,\
           WS_POPUP,CW_USEDEFAULT,\
           CW_USEDEFAULT,250,250,NULL,NULL,\
           hInstance,NULL
Note
that the window style is only WS_POPUP which will make the window borderless
and without caption. We also limit the width and height of the window to
250x250 pixels.
Now
when the window is created, in WM_CREATE message handler we move the window
to the center of the screen with the following code.
               
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
It retrieves the dimensions of the desktop and the window then calculates the appropriate coordinate of the left upper corner of the window to make it center.
               
invoke LoadBitmap,hInstance,addr BitmapName
               
mov hBitMap,eax
               
invoke SetTimer,hWnd,1,2000,NULL
               
mov TimerID,eax
Next it loads the bitmap from the resource with LoadBitmap and creates a timer with the timer ID of 1 and the time interval 2 seconds. The timer will send WM_TIMER messages to the window every 2 seconds.
        .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
When the window receives WM_PAINT message, it creates a memory DC, select the bitmap into the memory DC, obtain the size of the bitmap with GetObject and then put the bitmap on the window by calling StretchBlt which performs like BitBlt but it can stretch or compress the bitmap to the desired dimension. In this case, we want the bitmap to fit into the window so we use StretchBlt instead of BitBlt. We delete the memory DC after that.
       
.elseif uMsg==WM_LBUTTONDOWN
               
invoke DestroyWindow,hWnd
It would be frustrating to the user if he has to wait until the splash screen to disappear. We can provide the user with a choice. When he clicks on the splash screen, it will disappear. That's why we need to process WM_LBUTTONDOWN message in the DLL. Upon receiving this message, the window is destroyed by DestroyWindow call.
        .elseif uMsg==WM_TIMER
               
invoke SendMessage,hWnd,WM_LBUTTONDOWN,NULL,NULL
               
invoke KillTimer,hWnd,TimerID
If
the user chooses to wait, the splash screen will disappear when the specified
time has elapsed (in our example, it's 2 seconds). We can do this by processing
WM_TIMER message. Upon receiving this message, we closes the window by
sending WM_LBUTTONDOWN message to the window. This is to avoid code duplication.
We don't have further use for the timer so we destroy it with KillTimer.
When
the window is closed, the DLL will return control to the main program.