天天看点

MFC多国语言资源DLL中自绘控件显示问题CWnd::Create失败解决方案!

一般来说,从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);
	}
}