消息機制是WIN32的核心,本質就是一個消息結構的鏈表。
聲明
#define MSG_ERROR -1
#define MSG_SUCCEED 0 #define MSG_TRUE 1
#define MSG_FALSE 0 #define PM_NOREMOVE 0x00
#define PM_REMOVE 0x01 typedef unsigned longWPARAM; typedef unsigned longLPARAM; typedef unsigned intUINT; typedef intMSG_BOOL;//這個返回值很二 不要噴我... typedef struct
{
UINTmessage;//消息類型 UINTidThread;//線程ID WPARAMwParam;
LPARAMlParam;
}MSG;
typedef MSG* LPMSG;
typedef struct NODE
{
MSG data;
struct NODE* next;
}MSG_NODE;
void SetupMessage();//啟動消息隊列 void TerminalMessage();//終止消息隊列
MSG_BOOL PeekMessage( LPMSG lpMsg,
UINT hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax,
UINT wRemoveMsg);
MSG_BOOL PostThreadMessage( UINT idThread,
UINT msg,
WPARAM wParam,
LPARAM lParam);
實現
#include "msg.h" #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <pthread.h> static MSG_NODE * g_message_queue = NULL;
static MSG_NODE* msg_create()
{
MSG_NODE* pHead = calloc(sizeof(MSG_NODE),1);
return pHead;
}
static void msg_destroy(MSG_NODE* pHead)
{
MSG_NODE* pNode = NULL;
if(pHead)
{
pNode = pHead->next;
while(pNode)
{
pHead->next = pNode->next;
printf("Free Node:%p\n",pNode);
free(pNode);
pNode = pHead->next;
}
free(pHead);
printf("Free Head Node:%p\n",pHead);
}
}
//定位到消息列表尾部
static MSG_NODE* msg_tail(MSG_NODE* pHead)
{
MSG_NODE* pTail = NULL;
if(!pHead) return NULL;
pTail = pHead;
while(pTail->next) pTail = pTail->next;
return pTail;
}
//尾部插入一個消息結點
static int msg_push_back(MSG_NODE* pHead, MSG_NODE* pNode)
{
MSG_NODE* pTail = NULL;
if( !pHead || !pNode) return MSG_ERROR;
pTail = msg_tail(pHead);
if(pTail)
{
pTail->next = pNode;
pNode->next = NULL;
return MSG_SUCCEED;
}
return MSG_ERROR;
}
//啟動
void SetupMessage()
{
if(!g_message_queue)
{
g_message_queue = msg_create();
assert(g_message_queue);
}
}
//終止
void TerminalMessage()
{
msg_destroy(g_message_queue);
g_message_queue = NULL;
}
MSG_BOOL PostThreadMessage(UINT idThread,UINT msg, WPARAM wParam, LPARAM lParam)
{
MSG_NODE* pNode = NULL;
if( !g_message_queue && (msg < 0) ) return MSG_FALSE;
pNode = calloc(sizeof(MSG_NODE),1);
if (pNode)
{
pNode->data.message = msg;
pNode->data.idThread = (!idThread)?pthread_self():idThread;//如果ID是0 默認為當前線程 pNode->data.wParam = wParam;
pNode->data.lParam = lParam;
pNode->next = NULL;
return (msg_push_back(g_message_queue,pNode) == MSG_SUCCEED)?MSG_TRUE:MSG_FALSE;
}
return MSG_FALSE;
}
//第二個參數完成為了函數"像" Win32 API 沒有用處,LINUX沒有窗口句柄這一說 MSG_BOOL PeekMessage(LPMSG lpMsg,UINT HWND,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg)
{
MSG_NODE* pNode = NULL;
MSG_NODE* pPreNode = NULL;//保存前一個結點
if( !g_message_queue && lpMsg) return MSG_FALSE;
pPreNode = g_message_queue;
pNode = g_message_queue->next;
/*
*不要噴我 用這麼多goto啊 只是為了 不要寫一堆重復的代碼
*/
while(pNode)
{
if(pNode->data.idThread != (UINT)pthread_self() )
{
goto NEXT;
}
if(wMsgFilterMin|wMsgFilterMax)
{
if( pNode->data.message >= wMsgFilterMin &&
pNode->data.message <= wMsgFilterMax )
{
goto GET_MSG;
}
}
else
{
goto GET_MSG;
}
NEXT:
pPreNode = pNode;
pNode = pNode->next;
continue;
GET_MSG:
memcpy(lpMsg,&pNode->data,sizeof(MSG) );
if(wRemoveMsg == PM_REMOVE)//刪除消息鏈表結點 {
pPreNode->next = pNode->next;//前驅結點關聯後繼結點 防止鏈表截斷 free(pNode);//釋放當前消息鏈表結點 }
return MSG_TRUE;
}
return MSG_TRUE;
}
測試用例
#include <stdio.h>
#include <string.h>
#include "msg.h"
int main(int argc,char** argv)
{
int i=0;
MSG msg;
SetupMessage();
for(i=0;i<10;i++)
{
PostThreadMessage(0,1000+i, 100+i, 200+i);
}
while(1)
{
PeekMessage(&msg,0,0,0,PM_REMOVE);
printf("ID:%u,WPARAM:%lu,LPARAM:%lu\n",msg.message,msg.wParam,msg.lParam);
if(!msg.message)break;
memset(&msg,0,sizeof(MSG));
sleep(2);
}
TerminalMessage();
return 0;
}
測試用例只是做了一些簡單基礎的測試,並不完善。
除了線程相關的系統調用,全部采用標准庫實現。