设置/删除窗口子类时,正确传递/删除数据

Properly pass / remove data when setting / removing window subclass

本文关键字:删除 数据 窗口 子类 设置      更新时间:2023-10-16

简介和相关信息:

我在一个dialog box中有多个edit control,它们需要接受浮点数并具有locale意识我决定用subclassingedit control来实现这种行为。

为了实现locale意识,我决定将一个结构传递给SetWindowSubclass(它将保存有关十进制分隔符、负号等的数据…)作为dwRefData参数。

字段的值在WM_CREATE中设置,但如果用户更改Control Panel->Regional and Language Settings中的设置,它们可能会更改,因此我决定更新字段的值以响应WM_SETTINGCHANGE消息。

为了避免将此结构设为全局结构,我决定将其设为static,并在主窗口的过程中声明它。我将把它作为CreateDialogParamAPI的LPARAM参数传递给对话框。

问题:

我不知道如何将上述结构正确地传递给CCD_ 15和CCD_。

问题还在于正确移除subclass,从而可以避免内存泄漏

我为解决这个问题所做的努力:

在互联网上搜索后,我没有找到任何有用的东西,所以现在我只有一个概念性的解决方案。

它应该看起来像这样:

//declare our structure that holds locale info
struct locale_structure
{
wchar_t NegativeSign;
wchar_t separator;
};
//in my main window procedure: 
static locale_structure MyStruct;
case WM_CREATE:
{
//get locale info about separator, negative sign and so on...
MyStruct->separator      = //...
MyStruct->NegativeSign   = //...
}
return 0L;
case WM_SETTINGCHANGE:
{
//update locale info about separator, negative sign and so on...
MyStruct->NegativeSign  =    //...
MyStruct->separator     =    //...
//...
}
// in the WM_COMMAND, to the response to a button click, pass MyStruct:
hwndSomeDlg = CreateDialogParam( ..., (LPARAM)MyStruct );

在我的dialog box中,我应该像这样删除subclass/subclass

case WM_INITDIALOG:
{
/******** This is the tricky part ***********/
/// get locale structure from lParam
locale_structure MyStruct = ( locale_structure )lParam;
// pass it properly to subclassing procedures
SetWindowSubclass( GetDlgItem( hDlg, IDC_EDIT1 ), ...,  MyStruct );
SetWindowSubclass( GetDlgItem( hDlg, IDC_EDIT2 ), ...,  MyStruct );
/************** other stuff ***********************/     
}
return TRUE;
case WM_CLOSE:
{
// perform proper cleanup to avoid memory leaks
RemoveWindowSubclass( ... );
}  

问题:

  1. 我应该如何将MyStruct传递给CreateDialogParamSetWindowSubclass

  2. 我应该如何删除subclassing以避免内存泄漏

  3. 我假设subclassing procedure中也会发生一些内存分配和释放,你能告诉我如何正确地进行吗?

2014年2月22日编辑

我提交的代码实现了我努力解决这一问题一节中描述的概念。

该程序使主窗口带有一个启动对话框的按钮。该对话框包含两个子类编辑控件。一切都很好,所以我现在唯一关心的是我是否正确地删除了结构。

只需制作一个空项目并复制/粘贴所需文件:

resource.h:中

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by resource.rc
//
#define IDD_DIALOG1                     101
#define IDC_EDIT1                       1001
#define IDC_EDIT2                       1002
// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        102
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1003
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

resource.rc:中

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE 
BEGIN
"resource.h"
END
2 TEXTINCLUDE 
BEGIN
"#include ""afxres.h""rn"
""
END
3 TEXTINCLUDE 
BEGIN
"rn"
""
END
#endif    // APSTUDIO_INVOKED

/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_DIALOG1 DIALOGEX 0, 0, 316, 180
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON   "OK",IDOK,205,159,50,14
PUSHBUTTON      "Cancel",IDCANCEL,259,159,50,14
EDITTEXT        IDC_EDIT1,23,20,94,17,ES_AUTOHSCROLL
EDITTEXT        IDC_EDIT2,23,65,90,21,ES_AUTOHSCROLL
END

