FrozenHeart
FrozenHeart

Reputation: 20746

How to get text from DialogBox without global variable usage

Is there any way to get text from a dialog window created by DialogBox other than a global variable?

I mean, this is how I do it at the moment:

wchar_t str[80];
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDOK:
            if (GetDlgItemText(hDlg, IDC_EDIT, str, sizeof(str) / sizeof(*str)) == 0)
                *str = 0;

            EndDialog(hDlg, wParam);
            return (INT_PTR)TRUE;

        case IDCANCEL:
            EndDialog(hDlg, wParam);
            return (INT_PTR)TRUE;
        }
    }
    return (INT_PTR)FALSE;
}

But I wonder if it's possible to get rid of that str global variable?

Upvotes: 0

Views: 190

Answers (2)

Barmak Shemirani
Barmak Shemirani

Reputation: 31599

You can create the dialog box with DialogBoxParam which allows passing initialization data to the dialog.

In WM_INITDIALOG, use SetWindowLongPtr to save this data, then data is accessible in dialog procedure.

Note that with this method you are passing a pointer, therefore sizeof(ptr)/sizeof(*ptr) is not going to return the right allocation size.

Ideally, you may want to declare local variable wchar_t *str = NULL; and pass its address, then allow the dialog to allocate memory. The caller will then be responsible to free the memory.

INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    switch(msg)
    {
    case WM_INITDIALOG:
        SetWindowLongPtr(hwnd, GWL_USERDATA, lparam);
        break;
    case WM_COMMAND:
        switch(LOWORD(wparam))
        {
        case IDOK:
        {
            wchar_t *str = (wchar_t*)GetWindowLongPtr(hwnd, GWL_USERDATA);
            if(str)
                GetDlgItemText(hwnd, IDC_EDIT1, str, 80);
            EndDialog(hwnd, wparam);
            return (INT_PTR)TRUE;
        }
        }
    }
    return (INT_PTR)FALSE;
}

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int)
{
    wchar_t str[80];
    if(IDOK == DialogBoxParam(hinst, MAKEINTRESOURCE(IDD_DIALOG1), 0, 
        DialogProc, (LPARAM)(&str)))
        MessageBox(0, str, 0, 0);
    return 0;
}

Upvotes: 1

Drake Wu
Drake Wu

Reputation: 7170

First, since lParam hasn't been used, can you set lParam = (LPARAM )str to save the address of str ? Second, the return type isINT_PTR, but you only use to return TURE/FALSE, why not return the pointer value instead of TRUE(since the str pointer is always != NULL here):

INT_PTR CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDOK:
            wchar_t* str = new wchar_t[80];
            if (!str)   return (INT_PTR)FALSE;
            if (GetDlgItemText(hDlg, IDC_EDIT, str, 80) == 0)
                *str = 0;

            EndDialog(hDlg, wParam);
            return (INT_PTR)str;

        case IDCANCEL:
            EndDialog(hDlg, wParam);
            return (INT_PTR)TRUE;
        }
    }
    return (INT_PTR)FALSE;
}

Notes that, you'd better allocate memory for str in callback, so that the data won't be overwritten by others. You of course could also use any IPC method, but it will get more complicated.

Upvotes: 0

Related Questions