gpt4 book ai didi

c++ - 自Windows 10 20H1起,多个具有单独线程的窗口停止工作

转载 作者:行者123 更新时间:2023-12-02 10:14:02 26 4
gpt4 key购买 nike

我编写了一个带有主窗口的应用程序,该主窗口将多个子窗口作为子窗口(WS_CHILD)打开-即状态栏,带有按钮的栏和内容部分。到目前为止,主窗口是其他窗口的框架,在背景中起作用。它还正在组织消息等等。内容部分可以由具有其他内容的其他窗口替换。每个窗口都有其自己的线程,这些线程可以使用某种编程语言来填充其内容。为了加快程序的更改,我使用了线程池。因此,如果关闭了一个窗口,则它将线程释放到挂起模式,并且下一个打开的窗口可以再次使用该线程。
到现在为止还挺好。该结构可以正常工作10多年,是几个程序的基础。
现在,随着Windows 10 20H1的最新升级,该程序停止工作。 Windows中的消息队列似乎工作了一段时间,然后几秒钟后在DispatchMessage中挂断。尽管基础线程只是在等待工作,但某些Windows在WndProc中不再收到任何消息。
达到此目的的最快方法是,不使用WS_CHILD,而是使用WS_POPUP打开一个窗口。然后,窗口出现,但它没有收到绘制消息,并且永远不会被填充。这只是框架。此后,该程序不再起作用。
我试图找到从一个线程发送到另一个线程的PostMessage和SendMessage。曾经有一个观点,但是现在已经消除了(过去没有任何问题)。
另一个想法是删除线程池,并为每个新窗口使用一个新线程。但这并没有使任何事情变得更好。唯一有帮助的是保持打开所有创建的窗口。由于程序通常整天甚至几天运行,因此也不是解决方案。我无法在后台保留数百个窗口。
任何想法可能是什么问题?还是有人对Windows 20H1升级有类似的经历?
不幸的是,基于此的程序已在世界各地的许多计算机上运行,​​并且一些客户已经进行了Windows升级。快速的解决方案是回滚升级,但这当然不是永恒的解决方案。
编辑:在这里我有一个示例的问题:
SampleThreadWindow.cpp

// What the program does:
// It creates a main-window in the main-thread and then creates seperate threads
// and a child-window within this thread. Randomly one of the child windows is destroyed.
// If this is the case, the thread for the window is suspended.
// By timer, the thread is resumed and creates a new window.
// To reproduce the problem: Wait until one of the windows had been
// destroyed and then show the about-dialog. Sometimes the
// program hangs when starting the dialog, the other times it stops when
// ending it. In rare cases you have to call the dialog twice.
// This behaviour shows on Windows 10 2004, only, but not on Windows 10 1909.


// Default libraries
#include <windows.h>
#include <time.h>
#include "SampleThreadWindow.h"

// Class-name
#define WC_MAINWINDOW TEXT("MainWindowClass")
#define WC_CHILDWINDOW TEXT("ChildWindowClass")
#define MAIN_TITLE TEXT("Main Window")
#define CHILD_TITLE TEXT("Child Window")

// set TRUE if threads for all child-windows should end
volatile BOOL fEndChildWindowThread = FALSE;

// Reminder for the main window
HWND hWndMain = NULL;

// Instance of the process
HINSTANCE hInstanceMain = NULL;

// Close all windows on exit
BOOL fCloseAll = FALSE;

// the state of a thread in the pool
enum eThreadState
{
Unused, // unused and uninitialized thread
Active, // active thread bound to a window
Suspended, // suspended thread that had been active but the attached window was closed
Finished // finished thread (at program end)
};

// structure for a thread in the thread-pool
struct CThreadPool
{
// Handle of the window associated with the thread
HWND hWindow;

// the state of a thread in the pool
eThreadState tsState;

int iIndex0;
HANDLE hThread;
DWORD dwThreadId;
};

// maximum number of parallel running threads
#define MAX_THREADS 4

// the threadpool
CThreadPool cpThread[MAX_THREADS];


// random result in range 0..1
#define Random1() ((double) rand() / (double)RAND_MAX)


