How to pass a shared_ptr using win32 API PostMessage() to another thread? - shared-ptr

Win32 API:PostMessage
BOOL WINAPI PostMessage(
_In_opt_ HWND hWnd,
_In_ UINT Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
I have a shared_ptr created in a worker thread, and I need to pass it to the UI thread. How can I do it?
I have defined my own message WM_USER_THREAD, hWnd is the main window.

Related

c thread in windows HWND error

Below is my code.it getting a Handle mistake.
`
int main(){
HWND hMainWin;
DWORD threadID;
//Create thread down
HANDLE threadHandle = CreateThread(NULL,
0,
threadFunction,
(LPVOID)hMainWin,
0,
&threadID);
}
DWORD WINAPI threadFunction(LPVOID param){ //my thread function
HANDLE hwnd = (HANDLE)param;
for(int i=0;i<5;i++)
{
printf("hello");
}
return 0;
}
Error:
You have a variable HWND hMainWin; that is not initialized and you are using that (uninitialized) variable as argument #4 in a call to CreateThread(). Since the variable is uninitialized its value is undefined which is the reason for the error message you are getting.
From the looks of it your code seems to be a console application. As such you don't have a window or a handle to it (the HWND) thus you are having trouble initializing the hMainWin.
It looks like that parameter is just a dummy variable (not really used in your thread function) so you might as well (just for a "quick fix") initialize it with a NULL (or a 0)

64-bit Windows: longjmp lands in a wrong place

There's a problem when I use longjmp in a 32-bit application on Windows 64-bit (Windows 7). Instead of returning to a point of the last setjmp() call, it lands after the last DispatchMessage() call. Here's the code example, which works fine if compiled by a 64-bit compiler, and fails with a 32-bit version.
Are there any ideas for a workaround? Microsoft seems to be silent on a tangential question here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/b63a573f-007e-43a3-877c-b06280aa8bcc/0x80000026-application-error-when-exiting-after-using-longjmp-on-windows8-x64?forum=windowscompatibility
// Compile as: cl a.c user32.lib kernel32.lib
#include <windows.h>
#include <setjmp.h>
#include <stdio.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
jmp_buf jump_buffer;
int flag = 0;
int main()
{
WNDCLASS wc = {0, };
ATOM atom = 0;
HWND wnd;
MSG msg;
int ret;
wc.lpfnWndProc = &WndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = "ExitWindows() handler";
atom = RegisterClass(&wc);
wnd = CreateWindow(wc.lpszClassName, wc.lpszClassName,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, wc.hInstance, NULL);
ret = setjmp(jump_buffer);
switch ( ret ) {
case 0:
ShowWindow(wnd,SW_SHOW);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
if ( flag ) {
printf("not ok\n");
break;
}
}
break;
case 1:
printf("ok\n");
break;
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_PAINT:
flag = 1;
longjmp(jump_buffer, 1);
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
Using longjmp in WndProc is unsafe because of the nature of a window procedure:
if can be called through a SendMessage function, in which case it in not called with the same context (stack) that what you used for the setjmp. In that case, I think that anything could happen... - Ok WM_PAINT in normally posted and not sent so that should not apply here, even if IMHO it is the main reason to not do that
the system could prepare some internal structs for you before calling the window procedure (in DispatchMessage) and expect to be able to clean them after WndProc returns. Using a longjmp would break that.
The Windows API on WindowProc functions says: The return value is the result of the message processing and depends on the message sent.
My understanding of it is that a window procedure is supposed to return and to never call longjmp of exit. It is not explicit in Windows documentation, but I would not dare use a window procedure that would not return.
The correct way to exit correctly from a message loop is by posting a WM_QUIT message (Use the PostQuitMessage function to exit a message loop). It makes the GetMessage functions returns 0 and allows the system to cleanup the message loop that was installed at first call to GetMessage.

MessageBox won't work when handling WM_DESTROY event from DialogBox

While elaborating an answer for another question (by myself), I've come up with the idea of using a MessageBox to report the result of my dialog box. It is a WinAPI modal dialog box created with the DialogBox() function.
However, I noticed that handling WM_DESTROY in the dialog's procedure function will prevent the message box from appearing. I would like to understand the mechanics behind that.
Here's the full code, and the referred message box is at the end, right before return 0:
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <string.h>
#include "resource.h"
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
// uncomment these and the MessageBox won't show up
//case WM_DESTROY:
//PostQuitMessage(0);
//break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
if (MessageBoxW(hwnd, L"Close the window?", L"Confirm", MB_OKCANCEL) == IDOK)
EndDialog(hwnd, (INT_PTR)wParam);
break;
case IDCANCEL:
MessageBoxW(hwnd, L"Goodbye.", L"Close", MB_OK);
EndDialog(hwnd, (INT_PTR)TRUE);
break;
}
}
return (INT_PTR)FALSE;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
INT_PTR ret = DialogBoxW(NULL, MAKEINTRESOURCEW(IDD_DIALOG1), NULL, DlgProc);
wchar_t retTxt[10];
if (ret == IDOK)
wcscpy(retTxt, L"Alright!");
else
wcscpy(retTxt, L"Error");
MessageBoxW(NULL, retTxt, L"Result", MB_OK);
return 0;
}
When you use DialogBox rather than DialogBoxParam, the dialog runs its own message loop that handles WM_DESTROY internally. When you post the WM_QUIT message from your dialog procedure you are generating an additional message* that the dialog box won't use, so it remains in your thread's message queue once the DialogBox function returns.
You then call MessageBox, which runs its own message loop. This immediately pulls the WM_QUIT out of the queue, exits the loop and returns before the dialog is even displayed.
(* actually it's not a "real" message - an internal flag is set that indicates quit has been posted - but the effect is the same on the subsequent message loop)

Using CreateProcess, can't get CREATE_NO_WINDOW to supress the console

I want to kick off a process (we'll use notepad for simplicity) without the console window popping up.
I'm sure I've missed something very simple, here is my most simplified test case:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
void _tmain( int argc, TCHAR *argv[] )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
"notepad", // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NO_WINDOW, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
You are creating a new process(notepad.exe) from a parent process(your console application), and let parent process wait for child process to finish. The console window is the main window of your parent process. You can hide and restore is as show below.
// Notice how hiding the console window causes it to disappear from
// the Windows task bar. If you only want to make it minimize, use
// SW_MINIMIZE instead of SW_HIDE.
void _tmain(int argc, TCHAR *argv[])
{
ShowWindow( GetConsoleWindow(), SW_HIDE );
// create a new process and wait for it to finish
ShowWindow( GetConsoleWindow(), SW_RESTORE );
}
Change the application subsystem from Console to Windows. In VS2008, this is under linker properties, System.
Then change your main function to:
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
and change the code to return an int.
This is how you change the application subsystem from Console to Windows using MinGW, add these linker flags:
-Wl,-subsystem,windows

Handle to window handle

I've tried using the "grab all of the process IDs enumerated by the desktop" method, however that doesn't work.
Is there a way to convert a handle to a window handle? -or-
Is there a way to take a process ID and find out all of the child windows spawned by the process?
I don't want to use FindWindow due to multiple process issues.
You could call EnumWindows() to iterate over all the top-level windows on the screen, then use GetWindowThreadProcessId() to find out which ones belong to your process.
For example, something like:
BOOL CALLBACK ForEachTopLevelWindow(HWND hwnd, LPARAM lp)
{
DWORD processId;
GetWindowThreadProcessId(hwnd, &processId);
if (processId == (DWORD) lp) {
// `hwnd` belongs to the target process.
}
return TRUE;
}
VOID LookupProcessWindows(DWORD processId)
{
EnumWindows(ForEachTopLevelWindow, (LPARAM) processId);
}

Resources