关于DLL中创建窗口

dungeonsnd 2009-08-18 11:56:48

我现在要把窗口的创建及窗口过程封装到DLL里,主程序调用这个DLL里的函数后创建(多个)相互独立的子窗口。

最初,我在DLL里用全局函数创建窗口。然后,写了一个WIN32的测试程序来调用这个DLL,DLL创建子窗口成功,并且子窗口可以响应消息;但是在MFC的测试程序里调用同样的DLL时,创建子窗口成功,但是子窗口不能响应消息,也就是单击子窗口后,DLL中子窗口过程中的 case WM_LBUTTONDOWN没有执行(消息进不到子窗口的窗口过程中)。

后来,查到了Thunk技术。 想上面那个问题可能是由于MFC下调用DLL时,DLL创建子窗口的窗口过程没有得到正确句柄.(但是还是没搞明白,为什么同样的DLL,在WIN32下测试时,DLL创建的子窗口可以响应消息)。
我试着用Thunk技术,并用类来重写这个DLL。发现越写越复杂,要解决很多问题。比如,DLL及调用它的EXE程序之间共享 EXE中创建的DLL对象的指针。。等等。。 反正用Thunk时,遇到了很多问题。

再后来,发现ATL中用了Thunk技术,并封装了窗口。 但是我没有研究过ATL。 所以不知道它对我的目标有没有帮助。

请问,,我的目标是,让这个DLL 更面向对象,更易于维护,更易于调用者对子窗口的创建及销毁,,我要实现的这个DLL用哪个思路来做更好,? 谢谢!

比如,
1.在DLL中用全局函数(这个当然不是面向对象的,不容易维护,我不打算使用这种方法,而且调用者不能创建多个实例)
2.在DLL中用类来实现,自己封装窗口及窗口过程,运用Thunk技术来解决DLL中的窗口过程的句柄问题。(必须用Thunk或类似技术,因为窗口过程必须为全局的(或静态的) )
3.好好研究ATL(尚不知道ATL创建的DLL对我的要求是否有帮助),并用它来创建我的DLL。然后供MFC程序及WIN32程序来调用。


请帮我想个思路。谢谢!
急切,再次感谢!
...全文
908 28 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
dungeonsnd 2010-01-31
  • 打赏
  • 举报
回复
自己已解决,
dungeonsnd@126.com

结账!
cyofworld 2009-09-02
  • 打赏
  • 举报
回复
c/c++ code, vs2008 + win xp sp2, 使用多字节



// Test.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "Test.h"

#define MAX_LOADSTRING 100

HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名


ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);


//////////////////////////////////////////////////////////////////////////
class ZWindow;
ZWindow* g_pWnd = NULL;

#pragma pack(push,1)
struct _WndProcThunk
{
DWORD m_mov; // mov dword ptr [esp+0x4], pThis (esp+0x4 is hWnd)
DWORD m_this;
BYTE m_jmp; // jmp WndProc
DWORD m_relproc; // relative jmp
};
#pragma pack(pop)

class WndProcThunk
{
public:
_WndProcThunk thunk;

void Init(WNDPROC proc, void* pThis)
{
thunk.m_mov = 0x042444C7; //C7 44 24 04
thunk.m_this = (DWORD)pThis;
thunk.m_jmp = 0xe9;
thunk.m_relproc = (int)proc - ((int)this+sizeof(_WndProcThunk));

::FlushInstructionCache(GetCurrentProcess(), &thunk, sizeof(thunk));
}
};

class ZWindow
{
public:

virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return FALSE;
}

HWND m_hWnd;
WndProcThunk m_thunk;

ZWindow(HWND hWnd = 0) : m_hWnd(hWnd) { }

inline void Attach(HWND hWnd)
{ m_hWnd = hWnd; }

inline BOOL ShowWindow(int nCmdShow)
{ return ::ShowWindow(m_hWnd, nCmdShow); }

inline BOOL UpdateWindow()
{ return ::UpdateWindow(m_hWnd); }

inline HDC BeginPaint(LPPAINTSTRUCT ps)
{ return ::BeginPaint(m_hWnd, ps); }

inline BOOL EndPaint(LPPAINTSTRUCT ps)
{ return ::EndPaint(m_hWnd, ps); }

inline BOOL GetClientRect(LPRECT rect)
{ return ::GetClientRect(m_hWnd, rect); }

