Window设计程序笔记

    xiaoxiao2025-05-29  8

    Window程序的入口函数。

    入口函数和启动函数: WinMain --WinMainCRTStartup wWinMain -- wWinMainCRTStartup Main -- mainCRTStartup Wmain --  wmainCRTStartup

    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

    PSTR szCmdLine, int iCmdShow)

    UNICODE字符

    在严格的ASCII中,每个字符用7位表示,或者计算机上普遍使用的每字符有8位宽;而Unicode使用全16位字符集。这使得Unicode能够表示世界上所有的书写语言中可能用于计算机通讯的字符、象形文字和其它符号。这使得一个char长度变成双字节(宽字节)

    如果使用的是宽字符那么相关的函数也使用宽函数如wcslen。

    Windows的字符串函数 正如前面谈到的,Microsoft C包括宽字符和需要字符串参数的C语言执行时期链接库函数的所有普通版本。不过,Windows复制了其中一部分。例如,下面是Windows定义的一组字符串函数,这些函数用来计算字符串长度、复制字符串、连接字符串和比较字符串: ILength = lstrlen (pString) ; pString = lstrcpy (pString1, pString2) ; pString = lstrcpyn (pString1, pString2, iCount) ; pString = lstrcat (pString1, pString2) ; iComp = lstrcmp (pString1, pString2) ; iComp = lstrcmpi (pString1, pString2) ; 这些函数与C链接库中对应的函数功能相同。如果定义了UNICODE标识符,那么这些函数将接受宽字符串,否则只接受常规字符串。宽字符串版的lstrlenW函数可在Windows 98中执行

    窗口与消息

    Windows程序开始执行后,Windows为该程序建立一个「消息队列」。这个消息队列用来存放该程序可能建立的各种不同窗口的消息。程序中有一小段程序代码,叫做「消息循环」,用来从队列中取出消息,并且将它们发送给相应的窗口消息处理程序。有些消息直接发送给窗口消息处理程序,不用放入消息队列中

    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("HelloWin") ; HWND hwnd ; MSG msg ; WNDCLASwndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ;//窗口风格样式 wndclass.lpfnWndProc = WndProc ;//这条叙述将这个窗口类别的窗口消息处理程序设定为WndProc,即HELLOWIN.C中的第二个函数。这个过程将处理依据这个窗口类别建立的所有窗口的全部消息,即指向回调函数 wndclass.cbClsExtra = 0 ;用于在窗口类别结构和Windows内部保存的窗口结构中预留一些额外空间0表示不需要使用 wndclass.cbWndExtra = 0 ;用于在窗口类别结构和Windows内部保存的窗口结构中预留一些额外空间0表示不需要使用 wndclass.hInstance = hInstance ;//字段就是程序的执行实体句柄(它也是WinMain的参数之一) wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;//为所有依据这个窗口类别建立的窗口设置一个图标。图标是一个小的位图图像,它对使用者代表程序,将出现在Windows工作列中和窗口的标题列的左端.现在,为了方便起见,我们将使用预先定义的图示。 要取得预先定义图示的句柄,可以将第一个参数设定为NULL来呼叫LoadIcon。在加载程序写作者自订的图标时(图标应该存放在磁盘上的.EXE程序文件中),这个参数应该被设定为程序的执行实体句柄hInstance.第二个参数代表图示 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;//函数加载一个预先定义的鼠标光标 wndclass.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH) ;//这意味着窗口显示区域的背景完全为白色,这是一种极其普遍的做法 wndclass.lpszMenuNam = NULL ;//下一个字段指定窗口类别菜单。HElLOWIN没有应用程序菜单,所以该字段被设定为NULL wndclass.lpszClassName= szAppName ;//最后,必须给出一个类别名称。对于小程序,类别名称可以与程序名相同,即存放在szAppName变量中的「HelloWin」字符串。 if (!RegisterClass (&wndclass)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), 整理编撰:Defoe.Tu tyysoft@yahoo.com.cn szAppName, MB_ICONERROR) ; return 0 ; }

    建立窗口 hwnd = CreateWindow( szAppName, // window class name TEXT ("The Hello Program"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT,// initial x position相当于屏幕左上角 CW_USEDEFAULT,// initial y position CW_USEDEFAULT,// initial x size CW_USEDEFAULT,// initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL) ; // creation parameters

    返回所创建窗口的句柄到hwnd

    在CreateWindow呼叫传回之后,Windows内部已经建立了这个窗口。这就是说,Windows已经配置了一块内存

    ShowWindow (hwnd, iCmdShow) ;第一个参数是刚刚用CreateWindow建立的窗口句柄。第二个参数是作为参数传给WinMain的iCmdShow。 UpdateWindow (hwnd) ;//会重画显示区域

    程序通过执行一块称之为「消息循环」的程序代码从消息队列中取出消息: while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; }

    typedef struct tagMSG { HWND hwnd ; UINT message ; WPARAM wParam ; LPARAM lParam ; DWORD time ; POINT pt ; } MSG, * PMSG ;

    wParam 一个32位的「message parameter(消息参数)」,其含义和数值根据消息的不同而不同。 lParam 一个32位的消息参数,其值与消息有关

    time 消息放入消息队列中的时间。 pt 消息放入消息队列时的鼠标坐标。

    TranslateMessage (&msg) ; 将msg结构传给Windows,进行一些键盘转换。

    DispatchMessage (&msg) 

    又将msg结构回传给Windows。然后,Windows将该消息发送给适当的窗口消息处理程序,让它进行处理。这也就是说,Windows将呼叫窗口消息处理程序。在HELLOWIN中,这个窗口消息处理程序就是WndProe函数。处理完消息之后,WndProc传回到Windows。此时,Windows还停留在DispatchMessage呼叫中。在结束DispatchMessage呼叫的处理之后,Windows回到HELLOWIN,并且接着从下一个GetMessage呼叫开始消息循环。

    窗口消息处理程序总是定义为如下形式: LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

    一般来说,Windows程序写作者使用switch和case结构来确定窗口消息处理程序接收的是什么消息,以及如何适当地处理它。窗口消息处理程序在处理消息时,必须传回0.

    WM_PAINT消息

    当窗口显示区域的一部分显示内容或者全部变为「无效」,以致于必须「更新画面」时,将由这个消息通知程序

    。第一条WM_PAINT消息(通常发生在WinMain中呼叫UpdateWindow时)

    对WM_PAINT的处理几乎总是从一个BeginPaint呼叫开始:

    hdc = BeginPaint (hwnd, &ps) ; 而以一个EndPaint呼叫结束: EndPaint (hwnd, &ps) ;

    GetClientRect (hwnd, &rect) ; 第一个参数是程序窗口的句柄。第二个参数是一个指标,指向一个RECT型态的rectangle结构。该结构有四个LONG字段,分别为left、top、right和bottom。GetClientRect将这四个字段设定为窗口显示区域的尺寸。left和top字段通常设定为0,right和bottom字段设定为显示区域的宽度和高度(像素点数)。

    程序使用InvalidateRect或InvalidateRgn函数刻意产生WM_PAINT消息。

    WM_DESTROY消息 WM_DESTROY消息是另一个重要消息。这一个消息指示,Windows正在根据使用者的指示关闭窗口。该消息是使用者单击Close按钮或者在程序的系统菜单上选择 Close时发生的(在本章的后面,我们将详细讨论WM_DESTROY消息是如何生效的)。 HELLOWIN通过呼叫PostQuitMessage以标准方式响应WM_DESTROY消息: PostQuitMessage (0)

    串口的实现(从一个现场的类)

    声明一个串口类,然后创建BOOL CCommInterface::CreateInterface_CommPort(int nCommPort, int nCommBaudrate,  const void *pfnInterfaceOpenCallback,  const void *pfnInterfaceCloseCallback,  const void *pfnDataProcCallback,  const void *pParamCallback)

    BOOL CCommInterface::AppendCmdToSend(const BYTE byBuf[], int nLen, int nDstPort)发送队列

    void OnCommDataRcvd(BYTE * pBuff, int nLength, void * pParam)//串口数据接受

    多线程

    1.hThread = CreateThread (&security_attributes, dwStackSize, ThreadProc, pParam, dwFlags, &idThread) ; 第一个参数是指向SECURITY_ATTRIBUTES型态的结构的指针。在Windows 98中忽略该参数。在Windows NT中,它被设为NULL。第二个参数是用于新线程的初始堆栈大小,默认值为0。在任何情况下,Windows根据需要动态延长堆栈的大小。 CreateThread的第三个参数是指向线程函数的指标。函数名称没有限制,但是必须以下列形式声明: DWORD WINAPI ThreadProc (PVOID pParam) ; CreateThread的第四个参数为传递给ThreadProc的参数。这样主线程和从属线程就可以共享数据。

    CreateThread的第五个参数通常为0,但当建立的线程不马上执行时为旗标CREATE_SUSPENDED。线程将暂停直到呼叫ResumeThread来恢复线程的执行为止。第六个参数是一个指标,指向接受执行绪ID值的变量。 大多数Windows程序写作者喜欢用在PROCESS.H表头文件中声明的C执行时期链接库函数_beginthread。它的语法如下: 2.hThread = _beginthread (ThreadProc, uiStackSize, pParam) ; 它更简单,对于大多数应用程序很完美,这个线程函数的语法为: void __cdecl ThreadProc (void * pParam) ;

    3.3、AfxBeginThread——MFC中线程创建的MFC函数

    用户界面线程的AfxBeginThread  用户界面线程的AfxBeginThread的原型如下: CWinThread* AFXAPI AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority,  UINT nStackSize,  DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES lpSecurityAttrs) 其中: 参数1是从CWinThread派生的RUNTIME_CLASS类; 参数2指定线程优先级,如果为0,则与创建该线程的线程相同; 参数3指定线程的堆栈大小,如果为0,则与创建该线程的线程相同; 参数4是一个创建标识,如果是CREATE_SUSPENDED,则在悬挂状态创建线程,在线程创建后线程挂起,否则线程在创建后开始线程的执行。 参数5表示线程的安全属性,NT下有用。

     

    工作者线程的AfxBeginThread  工作者线程的AfxBeginThread的原型如下: CWinThread* AFXAPI AfxBeginThread( AFX_THREADPROC pfnThreadProc,  LPVOID pParam, int nPriority,  UINT nStackSize,  DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES lpSecurityAttrs) 其中: 参数1  线程的入口函数,声明一定要如下: UINT MyThreadFunction( LPVOID pParam ); 参数2 传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程. 参数3、4、5分别指定线程的优先级、堆栈大小、创建标识、安全属性,含义同用户界面线程。

    实际中我们经常这样用 AfxBeginThread(ThreadProc,this);//把this传过去,就可以调用类的成员了. 这样线程函数就可以使用和操作类的成员了。千万要注意线程函数是静态类函数成员

    创建了新的线程后,该线程就开始启动执行了。但如果在dwCreationFlags中使用了CREATE_SUSPENDED标志,那么线程并不马上执行,而是先挂起,等到调用ResumeThread后才开始启动线程

    当创建线程时,除了使用CREATE_SUSPENDED外,也可以调用SuspendThread函数来暂停线程的运行:

    DWORD SuspendThread(HANDLEhThread);

    当多个线程共同使用同一个资源的时候可以使用临界区域

    CRITICAL_SECTION cs ; 这个CRITICAL_SECTION数据型态是一个结构,但是其中的字段只能由Windows内部使用。这个临界区域对象必须先被程序中的某个线程初始化,通过呼叫: InitializeCriticalSection (&cs) ;

    当临界区域对象被初始化之后,线程可以通过下面的呼叫进入临界区域: EnterCriticalSection (&cs) ; 在这时,线程被认为「拥有」临界区域对象。两个线程不可以同时拥有同一个临界区域对象,因此,如果一个线程进入了临界区域,那么下一个使用同一临界区域对象呼叫EnterCriticalSection的线程将在函数呼叫中被暂停。只有当第一个线程通过下面的呼叫离开临界区域时,函数才会传回控制权: LeaveCriticalSection (&cs) ;

    这时,在EnterCriticalSection呼叫中被停住的那个线程将拥有临界区域,其函数呼叫也将传回,允许线程继续执行。 当临界区域不再被程序所需要时,可以通过呼叫 DeleteCriticalSection (&cs) ;

    转载请注明原文地址: https://ju.6miu.com/read-1299393.html
    最新回复(0)