RegisterClassEx, class conflict

Oct 21, 2014 at 5:31pm
I made a class that loads images from files and displays them on screen, with chosen color used for transparency (something similar to splash screen).

But when there are more than one of those objects they seem to effect one another, I mean they would show wrong images when I change their HBITMAP (only 1 has the correct image, expect in the case when the hbitmap was assigned when creating the window).
I use CreateWindowEx to create a window for each object and store it in their own HWND.
Each window is registered with RegisterClassEx with different className.

Why would they be interfering with each other?
Oct 22, 2014 at 12:34am
If I were to guess I'd say all the window classes you're creating are sharing the same window procedure and you're not taking this into account inside the window procedure.

If this is the case then you need to determine which image object the hwnd belongs to in the window procedure and then act accordingly. You can also simplify things by having all windows share the same window class instead of creating a new class for each window.
Oct 22, 2014 at 6:53pm
knn9, I think you are right, but idk how to fix it.

Here's a part of my code from my class. I believe the problem is in ExtWndProc function, but not sure what is going wrong?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//calling the create window function
m_hwnd = ::CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW, m_lpszClassName,
                              m_lpszClassName, WS_POPUP, x, y,
							  m_dwWidth, m_dwHeight, NULL, NULL, NULL, this);

//the window process function
static LRESULT CALLBACK ExtWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static MiniWinImage * mwi = NULL;
    if(uMsg == WM_CREATE)
    {
        mwi = (MiniWinImage*)((LPCREATESTRUCT)lParam)->lpCreateParams;
    }
    if(mwi)
        return mwi->WindowProc(hwnd, uMsg, wParam, lParam);
    else
        return DefWindowProc (hwnd, uMsg, wParam, lParam);
}
Oct 22, 2014 at 7:59pm
Try this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static LRESULT CALLBACK ExtWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    MiniWinImage * mwi = NULL;

    if(uMsg == WM_CREATE)
    {
        mwi = (MiniWinImage*)((LPCREATESTRUCT)lParam)->lpCreateParams;

        // save pointer in the window itself
        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG)mwi); 
    }
    else
        // get pointer from hwnd
        mwi = (MiniWinImage*)GetWindowLongPtr(hwnd, GWLP_USERDATA);

    if(mwi)
        return mwi->WindowProc(hwnd, uMsg, wParam, lParam);
    else
        return DefWindowProc (hwnd, uMsg, wParam, lParam);
}
Last edited on Oct 22, 2014 at 8:13pm
Oct 22, 2014 at 8:59pm
It works D:
I'm forever grateful xD
Oct 22, 2014 at 9:06pm
Glad I could help. It's a handy trick storing data as part of the window. It works for controls too. Anything with an HWND.
Last edited on Oct 22, 2014 at 9:10pm
Oct 22, 2014 at 9:26pm
I have another classConflicting problem, tho. This is probably very obvious to you, but idk why is it happening.

When registering my class (using RegisterClassEx) as lpszClassName I use a string (part to the image to be shown), and this works fine and all windows have a different className. But since the user could use 1 image for multiple windows only the first one will be shown.
So I made a static int in my class which would be same for all of my objects and I create a string using sprintf(buffer,"%09d",++classCount);, but it's as if they all have the same className. What could be happening?

(I checked and buffer is always different and I use TEXT() to convert buffer to LPCTSTR as well as path to image)
Oct 22, 2014 at 11:08pm
but it's as if they all have the same className


What do you mean by that?

Why don't you create one window class and have all your windows use it?
Oct 23, 2014 at 3:50pm
I meant that only the first one is displayed.

And I don't really know how to do that. Here's the function that I use to create windows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
HWND MiniWinImage::RegAndCreateWindow()
{
    //  =======================================================================
    //  Register the window with ExtWndProc as the window procedure
    //  =======================================================================
    WNDCLASSEX wndclass;
    wndclass.cbSize         = sizeof (wndclass);
    wndclass.style          = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW;
    wndclass.lpfnWndProc    = ExtWndProc;
    wndclass.cbClsExtra     = 0;
    wndclass.cbWndExtra     = DLGWINDOWEXTRA;
    wndclass.hInstance      = ::GetModuleHandle(NULL);
    wndclass.hIcon          = NULL;
    wndclass.hCursor		= ::LoadCursor(NULL, IDC_CROSS);
    wndclass.hbrBackground  = (HBRUSH)::GetStockObject(LTGRAY_BRUSH);
    wndclass.lpszMenuName   = NULL;
    wndclass.lpszClassName  = m_lpszClassName;
    wndclass.hIconSm        = NULL;

    if(!RegisterClassEx (&wndclass))
        return NULL;

    //  =======================================================================
    //  Create the window of the application, passing the this pointer so that
    //  ExtWndProc can use that for message forwarding
    //  =======================================================================
    DWORD nScrWidth  = ::GetSystemMetrics(SM_CXFULLSCREEN);
    DWORD nScrHeight = ::GetSystemMetrics(SM_CYFULLSCREEN);

    int x = (nScrWidth  - m_dwWidth) / 2;
    int y = (nScrHeight - m_dwHeight) / 2;
    m_hwnd = ::CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW, m_lpszClassName,
                              m_lpszClassName, WS_POPUP, x, y,
				m_dwWidth, m_dwHeight, NULL, NULL, NULL, this);

    //  =======================================================================
    //  Dimwiay the window
    //  =======================================================================
    if(m_hwnd)
    {
        MakeTransparent();
        ShowWindow   (m_hwnd, SW_SHOW) ;
        UpdateWindow (m_hwnd);
    }
    return m_hwnd;
}
Oct 24, 2014 at 9:52am
I believe RegisterClassEx() returns 0 if the window class name is already registered. That could explain why only one window is appearing. That is assuming m_lpszClassName is the same for all windows.