BOOL Create(LPCTSTR szClassName, LPCTSTR szTitle, HINSTANCE hInstance, HWND hWndParent = 0,
DWORD dwStyle = WS_OVERLAPPEDWINDOW, DWORD dwExStyle = 0, HMENU hMenu = 0,
int x = CW_USEDEFAULT, int y = CW_USEDEFAULT, int nWidth = CW_USEDEFAULT, int nHeight = CW_USEDEFAULT)
{
m_hWnd = ::CreateWindowEx(dwExStyle, szClassName, szTitle, dwStyle, x, y,
nWidth, nHeight, hWndParent, hMenu, hInstance, NULL);

return m_hWnd != NULL;
}

static LRESULT CALLBACK StartWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
ZWindow* pThis = g_pWnd;
pThis->m_hWnd = hWnd;

// initilize the thunk code
pThis->m_thunk.Init(WindowProc, pThis);

// get the address of thunk code
WNDPROC pProc = (WNDPROC)&(pThis->m_thunk.thunk);

::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)pProc);

return pProc(hWnd, uMsg, wParam, lParam);
}

static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
ZWindow* pThis = (ZWindow*)hWnd;

if (!pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam))
return ::DefWindowProc(pThis->m_hWnd, uMsg, wParam, lParam);
else
return 0;
}
};


class ZDriveWindow1 : public ZWindow
{
public:
virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

LRESULT OnPaint(WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
RECT rect;

hDC = BeginPaint(&ps);
GetClientRect(&rect);
::SetBkMode(hDC, TRANSPARENT);
::DrawText(hDC, "ZDriveWindow1", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
EndPaint(&ps);

return 0;
}

LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam)
{
::MessageBox(NULL, "ZDriveWindow1::OnLButtonDown", "Msg", MB_OK);
return 0;
}
};

class ZDriveWindow2 : public ZWindow
{
public:
virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT OnPaint(WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
RECT rect;

hDC = BeginPaint(&ps);
GetClientRect(&rect);
::SetBkMode(hDC, TRANSPARENT);
::Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);
::DrawText(hDC, "ZDriveWindow2", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
EndPaint(&ps);

return 0;
}

LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam)
{
::MessageBox(NULL, "ZDriveWindow2::OnLButtonDown", "Msg", MB_OK);
return 0;
}

};

class ZDriveWindow3 : public ZWindow
{
public:
virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT OnPaint(WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
RECT rect;

hDC = BeginPaint(&ps);
GetClientRect(&rect);
::SetBkMode(hDC, TRANSPARENT);
::Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);
::DrawText(hDC, "ZDriveWindow3", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
EndPaint(&ps);

return 0;
}

LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam)
{
::MessageBox(NULL, "ZDriveWindow3::OnLButtonDown", "Msg", MB_OK);
return 0;
}

};

BOOL ZDriveWindow1::ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

if (uMsg == WM_NCDESTROY)
::PostQuitMessage(0);

switch (uMsg)
{
case WM_LBUTTONDOWN:
OnLButtonDown(wParam, lParam);
break;

case WM_PAINT:
OnPaint(wParam, lParam);
break;
}

return FALSE;
}

BOOL ZDriveWindow2::ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_LBUTTONDOWN:
OnLButtonDown(wParam, lParam);
break;

case WM_PAINT:
OnPaint(wParam, lParam);
break;
}

return FALSE;
}


BOOL ZDriveWindow3::ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_LBUTTONDOWN:
OnLButtonDown(wParam, lParam);
break;

case WM_PAINT:
OnPaint(wParam, lParam);
break;
}

return FALSE;
}
//////////////////////////////////////////////////////////////////////////



int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: 在此放置代码。
MSG msg;
HACCEL hAccelTable;

// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_TEST, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TEST));

// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int) msg.wParam;
}




ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TEST));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_TEST);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}


BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

hInst = hInstance; // 将实例句柄存储在全局变量中

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)
{
return FALSE;
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);


char szAppName[] = "Hello world";
WNDCLASS wnd;
// ZDriveWindow1 zwnd1;
ZDriveWindow2 zwnd2;
ZDriveWindow3 zwnd3;

wnd.cbClsExtra = NULL;
wnd.cbWndExtra = NULL;
wnd.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wnd.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wnd.hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
wnd.hInstance = hInstance;
wnd.lpfnWndProc = ZWindow::StartWndProc;
wnd.lpszClassName = szAppName;
wnd.lpszMenuName = NULL;
wnd.style = CS_HREDRAW | CS_VREDRAW;

