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

标签 c++ winapi memory-leaks subclassing

简介及相关信息:

我有多个 edit control s 在 dialog box需要接受 float 并且是locale意识到。 我已经决定用 subclassing 来实现这个行为。 edit control

实现locale awareness 我决定将结构传递给 SetWindowSubclass (它将保存有关小数点分隔符、负号等的数据...)作为 dwRefData参数。

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

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

问题:

我不知道如何正确地将上述结构传递给 CreateDialogParamSetWindowSubclass .

问题也是正确删除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. 我应该如何传递 MyStructCreateDialogParamSetWindowSubclass ?

  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\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
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 或定制)结构()。通过这种方式,它会反射(reflect)您在所有窗口的结构中所做的更改。一些简短的程序会很好,因为我附近没有任何对话框模板,所以我不能真正给你一个关于如何将它传递给函数的例子。

  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

关于c++ - 设置/删除窗口子类时正确传递/删除数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21951229/

相关文章:

java - 从 JNI 代码检查 Java 类中是否存在可选字段或方法

c# - 如何以编程方式检测代码是否在共享 DLL 或 exe 中运行?

java - 为什么 MxBean 中的堆使用与堆转储中的不同?

ios - 将非 ARC 转换为 ARC

objective-c - Objective-C : How to check for Leaks or Bad Access Errors

c++ - 添加图像C++后发送文本到按钮

c++ - 在一个 VS 项目中使用多个工具集——有风险吗?

c++ - 删除传递给构造函数的对象指针导致错误

c++ - 在另一个应用程序中创建子窗口

c++ - GetCurrentThreadId 返回不同的 threadId