Set HWND on CreateWindow appears to fail - c++

I'm coming from C# and very new at this so please bear with me.
I have a MainWindow class which has some private HWND variables. One for the window itself, and one for each of the controls. I assume I need to keep track of them, or that it will make things easier later?
Anyway, I've got:
class GUIMain
{
private:
HINSTANCE hInstance;
HWND hWnd; // The windows itself
HWND cmdGenerate, cmdQuit; // 2 buttons
I've got a private method called initialise(HWND hWnd) which is called on WM_CREATE and it adds all the controls to the window:
void MainWindow::initialise(HWND hWnd)
{
this->hWnd = hWnd;
cmdGenerate = CreateWindow(TEXT("BUTTON"), TEXT("&Generate..."),
WS_VISIBLE | WS_CHILD,
6, 6, 150, 25,
hWnd, (HMENU)1, 0, 0);
cmdQuit = CreateWindow(TEXT("BUTTON"), TEXT("&Quit"),
WS_VISIBLE | WS_CHILD,
6, 37, 150, 25,
hWnd, (HMENU)2, 0, 0);
}
however this does not seem to put the buttons on the window. In fact, when I debug I can see that it's not even getting past the first line. What is strange is that when I change it to this:
void MainWindow::initialise(HWND hWnd)
{
//this->hWnd = hWnd;
/*cmdGenerate = */CreateWindow(TEXT("BUTTON"), TEXT("&Generate..."),
WS_VISIBLE | WS_CHILD,
6, 6, 150, 25,
hWnd, (HMENU)1, 0, 0);
/*cmdQuit = */CreateWindow(TEXT("BUTTON"), TEXT("&Quit"),
WS_VISIBLE | WS_CHILD,
6, 37, 150, 25,
hWnd, (HMENU)2, 0, 0);
}
it seems to work fine.
Logic would seem to suggest that assigning the private HWND variables the value of the CreateWindow function return is causing problems, but I have done this before and not had a problem?
The only difference between my previous code and this code is that I am now using classes whereas before (while I was learning) I just had everything in WinMain and WndProc.
WinMain: http://pastebin.com/j54vW9gc
Header File: http://pastebin.com/cUs4vVJ6
CPP File: http://pastebin.com/B5KUXTvx

Welcome to world of win32 that was not designed for C++. That's a good first try. I redid classes trying to make a generic framework hundreds of times before saying it was not worth any more time.
Your WinMain() would also be helpful, but a big issue i see is your call to CreateWindowEx() . The last parameter you send is 0. Than when you retrieve it later SetWindowLong(hWnd, GWL_USERDATA, (long) ((LPCREATESTRUCT)lParam)->lpCreateParams); you are saying it is a pointer to class. Did you mean to have:
hWnd = CreateWindowEx(0, TEXT("AS2MainWindow"),
TEXT("AS2"),
WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT,
824, 350,
0, 0,
hInstance, this);
Looking for other problems. See if that helps. If not maybe your post your main()
Added:
CreateWindowEx
HWND WINAPI CreateWindowEx(
__in DWORD dwExStyle,
__in_opt LPCTSTR lpClassName,
__in_opt LPCTSTR lpWindowName,
__in DWORD dwStyle,
__in int x,
__in int y,
__in int nWidth,
__in int nHeight,
__in_opt HWND hWndParent,
__in_opt HMENU hMenu,
__in_opt HINSTANCE hInstance,
__in_opt LPVOID lpParam
);
The last parameter lpParam is optional. So when you had it set to 0 it was not hurting anything. But this is how you "send" something to your WM_NCCREATE or WM_CREATE. It can be any LPVOID. In C you may send a pointer to a struct or anything you want. In this case you want to send it a pointer to the object that is about your window.
To get this parameter in WM_NCCREATE or WM_CREATE you use the below code:
(long) ((LPCREATESTRUCT)lParam)->lpCreateParams);
That is saying cast lParam to a pointer to a CREATESTRUCT. Than get lpCreateParams from it. and cast that to a long. This is slightly different than how i have written this hard to understand piece of code. If you break it into several steps it looks easier. Let me know if you need further explanation here.
Just so you get the full picture below is the definition of CreateStruct. It has more than just lpCreateParams in it. (which you chose to be a pointer to your class).
typedef struct tagCREATESTRUCT {
LPVOID lpCreateParams;
HINSTANCE hInstance;
HMENU hMenu;
HWND hwndParent;
int cy;
int cx;
int y;
int x;
LONG style;
LPCTSTR lpszName;
LPCTSTR lpszClass;
DWORD dwExStyle;
} CREATESTRUCT, *LPCREATESTRUCT;
After understanding all this. Check out ATL thunking. Its the way to go if you want all your code inside classes. I find it better to get away from EVERY piece of code being in a class when it doesn't have to be. Depends on the program I am writing.