if (!RegisterClass(&wnd))
{
::MessageBox(NULL, "Can not register window class", "Error", MB_OK | MB_ICONINFORMATION);
return -1;
}


g_pWnd = &zwnd2;
zwnd2.Create(szAppName, "Test", hInstance, hWnd,
WS_VISIBLE | WS_CHILD | ES_MULTILINE|WS_BORDER|WS_THICKFRAME|WS_OVERLAPPEDWINDOW, NULL, NULL, 20, 20, 150, 150);
zwnd2.ShowWindow(nCmdShow);

g_pWnd = &zwnd3;
zwnd3.Create(szAppName, "Test", hInstance, hWnd,
WS_VISIBLE | WS_CHILD | ES_MULTILINE|WS_BORDER|WS_THICKFRAME|WS_OVERLAPPEDWINDOW, NULL, NULL, 520, 20, 150, 150);
zwnd3.ShowWindow(nCmdShow);

return TRUE;
}


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, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, 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;
}


INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
return (INT_PTR)FALSE;
}
cyofworld 2009-09-02
  • 打赏
  • 举报
回复
顶一个,
期待高手解决!
dungeonsnd 2009-09-02
  • 打赏
  • 举报
回复
我把代码贴出来,谁能帮帮我,万分感谢!
下面是有问题的代码,单步过了,也用spy++看过了。
我不知道怎么解决。
dungeonsnd 2009-09-01
  • 打赏
  • 举报
回复
郁闷啊, 利用Thunk,编译出问题。。。 郁闷至极。。。
vincent_1011 2009-08-21
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 dungeonsnd 的回复:]
引用 15 楼 vincent_1011 的回复:
要不你的dll接管主窗口的消息循环吧
setwindowlong


不可以哦。 因为我把这个DLL发布出去之后 用户调用了,如果我接管消息循环,那么主窗口岂不口执行不了自己的消息循环了,。。。比如它想关闭程序 有可能都关闭不了了,,除非子窗口再向主窗口发送消息,那样有点南辕北辙了。。。
消息还是应该主窗口收到,发送对应的子窗口,给相应的窗口过程处理比较妥当。
[/Quote]

我晕,你没搞过子类化吗?我说的接管只是为了在中间截获这个消息,然后还要给回主窗口的
关键字:CallWindowProc
dungeonsnd 2009-08-21
  • 打赏
  • 举报
回复
感谢上面的朋友回复,请下面的继续讨论,谢谢!
dungeonsnd 2009-08-21
  • 打赏
  • 举报
回复
UP...
dungeonsnd 2009-08-21
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 vincent_1011 的回复:]
要不你的dll接管主窗口的消息循环吧
setwindowlong
[/Quote]

不可以哦。 因为我把这个DLL发布出去之后 用户调用了,如果我接管消息循环,那么主窗口岂不口执行不了自己的消息循环了,。。。比如它想关闭程序 有可能都关闭不了了,,除非子窗口再向主窗口发送消息,那样有点南辕北辙了。。。
消息还是应该主窗口收到,发送对应的子窗口,给相应的窗口过程处理比较妥当。
dungeonsnd 2009-08-21
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 vincent_1011 的回复:]
引用 21 楼 dungeonsnd 的回复:
感谢!

我没听说过thunk技术,哈哈
[/Quote]

thunk是一组动态生成的ASM指令,它记录了窗口类对象的this指针,并且这组指令可以当作函数,既也可以是窗口过程来使用。thunk先把窗口对象this指针记录下来,然后转向到静态stdProc回调函数,转向之前先记录HWND,然后把堆栈里HWND的内容替换为this指针,这样在stdProc里就可以从HWND取回对象指针,定位到WindowProc了。
From:
http://hi.baidu.com/sdhexu/blog/item/33e5a5dde9321fee76c63891.html


根据我目前所所知(其它的方法还有待去学习,去研究!不过,肯定有!),对于封装窗口,貌似它是解决窗口过程函数与窗口句柄联系的最好的手段了。
vincent_1011 2009-08-21
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 dungeonsnd 的回复:]
感谢!
[/Quote]
我没听说过thunk技术,哈哈
dungeonsnd 2009-08-21
  • 打赏
  • 举报
回复
感谢!
dungeonsnd 2009-08-21
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 vincent_1011 的回复:]
引用 16 楼 dungeonsnd 的回复:
引用 15 楼 vincent_1011 的回复:
要不你的dll接管主窗口的消息循环吧
setwindowlong