/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO 
BEGIN
IDD_DIALOG1, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 309
TOPMARGIN, 7
BOTTOMMARGIN, 173
END
END
#endif    // APSTUDIO_INVOKED
#endif    // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////

#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//

/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

main.cpp:中

#include <windows.h>
#include <commctrl.h>
#include <stdlib.h>
#include <locale.h>
#include <stdio.h>
#pragma comment( lib, "comctl32.lib")
const wchar_t g_szClassName[] = L"myWindowClass";
// structure to hold locale info 
typedef struct LocaleInfo
{
wchar_t NegativeSign[5];
wchar_t DecimalSeparator[5];
}*pLocaleInfo;
// subclassing procedure
LRESULT CALLBACK Decimalni( HWND hwnd, UINT message, 
WPARAM wParam, LPARAM lParam, 
UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
pLocaleInfo li = ( pLocaleInfo )dwRefData;
switch (message)
{
case WM_CHAR:
{
// accept digits,decimal separatorand negative sign
// this validation is just an example
if( ( isdigit(wParam) ) || ( wParam < L' ' ) )
break;
else
{
for( size_t i = 0; i < 5; i++ )
if( ( wParam == li->DecimalSeparator[i] )
|| ( wParam == li->NegativeSign[i] ) )
{
return DefSubclassProc( hwnd, message, wParam, lParam);
break;
}
else
{
MessageBeep(0);
return FALSE;
break;
}
}
}
break;
case WM_NCDESTROY:
// should I delete structure here ??
RemoveWindowSubclass( hwnd, Decimalni, 0 );
break;
}
return DefSubclassProc( hwnd, message, wParam, lParam);
}
// dialog box procedure
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_INITDIALOG:
{
// subclass edit control
pLocaleInfo li = ( pLocaleInfo )lParam;
SetWindowSubclass( GetDlgItem( hwnd, IDC_EDIT1 ), 
Decimalni, 0, (DWORD_PTR)li );
SetWindowSubclass( GetDlgItem( hwnd, IDC_EDIT2 ), 
Decimalni, 0, (DWORD_PTR)li );
}
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static pLocaleInfo li; // store decimal separator and minus sign
switch(msg)
{
case WM_CREATE:
{
/************* load current locale settings *************/
// max. len: language, country, code page
wchar_t lpszLocale[64+64+16+3] = L""; 
wchar_t lpszVal[128];
LCID nLCID = ::GetUserDefaultLCID(); // current LCID for user
if ( ::GetLocaleInfo( nLCID, LOCALE_SENGLANGUAGE, lpszVal, 128 ) )
{
wcscat_s( lpszLocale, 147, lpszVal ); // language
if ( ::GetLocaleInfo( nLCID, LOCALE_SENGCOUNTRY, lpszVal, 128 ) )
{
wcscat_s( lpszLocale, 147, L"_" ); // append country/region
wcscat_s( lpszLocale, 147, lpszVal );
if ( ::GetLocaleInfo( nLCID, LOCALE_IDEFAULTANSICODEPAGE, 
lpszVal, 128 ) )
{ 
// missing code page or page number 0 is no error 
// (e.g. with Unicode)
int nCPNum = _wtoi(lpszVal);
if (nCPNum >= 10)
{
wcscat_s( lpszLocale, 147, L"." ); // append code page
wcscat_s( lpszLocale, 147, lpszVal );
}
}
}
}
// set locale and LCID
_wsetlocale( LC_ALL, lpszLocale );
::SetThreadLocale(nLCID);
/*** get information for decimal separator and negative sign ***/
li = new LocaleInfo;
GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, 
li->DecimalSeparator, 
sizeof(li->DecimalSeparator) / sizeof(li->DecimalSeparator[0] ) );
GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SNEGATIVESIGN, 
li->NegativeSign, 
sizeof(li->NegativeSign) / sizeof(li->NegativeSign[0] ) );
/*** create a button that launches a test dialog box *****/
HWND hButton = CreateWindowEx(0, L"Button", 
L"Test subclassed edit controls in dialog box", 
WS_BORDER | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 
50, 50, 350, 80, hwnd, (HMENU)8001, 
GetModuleHandle(NULL), NULL);
}
break;
case WM_SETTINGCHANGE:
if( !wParam && !wcscmp( (wchar_t*)lParam, L"intl" ) )
{
// max. len: language, country, code page
wchar_t lpszLocale[64+64+16+3] = L""; 
wchar_t lpszVal[128];
LCID nLCID = ::GetUserDefaultLCID(); // current LCID for user
if ( ::GetLocaleInfo( nLCID, LOCALE_SENGLANGUAGE, lpszVal, 128 ) )
{
wcscat_s( lpszLocale, 147, lpszVal ); // language
if ( ::GetLocaleInfo( nLCID, LOCALE_SENGCOUNTRY, lpszVal, 128 ) )
{
wcscat_s( lpszLocale, 147, L"_" ); // append country/region
wcscat_s( lpszLocale, 147, lpszVal );
if ( ::GetLocaleInfo( nLCID, LOCALE_IDEFAULTANSICODEPAGE, 
lpszVal, 128 ) )
{ 
// missing code page or page number 0 is no error 
// (e.g. with Unicode)
int nCPNum = _wtoi(lpszVal);
if (nCPNum >= 10)
{
wcscat_s( lpszLocale, 147, L"." ); // append code page
wcscat_s( lpszLocale, 147, lpszVal );
}
}
}
}
// set locale and LCID
_wsetlocale( LC_ALL, lpszLocale );
::SetThreadLocale(nLCID);
/** update information for decimal separator and negative sign ***/
GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, 
li->DecimalSeparator, 
sizeof(li->DecimalSeparator) / sizeof(li->DecimalSeparator[0] ) );
GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SNEGATIVESIGN, 
li->NegativeSign, 
sizeof(li->NegativeSign) / sizeof(li->NegativeSign[0] ) );
return 0L;
}
else
break;
case WM_COMMAND:
{
if( LOWORD(wParam) == 8001 )
{
DialogBoxParam( GetModuleHandle(NULL), 
MAKEINTRESOURCE(IDD_DIALOG1), hwnd, DlgProc, (LPARAM)li );
}
}
return 0L;
case WM_CLOSE:
delete li;
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize        = sizeof(WNDCLASSEX);
wc.style         = 0;
wc.lpfnWndProc   = WndProc;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hInstance     = hInstance;
wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName  = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
0,
g_szClassName,
L"theForger's Tutorial Application",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 480, 320,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, L"Window Creation Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