// find a vacant thread in the pool
int FindFreeThread()
{
// search for an unused thread
for (int i = 0; i < MAX_THREADS; i++)
{
if (cpThread[i].tsState != Active)
return (i);
} // for (int i = 0; i < MAX_THREADS; i++)

// no free thread found
return (-1);
} // FindFreeThread


// find a thread by the window associated to the thread
int FindThreadByWindow(HWND hWindow)
{
// search for the thread that created the window
for (int i = 0; i < MAX_THREADS; i++)
{
if (cpThread[i].hWindow == hWindow)
return (i);
} // for (int i = 0; i < MAX_THREADS; i++)

// no thread found for the window
return (-1);
} // FindThreadByWindow


// Check if all threads are finished before program ends
BOOL AllThreadsFinished()
{
// search for an thread that is not finished yet
for (int iThread0 = 0; iThread0 < MAX_THREADS; iThread0++)
{
if ((cpThread[iThread0].tsState != Finished) && (cpThread[iThread0].tsState != Unused))
return (FALSE);
} // for (int iThread0 = 0; iThread0 < MAX_THREADS; iThread0++)

// all threads are finished
return (TRUE);
} // AllThreadsFinished


// WndProc for the about-dialog
INT_PTR CALLBACK AboutDlgProc (HWND hDlg, UINT iMessage, WPARAM wParam,
LPARAM lParam)
{
switch (iMessage)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
EndDialog (hDlg, 0);
break;
}
break;

default:
return (FALSE);
} // switch (iMessage)

return (TRUE);
} // AboutDlgProc


// show the about-dialog
void About (HWND hWndParent)
{
DialogBox (hInstanceMain, MAKEINTRESOURCE(IDD_ABOUTBOX),
(HWND)hWndParent, (DLGPROC)AboutDlgProc);
} // About


// place the window according to the index iIndex0 in the main-window
void PlaceWindow (HWND hWnd, int iIndex0)
{
RECT rcMainArea;
GetClientRect(hWndMain, &rcMainArea);

int x, y;
x = ((rcMainArea.right - rcMainArea.left) / 2) * ((iIndex0 & 0x02) ? 1 : 0);
y = ((rcMainArea.bottom - rcMainArea.top) / 2) * ((iIndex0 & 0x01) ? 1 : 0);

// set size and position ! THIS IS CRITICAL WITH WINDOWS 10 2004
SetWindowPos (hWnd, NULL, x, y, (rcMainArea.right - rcMainArea.left) / 2, (rcMainArea.bottom - rcMainArea.top) / 2, SWP_NOZORDER | SWP_SHOWWINDOW);
} // PlaceWindow


// Processes messages for the child window.
LRESULT CALLBACK WndProcChild(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
SetTimer(hWnd, 1, 50, NULL);
break;


case WM_COMMAND:
{
int wmId = LOWORD(wParam);

// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
About(hWnd);
break;

case IDM_EXIT:
DestroyWindow(hWnd);
break;

default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;


case WM_TIMER:
// randomly remove the window
if (Random1() > 0.98)
DestroyWindow(hWnd);

{
int iThread0;
iThread0 = FindThreadByWindow(hWnd);

SYSTEMTIME stTime;
TCHAR sTime[32];
GetLocalTime(&stTime);
wsprintf(sTime, TEXT("%02d:%02d:%02d - Window %d"), stTime.wHour, stTime.wMinute, stTime.wSecond, iThread0);

HDC hdc = GetDC(hWnd);
TextOut(hdc, 30, 30, sTime, lstrlen(sTime));
ReleaseDC(hWnd, hdc);

// set also in the title for convenience
SetWindowText(hWnd, sTime);
}

// close all windows on exit
if (fCloseAll)
DestroyWindow(hWnd);

break;


case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;


case WM_CLOSE:
DestroyWindow(hWnd);
break;

default:
return DefWindowProc(hWnd, message, wParam, lParam);
}

return 0;
} // WndProcChild



