因工作需要,需要寫一個DLL,在DLL中創建windows窗口,網上有很多關於DLL創建窗口的文章,不過是基於MFC的, 卻鮮見直接用win32的DLL創建的。研究調試了一下,實現了在win32 DLL中創建窗口,集結成文,分享一下。
實際上,用win32 DLL創建窗口有一個問題:
1.CreateWindow用到的HINSTANCE從哪裏來?
答:使用DllMain中的hModule
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
hModule雖然是HANDLE,不能直接使用,強轉即可。
g_hIntance= (HINSTANCE)hModule;
Handle 是代表系統的內核對象,如文件句柄,線程句柄,進程句柄。
HMODULE 是代表應用程序載入的模塊,win32系統下通常是被載入模塊的線性地址
HINSTANCE 在win32下與HMODULE是相同的東西,在Win32下還存在主要是因爲win16。
這是來自百度百科的解釋【1】。
顯然HINSTANCE和HANDLE是兩個玩意,但這裏卻可以強轉,併成功了。調試過程中,看到的值
hModule 是0x10000000
g_hIntance是0x10000000,成員unused的值是9460301,
顯然,hModule和g_hInstance 是模塊的起始地址。
LoadLiibrary返回的HINSTANCE值也是模塊的起始地址。
難道2者有什麼關聯?不細說了,有空研究。
實際運行中,我是將win32 windows的模板代碼直接拷過來,直接白WinMain作爲一個函數給DLL調用了,但不完善,遇到以下問題:
1. 編譯錯誤。一些宏沒有了,需要將resource.h、資源文件和一些資源如ico拷過來。
2. 窗口顯示不了。跟了一下ShowWindow,發現返回值是0,表示窗口隱藏,原來是由nCmdShow決定的,由於沒有值,就全部給了NULL或0。給nCmdShow改成1之後就OK了。
貼一下代碼:
//dllmain
// ad.cpp : 定義 DLL 應用程序的入口點。
#include "stdafx.h"
#include "ad.h"
#include "winform.h"
#include <process.h>
HINSTANCE g_hIntance;
int flag=0;
void c(void *)
{
flag=1;
MyCreateWindow(g_hIntance,NULL,NULL,1);
return;
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
g_hIntance= (HINSTANCE)hModule;
if(flag==0){
_beginthread(c,NULL,NULL);
flag=1;
}
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// 這是導出變量的一個示例
AD_API int nad=0;
// 這是導出函數的一個示例。
AD_API int fnad(void)
{
return 42;
}
// 這是已導出類的構造函數。
// 有關類定義的信息,請參閱 ad.h
Cad::Cad()
{
return;
}
//winform.h
// ad.cpp : 定義應用程序的入口點。
//
#include "stdafx.h"
#include "resource.h"
#define MAX_LOADSTRING 100
// 全局變量:
HINSTANCE hInst; // 當前實例
TCHAR szTitle[MAX_LOADSTRING]; // 標題欄文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口類名
BEGIN_OBJECT_MAP(ObjectMap)
END_OBJECT_MAP()
// 此代碼模塊中包含的函數的前向聲明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY MyCreateWindow(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
// TODO: 在此放置代碼。
MSG msg;
HACCEL hAccelTable;
// 初始化全局字符串
//LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
//LoadString(hInstance, IDC_AD, szWindowClass, MAX_LOADSTRING);
ATOM r=MyRegisterClass(hInstance);
// 執行應用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_AD);
// 主消息循環:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
//
// 函數: MyRegisterClass()
//
// 目的: 註冊窗口類。
//
// 註釋:
//
// 僅當希望在已添加到 Windows 95 的
// “RegisterClassEx”函數之前此代碼與 Win32 系統兼容時,
// 才需要此函數及其用法。調用此函數
// 十分重要,這樣應用程序就可以獲得關聯的
// “格式正確的”小圖標。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_AD);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCTSTR)IDC_AD;
wcex.lpszClassName = _T("TEST");
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
//
// 函數: InitInstance(HANDLE, int)
//
// 目的: 保存實例句柄並創建主窗口
//
// 註釋:
//
// 在此函數中,我們在全局變量中保存實例句柄並
// 創建和顯示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // 將實例句柄存儲在全局變量中
hWnd = CreateWindow(_T("TEST"), _T("TEST"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
DWORD r=GetLastError();
return FALSE;
}
BOOL r1=ShowWindow(hWnd, nCmdShow);
//DWORD r=GetLastError();
r1=UpdateWindow(hWnd);
//r=GetLastError();
return TRUE;
}
//
// 函數: WndProc(HWND, unsigned, WORD, LONG)
//
// 目的: 處理主窗口的消息。
//
// WM_COMMAND - 處理應用程序菜單
// WM_PAINT - 繪製主窗口
// WM_DESTROY - 發送退出消息並返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
//*********************
//**********************
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜單選擇:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意繪圖代碼...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// “關於”框的消息處理程序。
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
參考文獻:
1.HINSTANCE http://baike.baidu.com/view/2434154.htm