Related

WinAPI LoadImage to a button have border but LoadBitmap doesn't

My App is a DLL and i'm injecting it into a (Game) process .
When i use LoadBitmap() and use MAKEINTRESOURCE(IMAGE_RESOURCE_NAME)
Like this :
MyImage = LoadBitmap(hInstance, MAKEINTRESOURCE(IMAGE_RESOURCE_NAME))
SendMessage(MyButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)MyImage);
The Create Button code :
MyButton = CreateWindow("BUTTON", "My Button", WS_VISIBLE | WS_CHILD | BS_BITMAP | BS_FLAT, 17, 18, 110, 30, hwnd, (HMENU)ButtonId, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
LoadBitmap() works when i Inject the DLL into any application but the game.
i think because when i inject the DLL to the game, it won't load from Resources and the image doesn't appear. so i'm not able to use LoadBitmap from Resources. somehow the Resources dosen't go with the DLL data to the Game and the game doesn't find the resources so it can't find the Image.
So alternatively i tried to use LoadImage() from disk file. and that way it worked and the Image appears on the button.
When i Inject it to any application like notepad it appears like this :
(That's what i want it to be like)
But when i inject the DLL to the game, the button appears in a border & 3D Effect :
With a lot of searching i assumed that The Game i'm injecting to doesn't apply Visual Styles to my DLL GUI Window and the Buttons appear in the Classy look, Border & 3D Effect. even BS_FLAT doesn't apply to the button.
Here's the full code I'm using :
#include "stdafx.h"
#include "Process.h"
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <tchar.h>
#include "resource.h"
HINSTANCE hInstance;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc = { 0 };
HWND MainHwnd;
MSG Msg;
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(CreateSolidBrush(RGB(30, 30, 30)));
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.lpszMenuName = NULL;
wc.lpszClassName = "My Application";
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, std::to_string(GetLastError()).c_str(), "RegisterClassEx!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
MainHwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
"Application",
"My Application",
WS_SYSMENU | WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 280,
NULL, NULL, hInstance, NULL);
if (MainHwnd == NULL)
{
MessageBox(NULL, std::to_string(GetLastError()).c_str(), "CreateWindow!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(MainHwnd, nCmdShow);
UpdateWindow(MainHwnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
int MyButtonId = 1000;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE: {
HWND MyButton;
HBITMAP MyImage;
MyButton = CreateWindow("BUTTON", "A Button Text", WS_VISIBLE | WS_CHILD | BS_BITMAP | BS_FLAT, 17, 18, 110, 30, hwnd, (HMENU)MyButtonId, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
///////// --->
// Here I'm using one of these :
// Using LoadImage()
MyImage = (HBITMAP)LoadImage(hInstance, "UI\\myimage.bmp", IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_LOADFROMFILE);
// Using LoadBitmap() | My_Bitmap is an image resource name
MyImage = LoadBitmap(hInstance, MAKEINTRESOURCE(My_Bitmap));
///////// <---
SendMessage(MyButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)MyImage);
break;
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
unsigned long __stdcall Win_Thread(LPVOID Param)
{
WinMain(NULL, NULL, NULL, 1);
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
// Set hInstance to hModule
hInstance = hModule;
CreateThread(0, 0, LPTHREAD_START_ROUTINE(Win_Thread), hModule, 0, 0);
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I think i have two options.
1. try to make the game find my Images from Resources and use LoadBitmap() from Resources. so the button won't be with border & 3d effect.
2. continue using LoadImage() from disk file, and try to hide the border & 3d Effect, e.g Enable Visual Styles for my DLL GUI.
Unfortunately i couldn't do any of those and have no idea how to do that, i'm searching the whole internet but didn't find anything about that.
How could i achieve that, any ideas?
Unfortunately, your pursuit of LoadBitmap is a snipe hunt. Visual Styles are the only thing causing the different appearance. Even if you get the code for using a resource working, you'll still have the wrong appearance unless you enable visual styles.
MSDN has a reference specifically for using Visual Styles in a plugin DLL, when the main application doesn't use them:
Adding Visual Style Support to an Extension, Plug-in, MMC Snap-in or a DLL That Is Brought into a Process
The gist is that you need to use the ISOLATION_AWARE_ENABLED macro and manifest your DLL for visual styles.
You will also need to call InitCommonControlsEx. That's mentioned in several other sections of the above document. For flat buttons, pass the ICC_STANDARD_CLASSES flag (inside the structure).
You do have a couple mistakes in your code, and these might prevent visual styles from properly activating even when you do the manifesting and isolation.
Your DLL should not have a WinMain function. Let there be one function doing all the work that gets called from both WinMain and the DLL thread, instead of having the DLL thread call WinMain. This isn't wrong by itself, just bad style, but it caused the next error which is a bigger problem:
Your hInstance parameter hides the global hInstance variable, resulting in the wrong value for wc.hInstance. If WinMain and DllMain both set the global variable, and then all the rest of the code used the global, you wouldn't be having this problem. But fixing it needs code running in the EXE and not the DLL, which means removing the call from the DLL thread to WinMain.

WinAPI - C++ - Add Hyperlink to Window

I was wondering, how can I add a hyperlink (A link to an online webpage) to my window. Do I use CreateWindow, WM_PAINT, etc? Please give me some advice. Thanks!
Edit:
Here's what i'm doing:
HWND CreateSysLink(HWND hDlg, HINSTANCE hInst, RECT rect){
return CreateWindowEx(0, WC_LINK,
"For more information, click here " \
"or <A ID=\"idInfo\">here</A>.",
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
rect.left, rect.top, rect.right, rect.bottom,
hDlg, NULL, hInst, NULL);
}
I'm copying the hInstance from WinMain parameters to a global variable "globalhInstance" by running globalhInstance = hInstance; in WinMain. I'm also creating a global RECT called globalRect. Then on WM_CREATE, I'm calling GetWindowRect(hwnd, &globalRect); ("hwnd" is a parameter of WndProc). Finally, in a switch statement inside WM_COMMAND i'm calling CreateSysLink(hwnd, globalhInstance, globalRect);. But it just doesn't seem to work.
There's sample code from the MSDN page linked above:
HWND CreateSysLink(HWND hDlg, HINSTANCE hInst, RECT rect)
{
return CreateWindowExW(0, WC_LINK,
L"For more information, click here " \
L"or <A ID=\"idInfo\">here</A>.",
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
rect.left, rect.top, rect.right, rect.bottom,
hDlg, NULL, hInst, NULL);
}

SHAutoComplete on edit control without dialog boxes

I am having trouble using the function SHAutoComplete. It simply does not work correctly when I use it on a edit box whose parent window is not a dialog box.
The auto-complete functionality seems to be working fine, but the rendering of the drop-down list with the possible candidates based on what was typed on the edit box is very messed up. Basically only the borders of the drop-down are shown. The borders are rendered wide enough to fit the possible suggestions, but the suggestions themselves are never drawn. Even the drop-down list background color is wrong. It is as if it was never painted and remains with the original parent window color.
And if the number of suggestions is big enough so the drop-down needs a scroll-bar, the scrollbar also does not get rendered correctly - the arrows do not get drawn.
On both cases, with or without scrollbars, the drop-down list does not accept mouse input, i.e., I cannot click on the items. If I press the "down" key on the keyboard while the drop-down is being shown, it kind of works as expected. After the second or third press the items finally start to appear. But the scrollbar still is does not get rendered correctly.
If instead of registering my own windows class I simply use a dialog with ::DialogBoxParam(), then it all goes as expected. The auto-complete works without any problems at all.
Here is what I am doing. This code will register a window class, create the main window, create an edit box and then call SHAutoComplete on it. It must be linked with Shlwapi.lib
// this code must be linked with Shlwapi.lib
#include <Windows.h>
#include <Shlwapi.h>
// name of the class that will be created for the main window
static const char WindowClassName[] = "SHAutoCompleteDoesNotWorkWithoutADialogWindowClassName";
// the main window procedure
static LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
{
HWND hwndEdit = ::CreateWindowEx(
0,
"EDIT",
0,
WS_CHILD | WS_VISIBLE,
10,
10,
300,
25,
hwnd,
NULL,
NULL,
0);
::SHAutoComplete(hwndEdit, SHACF_DEFAULT);
return 0;
}
case WM_DESTROY:
::PostQuitMessage(1);
return 0;
default:
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
// the app entry point
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
::CoInitialize(NULL);
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(wcex);
wcex.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW ;
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = WindowClassName;
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
ATOM atom = ::RegisterClassEx(&wcex);
HWND hwnd = ::CreateWindowEx(
0,
MAKEINTATOM(atom),
"SHAutoComplete Test",
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
MSG msg;
while(::GetMessage(&msg, hwnd, 0, 0) > 0)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
::UnregisterClass((LPCTSTR)atom, NULL);
::CoUninitialize();
return 0;
}
That code produces the following:
the drop-down when a scroll bar is needed
http://www.abload.de/img/shautocomplete_2i1sk4.jpg
the drop-down after a couple of presses to the "down" key. Notice how the scroll bar still is not rendered correctly.
http://www.abload.de/img/shautocomplete_3efsgw.jpg
Now, when I switch to Dialog Boxes, works like a charm. In the code below, IDD_DIALOG1 is simply an empty dialog box resource, created automatically by the IDE.
Here is the relevant part of the rc file
IDD_DIALOG1 DIALOGEX 0, 0, 316, 185
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
END
And here is the code that uses it
// this code must be linked with Shlwapi.lib
#include <windows.h>
#include <Shlwapi.h>
#include "Resource.h"
BOOL CALLBACK DialogProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
{
HWND hwndEdit = ::CreateWindowEx(
0,
"EDIT",
0,
WS_VISIBLE | WS_CHILD,
0,
0,
300,
20,
hwnd,
NULL,
NULL,
0);
::SHAutoComplete(hwndEdit, SHACF_DEFAULT);
return 1;
}
case WM_CLOSE:
::EndDialog(hwnd, 0);
return 1;
default:
return 0;
}
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
::CoInitialize(NULL);
::DialogBoxParam(
NULL,
MAKEINTRESOURCE(IDD_DIALOG1),
NULL,
DialogProc,
0);
::CoUninitialize();
return 0;
}
Could you please point out where I am going wrong? As far as I can see, other than the creation and destruction of the main window, there seems to be no difference at all between the two of them. Am I missing something on the SHAutoComplete docs that states it can only be used on edit boxes inside dialogs?
You are using a filtered message loop so any messages for the drop down are not being processed. Pass NULL as the second parameter to GetMessage

Win32 GUI and callback to C++ function

So, basically I'm using a code like this one. It's a little simple window where you can only change text inside of an edit box and press a button that will make a callback to a function (DoSomethingCallback(text)).
#include <windows.h>
#define ID_EDIT 1
#define ID_BUTTON 2
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND hwndEdit;
static HWND hwndButton;
static int len;
static TCHAR text[30];
switch(msg)
{
case WM_CREATE:
hwndEdit = CreateWindow(TEXT("Edit"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER,
50, 50, 150, 20, hwnd, (HMENU) ID_EDIT,
NULL, NULL);
hwndButton = CreateWindow(
TEXT("button"), TEXT("Set Title"),
WS_VISIBLE | WS_CHILD,
50, 100, 80, 25,
hwnd, (HMENU) ID_BUTTON, NULL, NULL);
break;
case WM_COMMAND:
if (HIWORD(wParam) == BN_CLICKED) {
SetWindowText(hwnd, "Working...");
GetWindowText(hwndEdit, text, len);
DoSomethingCallback(text);
SetWindowText(hwnd, "Finished");
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{
MSG msg ;
WNDCLASS wc = {0};
wc.lpszClassName = TEXT( "Edit Control" );
wc.hInstance = hInstance ;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc ;
wc.hCursor = LoadCursor(0,IDC_ARROW);
RegisterClass(&wc);
CreateWindow( wc.lpszClassName, TEXT("Edit control"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
220, 220, 280, 200, 0, 0, hInstance, 0);
while( GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
The problem is that when running that Callback the window will appear as "Not responsive" and even laggy if you try to close or press the button. I understand the reason why this might be happening, the callback takes time and the receiving loop isn't there to check the input of the user. I've searched a way to 'fix' this and I couldn't find any. I'm pretty sure it's something dumb, but I have to try and ask.
An obvious way would be making a faster callback. But is there another one like checking the user input inside of a DoSomethingCallback() while, or I have to use multiple threads?
Sorry for the confusing question.
I would go for calling QueueUserWorkItem() to handle it. If your DoSomethingCallback() is too long, there is no way to make your window responsive while DoSomethingCallback() is working since there is only one thread to run the code. Good Luck!
If possible, you can process the message queue at intervals within DoSomethingCallback which will keep the UI responsive. Just run the original message loop i.e. while( GetMessage(... whenever you can but make sure you disable the button so the user does not click a second time... this will lead to recursion.
You can peek at the message queue to convince windows that you are still alive and kicking, by calling PeekMessage() from time to time. This assumes that you can do this in your DoSomethingCallback(), i.e. that the main thread doesn't hang completely. Regard the loop below as pseudo code and use your imagination to transform it to your needs.
void DoSomethingCallback()
{
// Loop that takes a long time
while (true) {
DoSomeStuff();
MSG msg;
PeekMessage(&msg, nil, 0, 0, PM_NOREMOVE);
if (ShouldBreak()) {
break;
}
}
}

How should I create a child window in win32 while programming with C++?

i'm new to C++ as well as for windows programming..
i have created a window using msdn CreateWindow() function
which works correctly..now i would like to create a child window...the parent window should control the child window...
Any helps sample code regarding this .
Thanks in advance
Roughly speaking, in the handler for the parent, where you wish to create the child, you call CreateWindow, passing in the window for the parent as the hwndParent - probably, you also want to set certain styles on the child such as WS_CHILD. Your interaction with the child window then depends on the type of the window you created. Some windows (such as buttons) are designed to work as child windows, so they send a lot of notification messages, so you would set up your parent to listen for those notification messages.
I'd highly recommend having a read through Charles Petzold's "Programming Windows" if you can obtain a copy.
Otherwise, to answer your question, pass the parent window's handle as the parent when you create the child window (using either CreateWindow or CreateWindowEx):
HWND CreateWindowEx
(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent, /// pass the parent window handle here
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
..As 1800 Info has also stated, perhaps also set the WS_CHILD style (more oon Window Styles here). This is just the rudimentary plumbing, really..
Can you be a bit more specific when you say "control the child window..."?
It Is 2018 by now.. doing some retro work on this I found SetParent() to come out handy, to assure a child window remains inside the client region of the parent.. Before SetParent() the child need not be registered as a child. In CreateWindowEx the parent handle can be NULL at first. Style WS_CHILD is not needed, but WS_CLIPSIBLINGS comes out handy, it avoids flickering.
This is my code for creating a child window:
HWND hwnd = CreateWindowExA(0, "WindowOfDLL", ctitle, WS_SIZEBOX | WS_CLIPSIBLINGS, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, hMenu, inj_hModule, NULL);
SetParent(hwnd, hwndparent);
ShowWindow(hwnd, SW_SHOWNORMAL);
I've seen no problems (yet) with threading in Win10. Each of below child windows is created in a DLL which manages the assembly. When a child window is created, the DLL adds a new member to the assembly and launches a thread, which will serve the child window and performs above code in its initialisation.
"could you post more of your code "
#BradB you're right.. our answers are all not very specific, this is old stuff it is difficult to put a complete frame in one post. Read the book RobS suggested I would say... and... take a look at Visual studio and more modern methods to design "child windows", like Winforms, WPF and Universal !
Here is some more of my legacy code, just the preparations, to let it be a CHILD window. The events etc you will have to fill in yourself..
BOOL RegisterDLLWindowClass(LPCWSTR s)
{
WNDCLASSEX wc;
wc.hInstance = NULL; // inj_hModule;
wc.lpszClassName = s;
wc.lpfnWndProc = DLLWindowProc;
wc.style = CS_DBLCLKS;
wc.cbSize = sizeof(WNDCLASSEX);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszMenuName = NULL;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
if (!RegisterClassEx(&wc))
return 0;
}
HMENU CreateDLLWindowMenu()
{
WriteLine("Create menu");
HMENU hMenu;
hMenu = CreateMenu();
HMENU hMenuPopup;
if (hMenu == NULL)
return FALSE;
hMenuPopup = CreatePopupMenu();
AppendMenu(hMenuPopup, MF_STRING, MYMENU_FILTERSOFF, TEXT("Off"));
AppendMenu(hMenuPopup, MF_STRING, MYMENU_CANNY, TEXT("Canny"));
AppendMenu(hMenuPopup, MF_STRING, MYMENU_SOBEL, TEXT("Sobel"));
AppendMenu(hMenuPopup, MF_STRING, MYMENU_THRESHOLD, TEXT("Threshold"));
AppendMenu(hMenuPopup, MF_STRING, MYMENU_DILATE, TEXT("Dilate"));
AppendMenu(hMenuPopup, MF_STRING, MYMENU_HARRIS, TEXT("Harris"));
CheckMenuItem(hMenuPopup, 0, MF_BYPOSITION | MF_CHECKED);
AppendMenuW(hMenu, MF_POPUP, (UINT_PTR)hMenuPopup, TEXT("Filter"));
HMENU hMenuPopup2 = CreatePopupMenu();
AppendMenu(hMenuPopup2, MF_STRING, MYMENU_SAMPLE1, TEXT("Change parameter"));
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hMenuPopup2, TEXT("Test"));
return hMenu;
}
void WINAPI CreateAWindow(PassedToDLL *lpParam, DWORD dwStyle)
{
if (nInstances == 0) RegisterDLLWindowClass((LPCWSTR)L"WindowOfDLL");
HMENU hMenu = CreateDLLWindowMenu();
nInstances++;
CommonInfo[nInstances - 1] = lpParam;
int i = 20 + 4 * (rand() % 10);
lpParam->p = NewPanningStruct();
lpParam->hWndChild = CreateWindowEx(0, L"WindowOfDLL", lpParam->title,
dwStyle,
i, i, 800, 550, lpParam->hWndParent, hMenu, NULL, NULL);
if (wcslen(lpParam->filename) > 0)
{
LoadBitmapFromBMPFileW(lpParam->hWndChild, lpParam->filename, &(lpParam->hBmp),
&(lpParam->hPalette));
}
}