-3

I've been following this thread for how to use the wndproc function as a member function but I keep getting read access violations (it won't tell me the exact line in my program though, but it's at line 120 of xmemory0 const uintptr_t _Ptr_container = _Ptr_user[-1]; and it says Unhandled exception thrown: read access violation. _Ptr_user was 0x7. I'm probably doing something funky that I shouldn't be doing. Does anyone see anything evident?

Code:

LRESULT CALLBACK wndproc::WndProc(HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam) {
    wndproc* pThis; //wndproc is the class name
    bool checked = true;

    HWND text, button, selection1, selection2;
    //hwnd is parent window

    switch (msg) {

    case WM_CREATE: {
        pThis = static_cast<wndproc*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
        SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<::LONG_PTR>(pThis));
        text = CreateWindow("STATIC", "Please select options from below:", WS_VISIBLE | WS_CHILD, 20, 20, 300, 25, hwnd, NULL, NULL, NULL);
        button = CreateWindow("BUTTON", "Submit", WS_VISIBLE | WS_CHILD | WS_BORDER, 500, 500, 80, 25, hwnd, (HMENU)0, NULL, NULL);
        selection1 = CreateWindow("button", "Scan?", WS_VISIBLE | WS_CHILD | BS_CHECKBOX | WS_OVERLAPPED, 500, 460, 350, 20, hwnd, (HMENU)1001, NULL, NULL);
        CheckDlgButton(hwnd, 1001, BST_CHECKED);
        LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
        vector<string> *strings = reinterpret_cast<vector<string>*>(lpcs->lpCreateParams);
        int j = 40;

        pThis->checkVectorSize = strings->size();
        for (int i = 1; i != strings->size() + 1; i++)
        {
            CreateWindowA("button", (*strings)[i - 1].c_str(),
                WS_VISIBLE | WS_CHILD | BS_CHECKBOX | WS_OVERLAPPED,
                20, j, 185, 35, hwnd, (HMENU)i,
                NULL, NULL);
            CheckDlgButton(hwnd, 0, BST_UNCHECKED);

            j = j + 30;
        }
        //SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<::LONG_PTR>(strings));

        break;
    }
    case WM_COMMAND: {
        pThis = reinterpret_cast<wndproc*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
        int i = wParam;
        if (i == 0) //LOWORD(wParam)
        {
            for (int j = 0; j != pThis->checkVectorSize; j++)
            {
                if (IsDlgButtonChecked(hwnd, j + 1) == true)
                {
                    pThis->check.push_back(j);
                }
            }
            if (IsDlgButtonChecked(hwnd, 1001) == true)
            {
                pThis->scan = true;
            }
            else
            {
                pThis->scan = false;
            }
            PostMessage(hwnd, WM_CLOSE, 0, 0);
            break;
        }
        checked = IsDlgButtonChecked(hwnd, i);
        if (checked) {

            CheckDlgButton(hwnd, i, BST_UNCHECKED);
        }
        else {
            CheckDlgButton(hwnd, i, BST_CHECKED);
        }
        break;
    }
    case WM_DESTROY: {

        PostQuitMessage(0);
        break;
    }
    }
    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

EDIT: Wrapper function:

