前言

我对Windows线程API有一种恐怖的感觉,那是因为在以前第一次接触它的时候是通过VB,好吧,就是VB,在他的开发环境中做子类化或者多线程编程时,IDE总会莫名其妙经常崩溃,以至于后面继续是哪怕改了一个字符,运行时都要先保存一下,因为这个IDE可没有自动保存功能。

但说回来,并不是API恐怖,而是IDE恐怖。

CreateThread

见名知意,这是创建线程的函数,如果函数成功,则返回新线程的句柄。

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES   lpThreadAttributes,
  SIZE_T                  dwStackSize,
  LPTHREAD_START_ROUTINE  lpStartAddress,
  __drv_aliasesMem LPVOID lpParameter,
  DWORD                   dwCreationFlags,
  LPDWORD                 lpThreadId
)
;

参数介绍:

  1. lpThreadAttributes指向SECURITY_ATTRIBUTES 结构,表示线程内核对象的安全属性,一般传入NULL就行,表示使用默认设置。
  2. dwStackSize线程栈空间大小。传入0表示使用默认大小。
  3. lpStartAddress线程执行的函数地址,就是线程跑的代码段在哪个函数中。
  4. lpParameter线程函数的参数
  5. dwCreationFlags这个参数为0表示线程创建后马上就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行,直到调用ResumeThread()。
  6. lpThreadId用于获取返回的线程的ID,传入NULL表示不需要返回该线程ID号。

还有两个创建线程的函数是_beginthread()或_beginthreadex(),自行了解一下。

代码示例

我们知道在做一个耗时较长的任务时,需要开启新线程,否则会阻塞后面代码执行,引起界面未响应。

下面简单做一个示例,开启一个线程,这个线程每隔1秒打印一次,一共打印5次。

.386
.model flat,stdcall
option casemap:none
include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
includelib c:\masm32\lib\user32.lib
include c:\masm32\include\kernel32.inc
includelib c:\masm32\lib\kernel32.lib

include  c:\masm32\include\msvcrt.inc
includelib c:\masm32\lib\msvcrt.lib

WinMain proto :DWORD

.DATA
ClassName db "MyWindowClass",0
AppName db "Win32线程",0
ButtonClassName db "Button",0
ButtonTitle db "开启线程",0
HelloGUI db "HelloGUI",0

Message db "完成",0
MessageTitle db "提示",0

OutMessage db "第%d次"
.DATA?
hInstance HINSTANCE ?
hWindowHdc HDC ?
hButton HWND ?
hWindow HWND ?

ThreadID DWORD ?
.CONST
ButtonID equ 1
.CODE


start:

invoke GetModuleHandle, NULL
mov hInstance,eax
invoke WinMain, hInstance
invoke ExitProcess, eax
WinMain proc hInst:HINSTANCE
   LOCAL wc:WNDCLASSEX
   LOCAL msg:MSG

   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,\
               0,\
               0,\
               300,\
               300,\
               NULL,\
               NULL,\
               hInst,\
               NULL
   mov   hWindow,eax

   invoke CreateWindowEx,NULL,ADDR ButtonClassName,ADDR ButtonTitle, WS_TABSTOP OR  WS_VISIBLE OR WS_CHILD OR BS_DEFPUSHBUTTON  ,\
   0,0,100,100,hWindow,ButtonID,NULL,NULL
   mov hButton,eax

   invoke GetDC,eax
   mov  hWindowHdc,eax
   invoke ShowWindow, hWindow,SW_SHOWDEFAULT
   invoke UpdateWindow, hWindow

   .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

PrintThread proc num:dword
invoke crt_printf, addr OutMessage,num
.while num>0
sub num,1
invoke Sleep,1000
invoke crt_printf, addr OutMessage,num
 
.endw
invoke MessageBox,NULL,addr Message,addr MessageTitle,MB_OK
ret

PrintThread endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL strRect:RECT
.IF uMsg == WM_LBUTTONDOWN
mov strRect.right,100
mov strRect.bottom,100
mov strRect.left,0
mov strRect.top,0
invoke DrawText,hWindowHdc, ADDR HelloGUI,8,ADDR  strRect,DT_VCENTER
.ELSEIF uMsg ==WM_COMMAND
mov eax,wParam
.IF ax == ButtonID
 mov  eax,OFFSET PrintThread
           
                invoke CreateThread,NULL,NULL,eax,5,0,ADDR ThreadID
                invoke CloseHandle,eax

.ENDIF

.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
   ret
WndProc endp

end start

如果在主线程开启循环打印的话,窗口就会无法拖动,但如果在新线程执行的话,窗口就可以拖动了。

Win32汇编系列八,多线程_java