A simple solution would be to use a static bool:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
HWND MiniWinImage::RegAndCreateWindow()
{
    //  =======================================================================
    //  Register the window with ExtWndProc as the window procedure
    //  =======================================================================

    static bool isregistered = false;

    if (!isregistered)
    {
        WNDCLASSEX wndclass;
        wndclass.cbSize         = sizeof (wndclass);
        wndclass.style          = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW;
        wndclass.lpfnWndProc    = ExtWndProc;
        wndclass.cbClsExtra     = 0;
        wndclass.cbWndExtra     = DLGWINDOWEXTRA;
        wndclass.hInstance      = ::GetModuleHandle(NULL);
        wndclass.hIcon          = NULL;
        wndclass.hCursor		= ::LoadCursor(NULL, IDC_CROSS);
        wndclass.hbrBackground  = (HBRUSH)::GetStockObject(LTGRAY_BRUSH);
        wndclass.lpszMenuName   = NULL;
        wndclass.lpszClassName  = m_lpszClassName;
        wndclass.hIconSm        = NULL;

        if(!RegisterClassEx (&wndclass))
            return NULL;

        isregistered = true;
    }

    ....
}


Alternatively you could call GetLastError() after RegisterClassEx(). It should return something like ERROR_ALREADY_EXISTS if the class is already registered.
Last edited on Oct 24, 2014 at 9:53am
Oct 24, 2014 at 10:19am
m_lpszClassName is a variable in my class, should be different for every object, but let me check the errors.
Oct 24, 2014 at 10:30am
You are right I am getting that error, but I can't seem to figure out why?

Here's how I assign value to m_lpszClassName :

1
2
3
4
m_lpszClassName = lpszFileName; //works fine

sprintf(buffer,"Class%09d",++classCount); //classCount is a static class variable initialised to 0
m_lpszClassName = TEXT(buffer); //gives error: already exists :/ 


Why is this only happening in the second case?
Last edited on Oct 24, 2014 at 10:31am
Oct 24, 2014 at 11:24am
I couldn't really say. Have you tried to output the class name in RegAndCreateWindow() to confirm whether it's actually changing?

The way you fill out the WNDCLASSEX structure doesn't seem... "clean" to me. Try initializing it to zero, as in WNDCLASSEX wndclass = {0};, and then fill the members you actually need.

I'm curious about this as well: wndclass.cbWndExtra = DLGWINDOWEXTRA;. According to MSDN this is necessary for dialog box resources whose class information is pulled from a resource file.

And to reiterate, there's no need to be registering a new window class for every window in this case. It's obviously causing unnecessary complications already.
Oct 25, 2014 at 5:00pm
I did check it when I created it and it was working fine, but I decided to check it in regandcreate function and something random poped up. I googled LPCTSTR and damn.. turns out it is a cstring pointer, not an object as I thought, whe didn't they said so right away :/ Anyway, I saved the string somewhere so it works now..

As for WNDCLASSEX I copied it from somewhere and only changed what I needed. DLGWINDOWEXTRA was in there already, not really sure what it's for, could you explain?
And I thought WNDCLASSEX was a class and the default constructor would initialise everything to null, but now that I figured out it's a structure "={0}" would make seance for initialization.

And I'll try to make it so I only register class once, I don't think it should be too difficult (again, I copied this function, so I didn't realize it's not the best solution for my problem)

Thanks for helping man :)
Oct 26, 2014 at 9:45am
zoran404 wrote:
As for WNDCLASSEX I copied it from somewhere and only changed what I needed. DLGWINDOWEXTRA was in there already, not really sure what it's for, could you explain?


Honestly I don't know. The MSDN page for the WNDCLASSEX structure says this:

If an application uses WNDCLASSEX to register a dialog box created by using the CLASS directive in the resource file, it must set this member to DLGWINDOWEXTRA.

I always let Visual Studio make the resource files for me, and I wasn't even aware that you could register a window class for a dialog box. I've always used the DialogBox() or CreateDialog() function to invoke a dialog box.


Topic archived. No new replies allowed.