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);
	}
}


CWnd类提供了微软基础类库中所有窗口类的基本功能。 CWnd对象与Windows的窗口不同,但是两者有紧密联系。CWnd对象是由CWnd的构造函数和析构函数创建或销毁的。另一方面,Windows的窗口是Windows的一种内部数据结构,它是由CWndCreate成员函数创建的,而由CWnd的虚拟析构函数销毁。DestroyWindow函数销毁Windows的窗口,但是不销毁对象。 CWnd类和消息映射机制隐藏了WndProc函数。接收到的Windows通知消息通过消息映射被自动发送到适当的CWnd OnMessage成员函数。你可以在派生类中重载OnMessage成员函数以处理成员的特定消息。 CWnd类同时还使你能够为应用程序创建Windows的子窗口。先从CWnd继承一个类,然后在派生类中加入成员变量以保存与你的应用程序有关的数据。在派生类中实现消息处理成员函数和消息映射,以指定当消息被发送到窗口时应该如何动作。 你可以经过两个步骤来创建一个子窗口。首先,调用构造函数CWnd以创建一个CWnd对象,然后调用Create成员函数以创建子窗口并将它连接到CWnd对象。 当用户关闭你的子窗口时,应销毁CWnd对象,或者调用DestroyWindow成员函数以清除窗口并销毁它的数据结构。 在微软基础类库中,从CWnd派生了许多其它类以提供特定的窗口类型。这些类中有许多,包括CFrameWnd,CMDIFrameWnd,CMDIChildWnd,CView和CDialog,被用来进一步派生。从CWnd派生的控件类,如CButton,可以被直接使用,也可以被进一步派生出其它类来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汪宁宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值