不可以哦。 因为我把这个DLL发布出去之后 用户调用了,如果我接管消息循环,那么主窗口岂不口执行不了自己的消息循环了,。。。比如它想关闭程序 有可能都关闭不了了,,除非子窗口再向主窗口发送消息,那样有点南辕北辙了。。。
消息还是应该主窗口收到,发送对应的子窗口,给相应的窗口过程处理比较妥当。


我晕,你没搞过子类化吗?我说的接管只是为了在中间截获这个消息,然后还要给回主窗口的
关键字:CallWindowProc
[/Quote]

谢谢回复!


呵呵。。 没听过子类化这个名字,刚才查了一下,原来就是重定向消息。
其实我最近研究的Thunk技术跟你说的子类化有点类似哦(也许可以说成重定向),不知是否。
请看,这是在DLL中实现的


static LRESULT CALLBACK StartWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
ZWindow* pThis = g_pWnd;
pThis->m_hWnd = hWnd;

// initilize the thunk code
pThis->m_thunk.Init(WindowProc, pThis);

// get the address of thunk code
WNDPROC pProc = (WNDPROC)&(pThis->m_thunk.thunk);

::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)pProc);

return pProc(hWnd, uMsg, wParam, lParam);
}

static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
ZWindow* pThis = (ZWindow*)hWnd;

if (!pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam))
return ::DefWindowProc(pThis->m_hWnd, uMsg, wParam, lParam);
else
return 0;
}

代码中把
把实例的地址传过来之后,利用Thunk技术把 HWND精巧地换成this指针(因为子窗口的HWND应该和相应的派生类关联起来,否则前者没办法处理自己窗口的消息),接着,在初始化thunk代码之后,获得thunk的地址并向thunk代码设置新的回调函数(::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)pProc);)。 然后,thunk代码会调用WindowProc,但是现在第一个参数就不是HWND了,事实上它是this指针。
vincent_1011 2009-08-20
  • 打赏
  • 举报
回复
要不你的dll接管主窗口的消息循环吧
setwindowlong
dungeonsnd 2009-08-20
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 fishion 的回复:]
C/C++ code#include<windows.h>
#include<commctrl.h>
#include<wchar.h>
#include<string.h>
#include"Resource.h"#define PROCRUNDLGAPI extern "C" __declspec(dllexport)
#include"ProcRunDlg.h"#define WM_STOPPROCTHREAD WM_USER + 102

HINSTANCE g_hinst= NULL;
HWND g_hwndDLG= NULL;
HWND g_TempDLG= NULL;
HBRUSH g_hbrBackground;
DWORD g_hThreadListId=0;int g_ListIndex=0;struct HookProcInfo{

TCHAR Operation[20];
TCHAR ProcessInfo[MAX_PATH];
};#define WM_STOPTHREAD WM_USER + 101

..........
[/Quote]

兄弟,你这个 CreateDialog(g_hinst,MAKEINTRESOURCE(IDD_RECORDLISTBOX),NULL,ReList_DlgProc);
。。
你自己没有封装窗口呀。你是使用资源的呀,当然可以响应消息了。 使用VC生成新建一个对话框资料载到DLL里可以直接用了。
我觉得,,微软在CreateDialog后已经把窗口的创建到消息的传递给封装得非常完美了(比如 createwindow(_T("button"),... ) ),你创建一个按钮,当然可以接收消息了,不用自己来理会消息接收正确与否。

我现在在DLL里用最原始的API创建窗口 CreateWindow();(而不要加载资源,因为我要在CreateWindow里根据调用者传到DLL里的参数来创建个性窗口)。 所以不可以加载资源的,而且我要在创建的子窗口里渲染图形,使用资源不太好用。
fishion 2009-08-20
  • 打赏
  • 举报
回复
#include <windows.h>
#include <commctrl.h>
#include <wchar.h>
#include <string.h>
#include "Resource.h"

#define PROCRUNDLGAPI extern "C" __declspec(dllexport)
#include "ProcRunDlg.h"

#define WM_STOPPROCTHREAD WM_USER + 102

HINSTANCE g_hinst = NULL;
HWND g_hwndDLG = NULL;
HWND g_TempDLG = NULL;
HBRUSH g_hbrBackground;
DWORD g_hThreadListId = 0;
int g_ListIndex = 0;