DWORD WINAPI ThreadChildWindow (void* pvThreadPool)
{
// type conversion for easier access
CThreadPool* pThreadPool = (CThreadPool*)pvThreadPool;

// Thread should not be ended so far
fEndChildWindowThread = FALSE;

// initialize Random-Function
srand((unsigned)time(NULL));

// keep in the loop until the external end is set on program end
while (!fEndChildWindowThread)
{
// No window associated? Then create a new one
if (pThreadPool->hWindow == NULL)
{
// create the window - invisible with dummy position and size
pThreadPool->hWindow = CreateWindow(WC_CHILDWINDOW, TEXT("Child Window"), WS_CHILD | WS_BORDER | WS_CAPTION | WS_SYSMENU, 1, 1, 100, 100, hWndMain, NULL, hInstanceMain, NULL);

// the problem does NOT appear with WS_POPUP, but with WS_CHILD only
// pThreadPool->hWindow = CreateWindow(WC_CHILDWINDOW, TEXT("Child Window"), WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU, 1, 1, 100, 100, hWndMain, NULL, hInstanceMain, NULL);

// correct size and position
PlaceWindow(pThreadPool->hWindow, pThreadPool->iIndex0);
} // if (pThreadPool->hWindow == NULL)


MSG msg;

// message loop for this thread and child
if (PeekMessage(&msg, pThreadPool->hWindow, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} // if (PeekMessage(&msg, pThreadPool->hWindow, 0, 0, PM_REMOVE))

// if this is no valid window any more, then suspend the thread behind
if (!IsWindow(pThreadPool->hWindow))
{
// mark the thread as suspended
pThreadPool->tsState = Suspended;

// no more window is associated with this thread
pThreadPool->hWindow = NULL;

// Suspend this thread
SuspendThread(pThreadPool->hThread);
} // if (!IsWindow(pThreadPool->hWindow))
} // while (!fEndChildWindowThread)

// mark the thread as finished (for the end of program)
pThreadPool->tsState = Finished;

// end the thread
ExitThread (TRUE);

// give something back to avoid warnings
return (0);
} // ThreadChildWindow



// create a new thread for a child window (the window is created within the thread)
void CreateThreadWindow()
{
// search for a free thread in the pool
int iThread0 = FindFreeThread();

// No more free thread? Then exit.
if (iThread0 == -1)
return;

// create a new thread (suspended)
if (cpThread[iThread0].tsState == Unused)
cpThread[iThread0].hThread = CreateThread (NULL, 0, ThreadChildWindow, (PVOID)&cpThread[iThread0], CREATE_SUSPENDED, &cpThread[iThread0].dwThreadId);

// mark the thread as active
cpThread[iThread0].tsState = Active;

// resume the thread
ResumeThread(cpThread[iThread0].hThread);
} // CreateThreadWindow


// Processes messages for the main window.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
// remember the main-window
hWndMain = hWnd;

// a timer to create a window in the remote thread
SetTimer (hWnd, 1, 1000, NULL);
}
break;


case WM_TIMER:
// create a Thread that opens a second window as child
CreateThreadWindow();

break;


case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInstanceMain, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, AboutDlgProc);
break;

case IDM_EXIT:
DestroyWindow(hWnd);
break;

default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;


case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// end the paint block
EndPaint(hWnd, &ps);
}
break;


case WM_DESTROY:
// close all child windows
fCloseAll = TRUE;
PostQuitMessage(0);
break;

default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
} // WndProc



// Registers the window class.
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW 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, MAKEINTRESOURCE(IDI_SAMPLETHREADWINDOW));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SAMPLETHREADWINDOW);
wcex.lpszClassName = WC_MAINWINDOW;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

RegisterClassEx(&wcex);

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW; // | CS_OWNDC;
wcex.lpfnWndProc = WndProcChild;
wcex.lpszClassName = WC_CHILDWINDOW;

return RegisterClassEx(&wcex);
} // MyRegisterClass


