RegisterClassEx, class conflict

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?
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.
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);
}
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
It works D:
I'm forever grateful xD
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
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)
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?
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;
}
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
m_lpszClassName is a variable in my class, should be different for every object, but let me check the errors.
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
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.
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 :)
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.