struct HookProcInfo{

TCHAR Operation[20];
TCHAR ProcessInfo[MAX_PATH];
};

#define WM_STOPTHREAD WM_USER + 101

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved){

switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hinst = (HINSTANCE)hModule;
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;

}
void WriteLog(HWND hWnd){

}
INT_PTR WINAPI ReList_DlgProc(HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
){


HWND ReListView;
switch(uMsg)
{
case WM_INITDIALOG:
{
g_hbrBackground = CreateSolidBrush(RGB(66, 66, 66));
ReListView = GetDlgItem(hwndDlg ,IDC_RECLIST);
LVCOLUMN rlcol;
rlcol.mask = LVCF_TEXT | LVCF_WIDTH |LVCF_FMT;
rlcol.cx = 150;
rlcol.pszText = TEXT("时间");
rlcol.fmt = LVCFMT_CENTER;
ListView_InsertColumn(ReListView,1,&rlcol);
rlcol.cx = 300;
rlcol.pszText = TEXT("进程名称");
ListView_InsertColumn(ReListView,2,&rlcol);
rlcol.mask = LVCF_TEXT | LVCF_WIDTH;
rlcol.cx = 70;
rlcol.pszText = TEXT(" 运行状态");
ListView_InsertColumn(ReListView,3,&rlcol);

}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_RCLBTN:
MessageBox(hwndDlg,TEXT("清空列表成功!"),NULL,MB_ICONINFORMATION|MB_OK);
}
break;

case WM_CTLCOLORDLG:
return (LONG)g_hbrBackground;
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(255, 255, 255));
SetBkMode(hdcStatic, TRANSPARENT);
return (LONG)g_hbrBackground;
}

case WM_CLOSE:
//DeleteObject(g_hbrBackground);
break;
default:break;
}
return FALSE;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////


HWND ProcRunDlg(){

g_hwndDLG = CreateDialog(g_hinst,MAKEINTRESOURCE(IDD_RECORDLISTBOX),NULL,ReList_DlgProc);

return g_hwndDLG;
}


我这个在win32与MFC中都能正常响应消息
dungeonsnd 2009-08-19
  • 打赏
  • 举报
回复
另外,我不打算在这个DLL中使用MFC的东西。
dungeonsnd 2009-08-19
  • 打赏
  • 举报
回复
如果有谁做过这样的DLL,请给个框架例子
(比如调用者调用DLL后,创建十个DLL实例,来创建十个子窗口,每个窗口过程可以正常的收到主窗口(调用者
发过来的消息,然后发送到正确的子窗口中,DLL中的子窗口过程进行处理),谢谢。 毕竟自己写框架不太成熟.(即使仿照 wtl and atl)

thank you

dungeonsnd@126.com
dungeonsnd 2009-08-19
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 tr0j4n 的回复:]
给你提供学习WTL的几个网址

http://blog.csdn.net/orbit/archive/2006/04/14/663865.aspx
http://www.codeproject.com/KB/wtl/wtl4mfc1.aspx
[/Quote]

Thank u!
MoXiaoRab 2009-08-19
  • 打赏
  • 举报
回复
给你提供学习WTL的几个网址