void wndproc::select(vector<string>& return)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);
    WNDCLASSW wc = { 0 };
    MSG  msg;

    wc.lpszClassName = L"Selection1";
    wc.hInstance = hInstance;
    wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 255));
    wc.lpfnWndProc = WndProc;
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.style = CS_DBLCLKS;

    RegisterClassW(&wc);
    CreateWindowW(wc.lpszClassName, L"Selection",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_SYSMENU,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, &return);

    while (GetMessage(&msg, NULL, 0, 0)) {

        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
Colebacha2
  • 27
  • 1
  • 6
  • 3
    `lpcs->lpCreateParams` point to what ? to `pThis` as you use in begin in `WM_CREATE` or to `vector *strings` ? – RbMm Jul 16 '18 at 13:23
  • Please show the declaration of WndProc (as given in the header file/class declaration). Is it a `static` function? Please provide a [MCVE]. – Werner Henze Jul 16 '18 at 13:25
  • @WernerHenze It is a static function: `static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);` – Colebacha2 Jul 16 '18 at 13:26
  • @RbMm To both? I'm not really sure, I thought it might be a problem that I used that twice – Colebacha2 Jul 16 '18 at 13:27
  • 1
    as notice raymond chen and i - first you use `lpcs->lpCreateParams` as pointer to `wndproc* pThis;` and then you interpret the same pointer as `vector *strings`. how minimum one cast is wrong – RbMm Jul 16 '18 at 13:29
  • so almost 100% this line `vector *strings = reinterpret_cast*>(lpcs->lpCreateParams);` is your direct bug – RbMm Jul 16 '18 at 13:35
  • @RbMm I agree, I'm trying to figure out how to go about the problem. Right now I'm trying the solution posted by Someprogrammerdude – Colebacha2 Jul 16 '18 at 13:38
  • `wndproc::select` is fake code. If you need help, don't post fake code. – IInspectable Jul 16 '18 at 14:05
  • @IInspectable Fake code? The rest of the function was doing simple calculations on values gathered by `wndproc::WndProc`, not relevant at all to the problem. – Colebacha2 Jul 16 '18 at 14:15
  • Yes, fake code. Neither I nor your compiler knows, what `&ret` is. – IInspectable Jul 16 '18 at 14:16
  • I changed it to `return` to make things more clear. I forgot to change it at that line – Colebacha2 Jul 16 '18 at 14:19
  • Even more fake code, now. You cannot use a reserved keyword as a formal parameter. Stop posting fake code. – IInspectable Jul 16 '18 at 14:22
  • @IInspectable lol you're crazy man. Try the code out yourself. That's perfectly legal to do. I know the code works. It's not like I haven't been able to test it. I just want WndProc to be a member function. – Colebacha2 Jul 16 '18 at 14:26
  • If I'm saying, that code does not compile, that code [does not compile](https://wandbox.org/permlink/IIwiGUlt5izyJTgj). You are posting fake code, code you aren't seeing in front of yourself. If you need help, stop doing that. See [ask]. – IInspectable Jul 16 '18 at 14:32
  • It's obviously not going to compile for you because you don't know the member variables (such as `bool scan`) – Colebacha2 Jul 16 '18 at 14:48
  • I'm referring to `wndproc::select`, which doesn't compile for *you* as well. It's fake code. Either show a [mcve], or have this closed off as off-topic. – IInspectable Jul 16 '18 at 14:53
  • You are passing the address of a string vector as the last parameter of `CreateWindowW`. This gets passed to your window procedure as the `lpcs->lpCreateParams`. But you cast it to `wndproc*` which is not what it is. Confusion quickly ensues. If you want to pass two things to your `WM_CREATE` handler, then pass a pointer to a struct. – Raymond Chen Jul 16 '18 at 15:33
  • @RaymondChen Thank you, that's an excellent idea. I created a struct with the two data pieces but createWindowW isn't accepting the struct as the last argument `no suitable conversion function from "x" to "LPVOID" exists` where "x" is the name of the struct. – Colebacha2 Jul 16 '18 at 16:09
  • *"pass a **pointer** to a struct"*. – IInspectable Jul 16 '18 at 16:13
  • There we go, thank you. Do I have to reinterpret the lParam as "x" where x is the name of the struct? – Colebacha2 Jul 16 '18 at 16:22
  • It sounds like you're struggling with more fundamental issues with C++. I would suggest that you hone your skills with simpler programs first. – Raymond Chen Jul 16 '18 at 18:15
  • @RaymondChen That's probably a good idea. I've been trying to learn things from the grassroots up over the past few weeks, I may have dived into this project a bit too soon. Since it's rather important that I get this finished up soon, I'm going to try to work out this problem first though and then continue reading/watching tutorials on youtube. Do you know the proper way to reinterpret the lParam as a struct so I can access the struct's variables? I tried `x data2 = static_cast(reinterpret_cast(lParam)->lpCreateParams);` – Colebacha2 Jul 16 '18 at 19:39

1 Answers1

2

Non-static member functions are not the same as a non-member function. Non-static member function needs an object to be called on, which non-member functions doesn't need.

If you don't use any other (non-static) member functions or member variables, you could make the function static and it should work.


Another possible solution, considering that you're passing "this" along to the function in other ways, is partially the same as the solution mentioned above, together with a second non-static member function.

Something like

class wndproc
{
    ...

    static LRESULT WndProcWrapper(...)
    {
        wndproc *pThis;

        // Set pThis...

        // Call *real* window procedure
        return pThis->WndProc(...);
    }

private:
    LRESULT WndProc(...)
    {
        ...
    }
};

Then make wndproc::WndProcWrapper the window procedure.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • What would be the solution then? Get rid of the pThis? However, WndProc is declared as static: `static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);` – Colebacha2 Jul 16 '18 at 13:23
  • When I set my other function as static (not the WndProc function), I get a compiler error here `wc.lpfnWndProc = WndProc;` saying type LRESULT cannot be assigned to WNDPROC. – Colebacha2 Jul 16 '18 at 13:41
  • Check my edit up top, it shows the wrapper function I'm using. I'm not exactly sure how to make WndProcWrapper "the window procedure". Let me know if I shouldn't use my above function as the wrapper – Colebacha2 Jul 16 '18 at 13:46
  • @Colebacha2 First of all, the function you added is your creation and message loop, not a wrapper function. As for your problem, have youturned `wndproc::WndProc` into a `static` member function? – Some programmer dude Jul 16 '18 at 13:51
  • @Colebacha2 And please try to create a [Minimal, **Complete**, and **Verifiable** Example](http://stackoverflow.com/help/mcve) to show us (but don't just copy-paste your whole code, make sure to not forget the **Minimal** part as well). – Some programmer dude Jul 16 '18 at 13:52
  • My apologies. As per your example, I removed the `static` from `wndproc::WndProc` and instead made the other function static. Would my wrapper function simply call my `select` function? – Colebacha2 Jul 16 '18 at 13:57
  • @Colebacha2 With my solution, you should do `wc.lpfnWndProc = WndProcWrapper;` in your `select` function (which is really badly named since it doesn't really select anything). And I suggest you take some time to study requirements analysis and design, as well as UI and event handling in general. – Some programmer dude Jul 16 '18 at 14:01
  • Unfortunately I can't set `wc.lpfnWndProc = WndProcWrapper;` because `LRESULT (*)() cannot be assigned to a type WNDPROC`. My `select` function actually does do some selecting but I didn't include that part to keep it minimal – Colebacha2 Jul 16 '18 at 14:07
  • @Colebacha2 You of course need a *proper* declaration with the correct arguments! What I shown are just *excerpts* to convey the idea, not exact code that should be copy-pasted! – Some programmer dude Jul 16 '18 at 14:49
  • I'm sorry I'm not all that familiar with winapi.I really don't see anything wrong with the declaration `wc.lpfnWndProc = WndProcWrapper;` I probably won't be using winapi it after this. I'll just stick to Qt because it seems a lot simpler and more feature-filled. – Colebacha2 Jul 16 '18 at 15:12