I'm trying to get the button press event in c++ win32 using WM_Command
HWND hBtn;
HWND hBtnParent = HWND("UploadVideo");
HWND SelectVideoBTN, UploadBTN;
HWND hWnd;
HINSTANCE hUpload;
WNDCLASSEX wcexUpload;
int nCmdShowUpload = 1;
using namespace std;
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
loader::alert("rrr");
switch (message)
{
case WM_COMMAND:
if (LOWORD(wParam) == WORD(SelectVideoBTN)) {
loader::alert("hello");
}
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
SelectVideoBTN = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Select Video's", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
460, // y position
100, // Button width
25, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
UploadBTN = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Upload", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
390, // x position
460, // y position
100, // Button width
25, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
I've been looking at this example - http://forums.devshed.com/programming-42/create-button-clicked-148407.html - but I can't quite get it to work, it won't even call the CALLBACK WindowProcedure - is there anyone who could help me?
The buttons are present on the window I've created, I create the window by doing -
WNDCLASSEX vidUploader;
vidUploader.cbSize = sizeof(WNDCLASSEX);
vidUploader.style = CS_HREDRAW | CS_VREDRAW;
vidUploader.lpfnWndProc = WndProc;
vidUploader.cbClsExtra = 0;
vidUploader.cbWndExtra = 0;
vidUploader.hInstance = hUpload;
vidUploader.hIcon = LoadIcon(hUpload, MAKEINTRESOURCE(IDI_P2GOVIDEOUPLOADER20));
vidUploader.hCursor = LoadCursor(NULL, IDC_ARROW);
vidUploader.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
vidUploader.lpszMenuName = MAKEINTRESOURCE(IDC_P2GOVIDEOUPLOADER20);
vidUploader.lpszClassName = (LPCWSTR)(L"UploadVideo");
vidUploader.hIconSm = LoadIcon(wcexUpload.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassEx(&vidUploader);
hInst = hUpload; // Store instance handle in our global variable
and then to create the window
hWnd = CreateWindow((LPCWSTR)(L"UploadVideo"), (LPCWSTR)(L"Upload Video's"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hUpload, NULL);
if (!hWnd)
{
MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 Guided Tour"), NULL);
return 1;
}
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd,
nCmdShowUpload);
UpdateWindow(hWnd);
Child windows (i.e. windows with the WS_CHILD window style) are identified by a unique numeric value, often called control ID or window ID. It is passed to the parent when it receives a WM_COMMAND message, for example. You never assigned a control ID to your button controls, though, and the parent window cannot identify them. In case of a child window, the hMenu parameter in the call to CreateWindow is overloaded to carry the unique identifier:
hMenu
For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window.
In other words, your application picks a numeric value to assign to controls. Since the lower IDs are used by the dialog manager already (e.g. IDOK), it is common practice to start assigning control IDs starting at 100 (see Why do dialog editors start assigning control IDs with 100?).
In your WM_COMMAND handler you can then compare LOWORD(wParam) to the identifier assigned to your button controls.
You need to apply the following changes to your code.
// Declare control IDs. This is usually done in a file called Resource.h
#define IDC_SELECT_VIDEO (100)
Change your window creation code:
SelectVideoBTN = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Select Video's", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
460, // y position
100, // Button width
25, // Button height
hWnd, // Parent window
(HMENU)IDC_SELECT_VIDEO, // Assign appropriate control ID
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
Check for the control ID in your WM_COMMAND handler:
switch (message)
{
case WM_COMMAND:
if (LOWORD(wParam) == IDC_SELECT_VIDEO) {
loader::alert("hello");
}
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
If your window procedure isn't called at all, this could mean that you aren't dispatching messages on the calling thread. A GUI thread always needs a message loop. The standard message loop suffices:
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Related
I have some problems with making static controls rounded. I can't understand why SetWindowRgn doesn't work for a static control here. Also I've tried SelectClipRgn and it works. But nevertheless why SetWindowRgn doesn't? The Microsoft documentation states that
The system does not display any portion of a window that lies outside
of the window region.
The control must be rounded and clipped according to the documentation. But it is not. Here's my example of the problem:
#include <windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL)
{
return 0;
}
HRGN hrgnMain = CreateRoundRectRgn(0, 0, 200, 200, 5, 5);
int res = SetWindowRgn(hwnd, hrgnMain, TRUE);
ShowWindow(hwnd, nCmdShow);
HWND hControl = CreateWindow(L"Static", L"hello, world", WS_VISIBLE | WS_CHILD | SS_NOTIFY | SS_LEFTNOWORDWRAP,
20, 20, 40, 40, hwnd, NULL, hInstance, NULL);
HRGN hrgnControl = CreateRoundRectRgn(0, 0, 10, 10, 5, 5);
res = SetWindowRgn(hControl, hrgnControl, TRUE);
ShowWindow(hwnd, nCmdShow);
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Some builtin controls use CS_PARENTDC class style.
CS_PARENTDC sets the clipping region of the child window to that of the parent window. This conflicts with SetWindowRgn which wants to install custom region. Depending how your window is refreshed you could get different combinations of custom region working or not. For example if you resize parent window you can get your control refreshed partially with region set and partially without region.
Parent Display Device Contexts states that:
The system ignores the CS_PARENTDC style if the parent window uses a
private or class device context, if the parent window clips its child
windows, or if the child window clips its child windows or sibling
windows.
But it looks that setting only WS_CLIPCHILDREN for parent windows is not enough. Adding WS_CLIPSIBLINGS or WS_CLIPCHILDREN flags in control styles (even if you have only one child) triggers desired behavior.
HWND hControl = CreateWindow(
L"Static",
L"hello, world",
WS_CLIPSIBLINGS | WS_VISIBLE | WS_CHILD | SS_NOTIFY | SS_LEFTNOWORDWRAP,
20, 20, 40, 40,
hwnd,
NULL,
hInstance,
NULL);
Your code without WS_CLIPSIBLINGS
And with WS_CLIPSIBLINGS
Alternatively the CS_PARENT style could be removed by using GetClassLongPtr and SetClassLongPtr. Because CS_PARENT is used only to reuse clipping region it shouldn't have any other unexpected effects.
SetClassLongPtr(
hControl,
GCL_STYLE,
GetClassLongPtr( hControl, GCL_STYLE ) & ~CS_PARENTDC );
I am making a desktop application, and I got it to display a button. Now what I am trying to do is somehow handle the button press, but I do not know how. Here is my code so far:
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
// Global variables
// The main window class name.
static TCHAR szWindowClass[] = _T("DesktopApp");
// The string that appears in the application's title bar.
static TCHAR szTitle[] = _T("First Desktop Application");
HINSTANCE hInst;
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// Store instance handle in our global variable
hInst = hInstance;
// The parameters to CreateWindow explained:
// szWindowClass: the name of the application
// szTitle: the text that appears in the title bar
// WS_OVERLAPPEDWINDOW: the type of window to create
// CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
// 500, 100: initial size (width, length)
// NULL: the parent of this window
// NULL: this application does not have a menu bar
// hInstance: the first parameter from WinMain
// NULL: not used in this application
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 500,
NULL,
NULL,
hInstance,
NULL
);
HWND hwndButton = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Test2", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
100, // y position
100, // Button width
20, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
NULL);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd,
nCmdShow);
UpdateWindow(hWnd);
// Main message loop:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Test");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// Here your application is laid out.
// For this introduction, we just print out "Hello, Windows desktop!"
// in the top left corner.
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
// End application-specific layout section.
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
It is a Windows Desktop Wizard project on Visual Studio 2019. I just want it to do something simple like display some text on the screen or something when the button is pressed.
This is what the window looks like:
When a BUTTON is clicked, it sends a BN_CLICKED notification message to its parent window. You would simply handle that message in your WndProc(), eg:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
...
case WM_COMMAND:
{
if (HIWORD(wParam) == BN_CLICKED)
{
// LOWORD(wParam) is the button's ID
// HWND(lParam) is the button's HWND
// do something with them as needed...
return 0;
}
break;
}
...
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
This is explained in the BUTTON documentation on MSDN:
Button Messages
Handling Messages from a Button
Notifications from a button are sent as either WM_COMMAND or WM_NOTIFY messages. Information about which message is used can be found on the reference page for each notification.
For more information on how to handle messages, see Control Messages. See also Button Messages.
Notification Messages from Buttons
When the user clicks a button, its state changes, and the button sends notification codes, in the form of WM_COMMAND messages, to its parent window. For example, a push button control sends the BN_CLICKED notification code whenever the user chooses the button. In all cases (except for BCN_HOTITEMCHANGE), the low-order word of the wParam parameter contains the control identifier, the high-order word of wParam contains the notification code, and the lParam parameter contains the control window handle.
I have some problems with making static controls rounded. I can't understand why SetWindowRgn doesn't work for a static control here. Also I've tried SelectClipRgn and it works. But nevertheless why SetWindowRgn doesn't? The Microsoft documentation states that
The system does not display any portion of a window that lies outside
of the window region.
The control must be rounded and clipped according to the documentation. But it is not. Here's my example of the problem:
#include <windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL)
{
return 0;
}
HRGN hrgnMain = CreateRoundRectRgn(0, 0, 200, 200, 5, 5);
int res = SetWindowRgn(hwnd, hrgnMain, TRUE);
ShowWindow(hwnd, nCmdShow);
HWND hControl = CreateWindow(L"Static", L"hello, world", WS_VISIBLE | WS_CHILD | SS_NOTIFY | SS_LEFTNOWORDWRAP,
20, 20, 40, 40, hwnd, NULL, hInstance, NULL);
HRGN hrgnControl = CreateRoundRectRgn(0, 0, 10, 10, 5, 5);
res = SetWindowRgn(hControl, hrgnControl, TRUE);
ShowWindow(hwnd, nCmdShow);
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Some builtin controls use CS_PARENTDC class style.
CS_PARENTDC sets the clipping region of the child window to that of the parent window. This conflicts with SetWindowRgn which wants to install custom region. Depending how your window is refreshed you could get different combinations of custom region working or not. For example if you resize parent window you can get your control refreshed partially with region set and partially without region.
Parent Display Device Contexts states that:
The system ignores the CS_PARENTDC style if the parent window uses a
private or class device context, if the parent window clips its child
windows, or if the child window clips its child windows or sibling
windows.
But it looks that setting only WS_CLIPCHILDREN for parent windows is not enough. Adding WS_CLIPSIBLINGS or WS_CLIPCHILDREN flags in control styles (even if you have only one child) triggers desired behavior.
HWND hControl = CreateWindow(
L"Static",
L"hello, world",
WS_CLIPSIBLINGS | WS_VISIBLE | WS_CHILD | SS_NOTIFY | SS_LEFTNOWORDWRAP,
20, 20, 40, 40,
hwnd,
NULL,
hInstance,
NULL);
Your code without WS_CLIPSIBLINGS
And with WS_CLIPSIBLINGS
Alternatively the CS_PARENT style could be removed by using GetClassLongPtr and SetClassLongPtr. Because CS_PARENT is used only to reuse clipping region it shouldn't have any other unexpected effects.
SetClassLongPtr(
hControl,
GCL_STYLE,
GetClassLongPtr( hControl, GCL_STYLE ) & ~CS_PARENTDC );
I'm trying to change text/background color for the static control. I can do this just fine the following way:
// This is the 'main' window
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance;
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW &~WS_MAXIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CW_USEDEFAULT, 0, 1035, 764, nullptr, nullptr, hInstance, nullptr);
...
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
case WM_CTLCOLORSTATIC:
{
MessageBox( NULL, "CTLCOLORSTATIC called", "", MB_OK );
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(200, 200, 20));
SetBkColor(hdcStatic, RGB(10, 10, 10));
return (INT_PTR)CreateSolidBrush(RGB(30, 30, 30));
}
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
But if I place the window inside another window, the child control text/background color stays default:
// This is the 'parent' window, which resides in the 'main' window
HWND parent = CreateWindowEx
(
0,
_TEXT("STATIC"),
"",
WS_TABSTOP | WS_VISIBLE | BS_SOLID | WS_CLIPCHILDREN,
10, 10, 500, 500,
hwnd,
NULL,
(HINSTANCE)GetWindowLong(hwnd, GWLP_HINSTANCE),
NULL
);
// This is the 'child' window which resides in the 'parent' window
HWND child = CreateWindowEx
(
0,
_TEXT("STATIC"),
"SubItem",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_SOLID,
10, 10, 100, 100,
parent,
NULL,
(HINSTANCE)GetWindowLong(parent, GWLP_HINSTANCE),
NULL
);
To conclude, I have 3 windows:
HWND hwnd; // the 'main' application window (color changes fine)
HWND parent; // the 'parent/container' window which is inside the 'main' window (color changes fine)
HWND child; // the 'child' window which is inside the 'parent' window (color DOES NOT change)
Even though if I put MessageBox inside the WM_CTLCOLORSTATIC, I see it triggering every time the children is drawn, yet the color is not being changed for the child, only for the parent.
As far as I understood I need to handle the message in the main window procedure, but I'm not entirelly clear how to do this. if I compare the (HWND)lParam to the childrens HWND, they're the same (within the default switch case), so I can get the reference in the 'default' section, but I'm not sure how I should handle it from there..
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
case WM_CTLCOLORSTATIC:
{
if ((HWND)lParam == child )
MessageBox( NULL, "Reference Match for CTLCOLORSTATIC", "", MB_OK ); // <-- THIS NEVER TRIGGERS
}
....
default:
if ((HWND)lParam == child )
MessageBox( NULL, "Reference Match for DEFAULT", "", MB_OK ); // <-- THIS DOES TRIGGER
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0;
}
The reason I'm placing one window inside another is so that I can use WS_CLIPCHILDREN property in the parent (becase the child will move/scroll).
WM_CTLCOLORSTATIC is sent by a static control to its parent window, not the top level window.
hwndMain: WM_CTLCOLORSTATIC for hwnd1
|
\--hwnd1: WM_CTLCOLORSTATIC for hwnd2 (You might have to subclass hwnd1)
|
\--hwnd2
You are also leaking brushes, store the brush from CreateSolidBrush somewhere when you create the window and delete it when the window is destroyed.
By reading the MSDN document, I know a function, SetWindowsLongPtr, whose parameter GWLP_WNDPROC can set a new address for the window procedure.
This function can change the text color and background color of the child window, that is to say, it can trigger WM_CTLCOLORSTATIC.
But after testing, I found that it is invalid to the secondary window, that is to say, it can not change the text color of the parent window.
I also consulted a lot of information, and very few documents related to three-tier windows.
So, I think to solve this problem and make all three windows change the color of the text, you may have to rewrite WndProc by yourself, but this is very complicated and involves a lot of things.
Edit: If you just need to change the text color and background color
of the static control, you can customize a control so that you can
handle all its operations.
Hope to help you.
I'm creating a plugin which loads a native window with 2 buttons, on press they should make a message box pop-up but there's no pup-up
Creating a thread for the message loop
//create message thread
class startMessageThreadLoop
{
public:
static DWORD WINAPI StaticThreadStart(void* Param)
{
MessageBox(hWnd, L"StaticThreadStart", L"StaticThreadStart", 0);
startMessageThreadLoop* This = (startMessageThreadLoop*)Param;
return This->ThreadStart();
}
DWORD ThreadStart(void)
{
MessageBox(hWnd, L"ThreadStart", L"ThreadStart", 0);
//create message loop for buttons
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0))
{
//translate and send messages
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
void startMyThread()
{
MessageBox(hWnd, L"startMyThread", L"startMyThread", 0);
DWORD ThreadID;
CreateThread(NULL, 0, StaticThreadStart, (void*) this, 0, &ThreadID);
char szTest[100];
printf(szTest, "%d", ThreadID);
MessageBox(hWnd, LPCWSTR(szTest), L"ThreadIDBaby", 0);
}
};
Starting the thread
startMessageThreadLoop ThreadLoopInstance;
ThreadLoopInstance.startMyThread();
Creating the window
vidUploader.cbSize = sizeof(WNDCLASSEX);
vidUploader.style = CS_HREDRAW | CS_VREDRAW;
vidUploader.lpfnWndProc = WndProc;
vidUploader.cbClsExtra = 0;
vidUploader.cbWndExtra = 0;
vidUploader.hInstance = hUpload;
vidUploader.hIcon = LoadIcon(hUpload, MAKEINTRESOURCE(IDI_P2GOVIDEOUPLOADER20));
vidUploader.hCursor = LoadCursor(NULL, IDC_ARROW);
vidUploader.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
vidUploader.lpszMenuName = MAKEINTRESOURCE(IDC_P2GOVIDEOUPLOADER20);
vidUploader.lpszClassName = (LPCWSTR)(L"UploadVideo");
vidUploader.hIconSm = LoadIcon(wcexUpload.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassEx(&vidUploader);
hInst = hUpload; // Store instance handle in our global variable
hWnd = CreateWindow((LPCWSTR)(L"UploadVideo"), (LPCWSTR)(L"Upload Video's"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hUpload, NULL);
Handle Button
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
if (LOWORD(wParam) == IDC_SELECT_VIDEO) {
MessageBox(hWnd, L"Heeey", L"Hoi", 0);
}
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
Creating buttons & show Window
SelectVideoBTN = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Select Video's", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
460, // y position
100, // Button width
25, // Button height
hWnd, // Parent window
(HMENU)IDC_SELECT_VIDEO, // Assign appropriate control ID
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
UploadBTN = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Upload", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
390, // x position
460, // y position
100, // Button width
25, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
RECT rect = { 0, 0, uploadWNDWidth, uploadWNDHeight };
AdjustWindowRect(&rect, GetWindowLong(hWnd, GWL_STYLE), FALSE);
SetWindowPos(hWnd, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE);
if (!hWnd)
{
MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 Guided Tour"), NULL);
return 1;
}
MSG msg;
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
//nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd,
nCmdShowUpload);
UpdateWindow(hWnd);
I believe that I'm doing everything that I have to in order to get the buttons to work, I have a message loop in a thread, I'm registering & handling the buttons and window, what am I missing?
The message queue of a window is linked to the thread in which the window was created. The message loop must be processed in the same thread.