http://blog.csdn.net/orbit/archive/2006/04/14/663865.aspx
http://www.codeproject.com/KB/wtl/wtl4mfc1.aspx
加载更多回复(8)
DirectX修复工具(DirectX Repair)是一款系统级工具软件,简便易用。本程序为绿色版,无需安装,可直接运行。 本程序的主要功能是检测当前系统的DirectX状态,如果发现异常则进行修复。程序主要针对0xc000007b问题设计,可以完美修复该问题。本程序包含了最新版的DirectX redist(Jun2010),并且全部DX文件都有Microsoft的数字签名,安全放心。 本程序为了应对一般电脑用户的使用,采用了傻瓜式一键设计,只要点击主界面上的“检测并修复”按钮,程序就会自动完成校验、检测、下载、修复以及注册的全部功能,无需用户的介入,大大降低了使用难度。 本程序适用于多个操作系统,如Windows XP(需先安装.NET 2.0,详情请参阅“致Windows XP用户.txt”文件)、Windows Vista、Windows 7、Windows 8、Windows Blue(Windows 8.1),同时兼容32位操作系统和64位操作系统。本程序会根据系统的不同,自动调整任务模式,无需用户进行设置。 本程序的V3.2版分为标准版、增强版以及在线修复版。其的标准版以及增强版都包含完整的DirectX组件。另外,增强版还额外包含了c++ Redistributable Package,因此增强版不但能解决DirectX组件的问题,而且还能解决c++组件异常产生的问题。增强版适合无法自行解决c++相关问题的用户使用。在线修复版的功能与标准版相同,只是其所需的文件将通过Internet下载,因此大大减小了程序的体积。本程序的各个版本之间,主程序完全相同,只是配套使用的数据包不同。因此,当您使用标准版数据包时,程序将进行标准修复;当您使用增强版的数据包时,程序将进行增强修复;当数据包不全或没有数据包(即只有DirectX Repair.exe程序)时,程序将进行在线修复。在线修复、离线修复可自由灵活组合,充分满足不同用户的需要。 本程序自V2.0版起采用全新的底层程序架构,使用了异步多线程编程技术,使得检测、下载、修复单独进行,互不干扰,快速如飞。新程序更改了自我校验方式,因此使用新版本的程序时不会再出现自我校验失败的错误;但并非取消自我校验,因此程序安全性与之前版本相同,并未降低。 程序有自动更新c++功能。由于绝大多数软件运行时需要c++的支持,并且c++的异常也会导致0xc000007b错误,因此程序在检测修复的同时,也会根据需要更新系统的c++组件。V3.2版本使用了全新的c++扩展包,可以大幅提高工业软件修复成功的概率。此功能仅限于增强版。 程序有两种窗口样式。正常模式即默认样式,适合绝大多数用户使用。另有一种简约模式,此时窗口将只显示最基本的内容,修复会自动进行,修复完成10秒钟后会自动退出。该窗口样式可以使修复工作变得更加简单快速,同时方便其他软件、游戏将本程序内嵌,即可进行无需人工参与的快速修复。开启简约模式的方法是:打开程序所在目录下的“Settings.ini”文件(如果没有可以自己创建),将其的“FormStyle”一项的值改为“Simple”并保存即可。 程序有高级筛选功能,开启该功能后用户可以自主选择要修复的文件,避免了其他不必要的修复工作。同时,也支持通过文件进行辅助筛选,只要在程序目录下建立“Filter.dat”文件,其的每一行写一个需要修复文件的序号即可。该功能仅针对高级用户使用,并且必须在正常窗口模式下才有效(简约模式时无效)。 本程序有自动记录日志功能,可以记录每一次检测修复结果,方便在出现问题时,及时分析和查找原因,以便找到解决办法。 程序的“选项”对话框包含了4项高级功能。点击其的“注册系统文件夹所有dll文件”按钮可以自动注册系统文件夹下的所有dll文件。该项功能不仅能修复DirectX的问题,还可以修复系统很多其他由于dll未注册而产生的问题,颇为实用。点击该按钮旁边的小箭头,还可以注册任意指定文件夹下的dll文件,方便用户对绿色版、硬盘版的程序组件进行注册。点击第二个按钮可以为dll文件的右键菜单添加“注册”和“卸载”项,方便对单独的dll文件进行注册。请注意,并不是所有的dll文件都可以通过这种方式注册。点击“DirectX版本”选项卡可以自行修改系统DirectX的版本信息。点击“DirectX加速”选项卡可以控制系统DirectX加速的开启与关闭。 新版程序集成了用户反馈程序,可以在用户允许的前提下发送检测修复结果。用户也可以在出现问题时通过反馈程序和软件作者进行交流,共同查找问题。反馈是完全自愿和匿名(如果不填写E-mail地址)的。 本程序的通用版基于Microsoft .NET Framework 2.0开发,对于Windows 2000、Windows XP、Windows 2003的用户需要首先安装.NET Framework 2.0或更高版本方可运行本程序。有关下载和安装的详细信息请参阅“致Windows XP用户.txt”文件。对于Windows Vista、Windows 7用户,可以直接运行本程序。 同时鉴于Windows 8(Windows Blue、Windows 8.1)系统默认未包含.NET Framework 2.0,因此新版的程序文件夹内将包含一个DirectX_Repair_win8的特别版程序,该程序功能与通用版相同,基于.NET Framework 4.0开发,可以在Windows8(Windows Blue、Windows 8.1)系统直接运行(其他系统如果安装了.NET Framework 4.0也可以运行这个特别版的程序)。 本程序的官方博客地址为:http://blog.csdn.net/vbcom/article/details/6962388所有的更新以及技术支持都可以到该博客上找到。

15,473

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