// main
int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE,
LPSTR /*lpszCmdLine*/, int nCmdShow)
{
// Initialize global strings
hInstanceMain = hInstance;
MyRegisterClass(hInstance);


// clean the threadpool
ZeroMemory (cpThread, sizeof(cpThread));


// set the index for the threads (just for the position of the window associated to the thread)
for (int i = 0; i < MAX_THREADS; i++)
{
cpThread[i].iIndex0 = i;
} // for (int i = 0; i < MAX_THREADS; i++)


// create and show the main window
HWND hWndMain = CreateWindow(WC_MAINWINDOW, MAIN_TITLE, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
ShowWindow(hWndMain, nCmdShow);
UpdateWindow(hWndMain);

MSG msg;

// Main message loop:
while (GetMessage(&msg, hWndMain, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);

// leave the thread if the window is destroyed
if (!IsWindow(hWndMain))
break;
} // while (GetMessage(&msg, nullptr, 0, 0))

// also end the Child-Window-Threads
fEndChildWindowThread = TRUE;

Sleep(100);

// resume all suspended threads so they can finish
for (int iThread0 = 0; iThread0 < MAX_THREADS; iThread0++)
{
if (cpThread[iThread0].tsState == Suspended)
{
// mark the thread as active
cpThread[iThread0].tsState = Active;

// resume the thread
ResumeThread(cpThread[iThread0].hThread);
} // if (cpThread[iThread0].tsState == Suspended)
} // for (iThread0)


// wait for the end
while (!AllThreadsFinished())
{
Sleep(10);
} // while (!AllThreadsFinished())

return (int)msg.wParam;
} // WinMain
SampleThreadWindow.rc
#include "resource.h"
#include "windows.h"

// Menu
IDC_SAMPLETHREADWINDOW MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", IDM_EXIT
END
POPUP "&Help"
BEGIN
MENUITEM "&About ...", IDM_ABOUT
END
END


// Dialog
IDD_ABOUTBOX DIALOGEX 0, 0, 170, 62
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About SampleThreadWindow"
FONT 8, "MS Shell Dlg"
BEGIN
LTEXT "SampleThreadWindow, Version 1.0",IDC_STATIC,42,14,114,8,SS_NOPREFIX
LTEXT "Copyright (C) 2020",IDC_STATIC,42,26,114,8
DEFPUSHBUTTON "OK",IDOK,113,41,50,14,WS_GROUP
END
Resource.h
#define IDS_APP_TITLE           103

#define IDR_MAINFRAME 128
#define IDD_SAMPLETHREADWINDOW_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDM_ABOUT 104
#define IDM_EXIT 105

#define IDI_SAMPLETHREADWINDOW 120
#define IDI_SMALL 121
#define IDC_SAMPLETHREADWINDOW 122

#define IDC_MYICON 2
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif

最佳答案

以下示例对我有效,而无需使用线程池:
MyTestMultiWindow.cpp

// MyTestMultiWindow.cpp : Defines the entry point for the application.
//

#include "framework.h"
#include "MyTestMultiWindow.h"
#include "windows.h"
#include "time.h"

#define MAX_LOADSTRING 100
#define MAX_THREADS 4

#define WC_MAINWINDOW TEXT("MainWindowClass")
#define WC_CHILDWINDOW TEXT("ChildWindowClass")
#define MAIN_TITLE TEXT("Main Window")
#define CHILD_TITLE TEXT("Child Window")
#define Random10() (int)((double) rand() / (double)RAND_MAX * 10)

// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name

HWND hWndMain = NULL;
HANDLE hThreads[MAX_THREADS];
DWORD dwThreadId[MAX_THREADS];
HWND hwndThreads[MAX_THREADS];

DWORD dwCount = 1;

// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

DWORD WINAPI ThreadMainChild(void*);
LRESULT CALLBACK WndProcChild(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: Place code here.

// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_MYTESTMULTIWINDOW, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}

HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MYTESTMULTIWINDOW));

MSG msg;

// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int)msg.wParam;
}



//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW 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, MAKEINTRESOURCE(IDI_MYTESTMULTIWINDOW));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_MYTESTMULTIWINDOW);
wcex.lpszClassName = WC_MAINWINDOW;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

RegisterClassExW(&wcex);


wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProcChild;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYTESTMULTIWINDOW));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_MYTESTMULTIWINDOW);
wcex.lpszClassName = WC_CHILDWINDOW;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassExW(&wcex);
}

//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable

HWND hWnd = CreateWindowW(WC_MAINWINDOW, MAIN_TITLE, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

if (!hWnd)
{
return FALSE;
}

hWndMain = hWnd;

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;
}

//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
int count = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
srand((unsigned)time(NULL));
SetTimer(hWnd, 10, 1000, NULL);
for (int i = 0; i < MAX_THREADS; i++)
{
hThreads[i] = CreateThread(NULL, 0, ThreadMainChild, (LPVOID)i, CREATE_SUSPENDED, &dwThreadId[i]);
}
break;
case WM_TIMER:
if (count > 3)
{
KillTimer(hWnd, 10);
}
else
{
ResumeThread(hThreads[count]);
count++;
}
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;

case WM_SYSCOMMAND:
if (wParam == SC_MINIMIZE)
{
OutputDebugString(L"SC_MINIMIZE triggered.\n");
}
else if (wParam == SC_RESTORE)
{
OutputDebugString(L"SC_RESTORE triggered.\n");
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

DWORD WINAPI ThreadMainChild(void* lpParameter)
{
HWND hWndChild;
DWORD dwChildId = (DWORD)lpParameter;

while (1)
{
hWndChild = CreateWindow(WC_CHILDWINDOW, CHILD_TITLE, WS_CHILD | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
0, 0, 0, 0, hWndMain, (HMENU)(lpParameter), hInst, NULL);

if (!hWndChild)
{
DWORD dwGLE = GetLastError();
return 0;
}
else
{
hwndThreads[dwChildId] = hWndChild;
}

RECT rcMainArea;
GetClientRect(hWndMain, &rcMainArea);

int x, y;
x = ((rcMainArea.right - rcMainArea.left) / 2) * (((DWORD)lpParameter & 0x02) ? 1 : 0);
y = ((rcMainArea.bottom - rcMainArea.top) / 2) * (((DWORD)lpParameter & 0x01) ? 1 : 0);

SetWindowPos(hWndChild, NULL, x, y, (rcMainArea.right - rcMainArea.left) / 2, (rcMainArea.bottom - rcMainArea.top) / 2, SWP_NOZORDER | SWP_SHOWWINDOW);

ShowWindow(hWndChild, SW_SHOW);
UpdateWindow(hWndChild);

MSG msg;

// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(500);
}

return 0;
}

LRESULT CALLBACK WndProcChild(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
SetTimer(hWnd, 11, 1000, NULL);
break;

case WM_TIMER:
if (wParam == 12)
{
}
else if (wParam == 11)
{
if (Random10() >= 8)
{
KillTimer(hWnd, 11);
DestroyWindow(hWnd);
for (int i = 0; i < MAX_THREADS; i++)
{
if (hwndThreads[i] == hWnd)
hwndThreads[i] = NULL;
}
}
else
{
SYSTEMTIME stTime;
TCHAR sTime[32];
GetLocalTime(&stTime);
wsprintf(sTime, TEXT("%02d:%02d:%02d"), stTime.wHour, stTime.wMinute, stTime.wSecond);

HDC hdc = GetDC(hWnd);
TextOut(hdc, 30, 30, sTime, lstrlen(sTime));
ReleaseDC(hWnd, hdc);

SetWindowText(hWnd, sTime);
}
}
break;

case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
for (int i = 0; i < MAX_THREADS; i++)
{
if (hwndThreads[i] == hWnd)
hwndThreads[i] = NULL;
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);

SYSTEMTIME stTime;
TCHAR sTime[32];
GetLocalTime(&stTime);
wsprintf(sTime, TEXT("%02d:%02d:%02d"), stTime.wHour, stTime.wMinute, stTime.wSecond);

TextOut(hdc, 30, 30, sTime, lstrlen(sTime));
ReleaseDC(hWnd, hdc);

SetWindowText(hWnd, sTime);

EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

关于c++ - 自Windows 10 20H1起,多个具有单独线程的窗口停止工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62556289/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com