EDIT 2 :
Here's a working example (I hope):
#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;
}
EDIT:
Everything is fine. You are right to delete it on WM_NCDESTROY
, because it wil always be called (WM_CLOSE
sometimes might be skipped). Still you forgot {}
on WM_CLOSE
, so there might be some problems when compiler decides you need problem.
Smart pointers should be used, because it should free memory for you in case something goes wrong, but it's up to you to choose. Also one good thing about them is that it is very easy to adapt to your code, you basically change nothing. One last thing, this "SmartPointer" is my creation and might still be incomplete, the other alternatives are unique_ptr
, shared_ptr
and many more which can be found on internet.
There you go:
#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;
}
If I were you, I would want to pass a pointer (preferably a smart pointer, it can be from STD or custom made) structure trough
SetWindowSubclass()
orCreateDialogParam()
. This way it would reflect on changes you make inside your structure across all of your windows. Some short program would be nice, as I don't have any dialog template nearby so I can't really give you an example on how to pass it to functions.I think that removing sublassing on WM_CLOSE should work just fine.
A little more information would be good.
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