编辑结束

感谢您的时间和帮助。

致以最良好的问候。

编辑2:

下面是一个工作示例(我希望如此):

#include "resource.h"
#include <windows.h>
#include <commctrl.h>
#include <stdlib.h>
#include <locale.h>
#include <stdio.h>
#pragma comment( lib, "comctl32.lib")
const wchar_t g_szClassName[] = L"myWindowClass";
// structure to hold locale info 
typedef struct LocaleInfo
{
size_t NegativeSize, DecimalSize;
wchar_t *NegativeSign, *DecimalSeparator;
LocaleInfo()
{
NegativeSize = 0;
DecimalSize = 0;
NegativeSign = NULL;
DecimalSeparator = NULL;
}
~LocaleInfo()
{
if (NegativeSign != NULL)
{
delete[] NegativeSign;
NegativeSign = NULL;
}
if (DecimalSeparator != NULL)
{
delete[] DecimalSeparator;
DecimalSeparator = NULL;
}
}
}*pLocaleInfo;
void ReallocateInfo(wchar_t *&InsideArray, size_t &InsideSize, size_t NewSize)
{
if (NewSize == 0)
return;
wchar_t *NewArray = new wchar_t[NewSize];
delete[] InsideArray;
InsideArray = NewArray;
InsideSize = NewSize;
}
// subclassing procedure
LRESULT CALLBACK Decimalni(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
pLocaleInfo li = (pLocaleInfo)dwRefData;
switch (message)
{
case WM_CHAR:
{
// accept digits,decimal separatorand negative sign
// this validation is just an example
if ((isdigit(wParam)) || (wParam < L' '))
break;
else
{
for (size_t i = 0; i < 5; i++)
if ((wParam == li->DecimalSeparator[i])
|| (wParam == li->NegativeSign[i]))
{
return DefSubclassProc(hwnd, message, wParam, lParam);
break;
}
else
{
MessageBeep(0);
return FALSE;
break;
}
}
}
break;
case WM_NCDESTROY:
// should I delete structure here ??
RemoveWindowSubclass(hwnd, Decimalni, 0);
break;
}
return DefSubclassProc(hwnd, message, wParam, lParam);
}
// dialog box procedure
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_INITDIALOG:
{
// subclass edit control
pLocaleInfo li = (pLocaleInfo)lParam;
SetWindowSubclass(GetDlgItem(hwnd, IDC_EDIT1),
Decimalni, 0, (DWORD_PTR)li);
SetWindowSubclass(GetDlgItem(hwnd, IDC_EDIT2),
Decimalni, 0, (DWORD_PTR)li);
}
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static pLocaleInfo li; // store decimal separator and minus sign
switch (msg)
{
case WM_CREATE:
{
/************* load current locale settings *************/
// max. len: language, country, code page
wchar_t lpszLocale[64 + 64 + 16 + 3] = L"";
wchar_t lpszVal[128];
LCID nLCID = ::GetUserDefaultLCID(); // current LCID for user
if (::GetLocaleInfo(nLCID, LOCALE_SENGLANGUAGE, lpszVal, 128))
{
wcscat_s(lpszLocale, 147, lpszVal); // language
if (::GetLocaleInfo(nLCID, LOCALE_SENGCOUNTRY, lpszVal, 128))
{
wcscat_s(lpszLocale, 147, L"_"); // append country/region
wcscat_s(lpszLocale, 147, lpszVal);
if (::GetLocaleInfo(nLCID, LOCALE_IDEFAULTANSICODEPAGE,
lpszVal, 128))
{
// missing code page or page number 0 is no error 
// (e.g. with Unicode)
int nCPNum = _wtoi(lpszVal);
if (nCPNum >= 10)
{
wcscat_s(lpszLocale, 147, L"."); // append code page
wcscat_s(lpszLocale, 147, lpszVal);
}
}
}
}
// set locale and LCID
_wsetlocale(LC_ALL, lpszLocale);
::SetThreadLocale(nLCID);
/*** get information for decimal separator and negative sign ***/
li = new LocaleInfo;
ReallocateInfo(li->DecimalSeparator, li->DecimalSize, GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, NULL, NULL));
ReallocateInfo(li->NegativeSign, li->NegativeSize, GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNEGATIVESIGN, NULL, NULL));
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
li->DecimalSeparator,
li->DecimalSize);
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNEGATIVESIGN,
li->NegativeSign,
li->NegativeSize);
/*** create a button that launches a test dialog box *****/
HWND hButton = CreateWindowEx(0, L"Button",
L"Test subclassed edit controls in dialog box",
WS_BORDER | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
50, 50, 350, 80, hwnd, (HMENU)8001,
GetModuleHandle(NULL), NULL);
}
break;
case WM_SETTINGCHANGE:
if (!wParam && !wcscmp((wchar_t*)lParam, L"intl"))
{
// max. len: language, country, code page
wchar_t lpszLocale[64 + 64 + 16 + 3] = L"";
wchar_t lpszVal[128];
LCID nLCID = ::GetUserDefaultLCID(); // current LCID for user
if (::GetLocaleInfo(nLCID, LOCALE_SENGLANGUAGE, lpszVal, 128))
{
wcscat_s(lpszLocale, 147, lpszVal); // language
if (::GetLocaleInfo(nLCID, LOCALE_SENGCOUNTRY, lpszVal, 128))
{
wcscat_s(lpszLocale, 147, L"_"); // append country/region
wcscat_s(lpszLocale, 147, lpszVal);
if (::GetLocaleInfo(nLCID, LOCALE_IDEFAULTANSICODEPAGE,
lpszVal, 128))
{
// missing code page or page number 0 is no error 
// (e.g. with Unicode)
int nCPNum = _wtoi(lpszVal);
if (nCPNum >= 10)
{
wcscat_s(lpszLocale, 147, L"."); // append code page
wcscat_s(lpszLocale, 147, lpszVal);
}
}
}
}
// set locale and LCID
_wsetlocale(LC_ALL, lpszLocale);
::SetThreadLocale(nLCID);
/** update information for decimal separator and negative sign ***/
ReallocateInfo(li->DecimalSeparator, li->DecimalSize, GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, NULL, NULL));
ReallocateInfo(li->NegativeSign, li->NegativeSize, GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNEGATIVESIGN, NULL, NULL));
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
li->DecimalSeparator,
li->DecimalSize);
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNEGATIVESIGN,
li->NegativeSign,
li->NegativeSize);
return 0L;
}
else
break;
case WM_COMMAND:
{
if (LOWORD(wParam) == 8001)
{
DialogBoxParam(GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_DIALOG1), hwnd, DlgProc, (LPARAM)li);
}
}
return 0L;
case WM_CLOSE:
{
delete li;
DestroyWindow(hwnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
0,
g_szClassName,
L"theForger's Tutorial Application",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 480, 320,
NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, L"Window Creation Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

编辑:

一切都很好。您在WM_NCDESTROY上删除它是正确的,因为它将始终被调用(有时可能会跳过WM_CLOSE)。尽管如此,您还是忘记了WM_CLOSE上的{},所以当编译器决定您需要问题时,可能会出现一些问题。

应该使用智能指针,因为它应该为您释放内存,以防出现问题,但这取决于您的选择。它们还有一个好处,那就是很容易适应你的代码,你基本上什么都不改变。最后一件事,这个"SmartPointer"是我创建的,可能仍然不完整,其他的替代品是unique_ptrshared_ptr和更多可以在互联网上找到的。

好了:

#include "resource.h"
#include <Windows.h>
#include <commctrl.h>
#include <stdlib.h>
#include <locale.h>
#include <stdio.h>
#include "SmartPointer.h"
#pragma comment( lib, "comctl32.lib")
const wchar_t g_szClassName[] = L"myWindowClass";
// structure to hold locale info 
struct LocaleInfo
{
wchar_t NegativeSign[5];
wchar_t DecimalSeparator[5];
};
// subclassing procedure
LRESULT CALLBACK Decimalni(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
SmartPointer<LocaleInfo> *li = (SmartPointer<LocaleInfo>*)dwRefData;
switch (message)
{
case WM_CHAR:
{
// accept digits,decimal separatorand negative sign
// this validation is just an example
if ((isdigit(wParam)) || (wParam < L' '))
break;
else
{
for (size_t i = 0; i < 5; i++)
if ((wParam == (*li)->DecimalSeparator[i])
|| (wParam == (*li)->NegativeSign[i]))
{
return DefSubclassProc(hwnd, message, wParam, lParam);
break;
}
else
{
MessageBeep(0);
return FALSE;
break;
}
}
}
break;
case WM_NCDESTROY:
// should I delete structure here ??
RemoveWindowSubclass(hwnd, Decimalni, 0);
break;
}
return DefSubclassProc(hwnd, message, wParam, lParam);
}
// dialog box procedure
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_INITDIALOG:
{
// subclass edit control
SmartPointer<LocaleInfo> *li = (SmartPointer<LocaleInfo>*)lParam;
SetWindowSubclass(GetDlgItem(hwnd, IDC_EDIT1),
Decimalni, 0, (DWORD_PTR)li);
SetWindowSubclass(GetDlgItem(hwnd, IDC_EDIT2),
Decimalni, 0, (DWORD_PTR)li);
}
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static SmartPointer<LocaleInfo> li; // store decimal separator and minus sign
switch (msg)
{
case WM_CREATE:
{
/************* load current locale settings *************/
// max. len: language, country, code page
wchar_t lpszLocale[64 + 64 + 16 + 3] = L"";
wchar_t lpszVal[128];
LCID nLCID = ::GetUserDefaultLCID(); // current LCID for user
if (::GetLocaleInfo(nLCID, LOCALE_SENGLANGUAGE, lpszVal, 128))
{
wcscat_s(lpszLocale, 147, lpszVal); // language
if (::GetLocaleInfo(nLCID, LOCALE_SENGCOUNTRY, lpszVal, 128))
{
wcscat_s(lpszLocale, 147, L"_"); // append country/region
wcscat_s(lpszLocale, 147, lpszVal);
if (::GetLocaleInfo(nLCID, LOCALE_IDEFAULTANSICODEPAGE,
lpszVal, 128))
{
// missing code page or page number 0 is no error 
// (e.g. with Unicode)
int nCPNum = _wtoi(lpszVal);
if (nCPNum >= 10)
{
wcscat_s(lpszLocale, 147, L"."); // append code page
wcscat_s(lpszLocale, 147, lpszVal);
}
}
}
}
// set locale and LCID
_wsetlocale(LC_ALL, lpszLocale);
::SetThreadLocale(nLCID);
/*** get information for decimal separator and negative sign ***/
li = SmartPointer<LocaleInfo>(LocaleInfo());
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
li->DecimalSeparator,
sizeof(li->DecimalSeparator) / sizeof(li->DecimalSeparator[0]));
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNEGATIVESIGN,
li->NegativeSign,
sizeof(li->NegativeSign) / sizeof(li->NegativeSign[0]));
/*** create a button that launches a test dialog box *****/
HWND hButton = CreateWindowEx(0, L"Button",
L"Test subclassed edit controls in dialog box",
WS_BORDER | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
50, 50, 350, 80, hwnd, (HMENU)8001,
GetModuleHandle(NULL), NULL);
}
break;
case WM_SETTINGCHANGE:
if (!wParam && !wcscmp((wchar_t*)lParam, L"intl"))
{
// max. len: language, country, code page
wchar_t lpszLocale[64 + 64 + 16 + 3] = L"";
wchar_t lpszVal[128];
LCID nLCID = ::GetUserDefaultLCID(); // current LCID for user
if (::GetLocaleInfo(nLCID, LOCALE_SENGLANGUAGE, lpszVal, 128))
{
wcscat_s(lpszLocale, 147, lpszVal); // language
if (::GetLocaleInfo(nLCID, LOCALE_SENGCOUNTRY, lpszVal, 128))
{
wcscat_s(lpszLocale, 147, L"_"); // append country/region
wcscat_s(lpszLocale, 147, lpszVal);
if (::GetLocaleInfo(nLCID, LOCALE_IDEFAULTANSICODEPAGE,
lpszVal, 128))
{
// missing code page or page number 0 is no error 
// (e.g. with Unicode)
int nCPNum = _wtoi(lpszVal);
if (nCPNum >= 10)
{
wcscat_s(lpszLocale, 147, L"."); // append code page
wcscat_s(lpszLocale, 147, lpszVal);
}
}
}
}
// set locale and LCID
_wsetlocale(LC_ALL, lpszLocale);
::SetThreadLocale(nLCID);
/** update information for decimal separator and negative sign ***/
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
li->DecimalSeparator,
sizeof(li->DecimalSeparator) / sizeof(li->DecimalSeparator[0]));
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNEGATIVESIGN,
li->NegativeSign,
sizeof(li->NegativeSign) / sizeof(li->NegativeSign[0]));
return 0L;
}
else
break;
case WM_COMMAND:
{
if (LOWORD(wParam) == 8001)
{
DialogBoxParam(GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_DIALOG1), hwnd, DlgProc, (LPARAM)li);
}
}
return 0L;
case WM_CLOSE:
{
DestroyWindow(hwnd);
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
0,
g_szClassName,
L"theForger's Tutorial Application",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 480, 320,
NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, L"Window Creation Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

  1. 如果我是你,我想通过SetWindowSubclass()CreateDialogParam()传递一个指针(最好是智能指针,它可以来自STD或定制)结构。通过这种方式,它将反映出您在所有窗口的结构内部所做的更改。一些简短的程序会很好,因为我附近没有任何对话框模板,所以我不能给你一个如何将其传递给函数的例子。

  2. 我认为删除WM_CLOSE上的子线程应该很好。

  3. 多一点信息就好了。


struct locale_structure
{
wchar_t NegativeSign;
wchar_t separator;
};
static SmartPointer<locale_structure> MyStruct;

#ifndef __SMART_POINTER
#define __SMART_POINTER
#include <wtypes.h>
#include <utility>
template <class Type>
class SmartPointer
{
private:
void SmartDelete()
{
if (Pointer != nullptr && RefCount != nullptr && Size != nullptr)
{
if (RefCount[0] > 0)
RefCount[0]--;
else
{
if (Size[0] == 0)
delete Pointer;
else
delete[] Pointer;
delete RefCount;
delete Size;
}
Pointer = nullptr;
RefCount = nullptr;
Size = nullptr;
}
}
Type* Pointer;
size_t* Size;
UINT* RefCount;
public:
UINT size()
{
if (Pointer != NULL && RefCount != NULL && Size != NULL)
{
if (Size[0] == 0)
return 1;
else
return Size[0];
}
else
return 0;
}
SmartPointer() : Pointer(nullptr), Size(nullptr), RefCount(nullptr) {}
Type& operator*() { return *Pointer; }
const Type& operator*() const { return *Pointer; }
Type* operator->() { return Pointer; }
const Type* operator->() const { return Pointer; }
Type& operator[](size_t index) { return Pointer[index]; }
const Type& operator[](size_t index) const { return Pointer[index]; }
template<typename ConversionType>
operator ConversionType() { return reinterpret_cast<ConversionType>(this); }
SmartPointer(Type& Object, size_t Size = 0)
{
RefCount = new UINT();
this->Size = new size_t(Size);
if (Size == 0)
Pointer = new Type(std::move(Object));
else
{
Pointer = new Type[Size];
Pointer[0] = std::move(Object);
for (size_t i = 1; i < Size; i++)
Pointer[i] = Pointer[0];
}
}
~SmartPointer() { SmartDelete(); }
SmartPointer(SmartPointer &&OtherSP)
{
if (Pointer != OtherSP.Pointer)
{
SmartDelete();
Size = OtherSP.Size;
Pointer = OtherSP.Pointer;
RefCount = OtherSP.RefCount;
OtherSP.Size = nullptr;
OtherSP.Pointer = nullptr;
OtherSP.RefCount = nullptr;
}
}
SmartPointer& operator=(SmartPointer &&OtherSP)
{
if (Pointer != OtherSP.Pointer)
{
SmartDelete();
Size = OtherSP.Size;
Pointer = OtherSP.Pointer;
RefCount = OtherSP.RefCount;
OtherSP.Size = nullptr;
OtherSP.Pointer = nullptr;
OtherSP.RefCount = nullptr;
}
return *this;
}
SmartPointer(const SmartPointer &OtherSP)
{
if (Pointer != OtherSP.Pointer)
{
SmartDelete();
Size = OtherSP.Size;
Pointer = OtherSP.Pointer;
RefCount = OtherSP.RefCount;
RefCount[0]++;
}
else
RefCount[0]++;
}
SmartPointer& operator=(const SmartPointer &OtherSP)
{
if (Pointer != OtherSP.Pointer)
{
SmartDelete();
Size = OtherSP.Size;
Pointer = OtherSP.Pointer;
RefCount = OtherSP.RefCount;
RefCount[0]++;
}
else
RefCount[0]++;
return *this;
}
};
#endif