Click here to Skip to main content
15,887,135 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I've got a DLL that gets loaded by a parent executable.

The DLL needs to create a window.

I'd like the DLL window to use the primary message loop in the executable, but the windowproc in the DLL.

I'm just curious if this even a thing I can do, or if I have to create my own thread and pump messages on it. I feel like I used to know the answer but win32 has been ages for me.

I am getting an hourglass/unresponsive window when it pops, as if my WindowProc isn't being fired.

I can't get a debugger on it right now for reasons.

It's stumping me as to why. I thought this was working before.

What I have tried:

C++
WNDCLASSW wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandleW(NULL);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"spi_screen";
RegisterClassW(&wc);

and
C++
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    if (uMsg == WM_CLOSE) {
        SetEvent(quit_event);
    }
    return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
Posted
Comments
[no name] 23-Sep-23 16:30pm    
Change your GetModuleHandleW(NULL) to the DLL hInstance.

Update with Dev Blog:
https://devblogs.microsoft.com/oldnewthing/20050418-59/?p=35873
honey the codewitch 23-Sep-23 16:31pm    
I'll try that. I'm using GCC and don't currently have a DllMain to grab the HINSTANCE off of but I can sort that out, thanks.
[no name] 23-Sep-23 16:50pm    
All HINSTANCE are simply the base address of the module.
https://www.codeproject.com/Messages/2896177/Re-AfxGetInstanceHandle-Crash-in-MFC-Extension-dll
[no name] 23-Sep-23 17:15pm    
I see a bug in that function from 14 years ago. If you use it make sure to set GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT so it doesn't increment the module handle reference count.
honey the codewitch 23-Sep-23 18:37pm    
Yeah, I'm aware of what an hinstance is. But I did not know about that bug, thanks. I tried replacing GetModuleHandle(NULL) with the hinstance from DllMain and it did not like that at all. It wouldn't even register the window class i think (hard to tell because i can't debug and logging is limited)

When a Win32 DLL is loaded into an application using the LoadLibrary function, the DLL is loaded into the application's memory and becomes part of the application's address space. This means that the DLL and the original executable (exe) are in the same module address space, which in this context means the same process space or context. When you have successfully initialized a window class, it will specify which WinProc to use. Here it is assumed (according to MS doc) that the module that registered the class is also the module that creates the window.
I could call CreateWindow from the loaded DLL without any problems and use the message loop of the exe. In my test program it did not matter whether the window class was registered in the exe or in the dll.
However, it would probably be necessary that the windows and the DLL run in the same thread, since Windows messages can be processed normally only within the same thread. A short test program with LoadLibrary and Createwindow confirms that the module handle returned by Loadlibrary is the same as in the first parameter of WinMain The function in the DLL opens another window without problems. The message loop at the end of WinMain in the exe is used for all windows, but only one is active at a time.

// Edit:
Here is the code I used in the DLL. It runs as expected and also the call to GetModuleHandle(NULL) is taken directly from the questioner.
C++
bool     created_wndcls = false;
WNDPROC  MainWndProc = NULL;

extern "C" DLLPROC1_API void SetMainWinProc(WNDPROC  proc)
{
    MainWndProc = proc;
}

extern "C" DLLPROC1_API HWND CreateWindowInDll() 
{
    if (!created_wndcls) {
        WNDCLASSW wc;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = MainWndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = GetModuleHandle(NULL);
        wc.hbrBackground = NULL;
        wc.lpszMenuName = NULL;
        wc.hIcon = NULL;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.lpszClassName = _T("spi_screen");
        RegisterClassW(&wc);
        created_wndcls = true;
    }

    HWND hwnd = CreateWindow(_T("spi_screen"), _T("Window from DLL"), WS_OVERLAPPEDWINDOW, 200, 200, 400, 300, NULL, NULL, GetModuleHandle(NULL), NULL);

    if (hwnd == NULL) {
        return NULL;
    }

    ShowWindow(hwnd, SW_SHOWDEFAULT);
    UpdateWindow(hwnd);

    return hwnd;
}


//Edit2:
I tested with Visual-Studio, if the gcc behaves the same way I can't say.
 
Share this answer
 
v6
Comments
honey the codewitch 23-Sep-23 19:13pm    
I'll go ahead and accept this, as it all jibes with what I was expecting. Seems my problem lies elsewhere.
[no name] 23-Sep-23 19:50pm    
Could you translate it into English for me? :)
honey the codewitch 23-Sep-23 21:12pm    
He's saying their shouldn't be any problem since everything shares the same process address space, as long as it's all operating on the same thread (which it is).

All of that is what I expect. I was looking for things I *wasn't* expecting at this point.

I still can't find the problem, but I don't think it's the above. I just don't know what it is.
[no name] 23-Sep-23 22:05pm    
You could always call SetWindowLongPtr with GWLP_WNDPROC and replace the windowproc after it's created. Until you figure it out.
honey the codewitch 23-Sep-23 22:06pm    
I was able to get it to start logging, and it has called my WndProc, so that's not the issue.

The other thing that's weird, and that I don't understand at all, is that window is the ONLY one that's hourglassing and going non-responsive. This despite the fact that all windows are on the same thread/message pump. How is that even possible? They are cooperatively tasked within the same thread.
I was creating the window on a different thread without realizing it. Once I fixed that the problem went away.
 
Share this answer
 
Comments
Richard MacCutchan 24-Sep-23 10:49am    
:thumbsup:
[no name] 29-Sep-23 22:07pm    
Since you ended up using the DLL instance handle:

https://github.com/codewitch-honey-crisis/winduino/blob/main/winduino_hardware/spi_screen/spi_screen.cpp#L154

Could you share your thoughts on making the change?
honey the codewitch 30-Sep-23 0:30am    
It didn't seem to make any difference, as long as I was consistent (always using the dllmain hinstance vs always using the result of GetModuleHandle(NULL) ). They were clearly different handles, but windows didn't seem to care. I imagine it makes a difference if you were loading resources though, because if you used the GetModuleHandle(NULL) it would try to load them from the exe instead of the DLL. Since I'm not using resources it made - as far as I can tell, no discernable difference.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900