一般来说,从CWnd继承下来的控件(非标准控件),都需要在构造函数初始化时,添加下面这个成员函数:
#define YOUR_CLASS_NAME _T("TestCtrl")
class CxxYouCtrl : public CWnd
{
public:
CxxYouCtrl();
// ...
};
// 这里必须注册控件
CxxYouCtrl::CxxYouCtrl()
{
RegisterWindowClass();
}
// Register the window class if it has not already been registered.
BOOL CxxYouCtrl::RegisterWindowClass()
{
WNDCLASS wndcls;
HINSTANCE hInst = AfxGetResourceHandle();
ZeroMemory(&wndcls, sizeof(WNDCLASS));
if (!(::GetClassInfo(hInst, YOUR_CLASS_NAME, &wndcls)))
{
// otherwise we need to register a new class
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
#ifndef _WIN32_WCE_NO_CURSOR
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
#else
wndcls.hCursor = 0;
#endif
wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = YOUR_CLASS_NAME;
if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}
上面这种写法是常规的,无论你从导出函数还是主程序直接调用都没有任何问题。
但是!!!!!!!!
当你在使得多语言的资源DLL时,你会发现自绘控件全跪了,基本在CWnd::Create这里就失败(错误0,S_OK没异常)
而你的GetClassInfo又是正常返回TRUE,这下就蛋疼了,经过排查发现:
当你在调用AfxSetResourceHandle切换资源句柄的时候,需要先用AfxGetResourceHandle保存旧的句柄,上面的Reg函数在旧的资源句柄中也需要注册一次,就能完美解决!
函数修正了一下:
// Register the window class if it has not already been registered.
BOOL MTRegisterWindowClass(HINSTANCE hInstance, TCHAR *pszName)
{
WNDCLASS wndcls;
HINSTANCE hInst = NULL;
if(hInstance == NULL)
hInst = AfxGetResourceHandle();
else
hInst = hInstance;
ZeroMemory(&wndcls, sizeof(WNDCLASS));
if (!(::GetClassInfo(hInst, pszName, &wndcls)))
{
// otherwise we need to register a new class
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
#ifndef _WIN32_WCE_NO_CURSOR
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
#else
wndcls.hCursor = 0;
#endif
wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = pszName;
if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}
#define YOUR_CLASS_NAME _T("TestCtrl")
class CxxYouCtrl : public CWnd
{
public:
CxxYouCtrl();
// ...
};
// 这里必须注册控件
CxxYouCtrl::CxxYouCtrl()
{
RegisterWindowClass();
}
// Register the window class if it has not already been registered.
BOOL CxxYouCtrl::RegisterWindowClass()
{
WNDCLASS wndcls;
HINSTANCE hInst = AfxGetResourceHandle();
ZeroMemory(&wndcls, sizeof(WNDCLASS));
if (!(::GetClassInfo(hInst, YOUR_CLASS_NAME, &wndcls)))
{
// otherwise we need to register a new class
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
#ifndef _WIN32_WCE_NO_CURSOR
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
#else
wndcls.hCursor = 0;
#endif
wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = YOUR_CLASS_NAME;
if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}
在调用前,重新注册一下旧句柄即可!
void SetNewResourceHandle()
{
HINSTANCE hInstOld = AfxGetResourceHandle();
HINSTANCE hInstNew = LoadLibrary(_T("english.dll");
// 切换资源前保存旧句柄,并重新注册控件
if(hInstNew)
{
AfxSetResourceHandle(hInstNew);
MTRegisterWindowClass(hInstOld, YOUR_CLASS_NAME);
}
}