我完全没理解这个的原因。当我编译并运行它时,程序会不断打开打印机选择对话框。我知道我可能会误解一些东西,但我尽管我至少可以通过互斥锁防止这种情况,为什么互斥锁不会阻止多线程执行? PrintDlgEx是一个阻塞程序,我确认有多个线程(????)运行调试输出。好的代码只有在前一个关闭之后才会打开打印对话框。
以下代码运行5秒左右的典型输出是:
168
called pdx
called pdx
168
pdx returned
HRES 0
pdx returned
HRES 0
肯定意味着有多个线程正在运行但是我没有在ProcessExplorer中看到这些线程。一个线程如何运行WndProc
的多个实例?
因此,在指出互斥锁是线程拥有的之后,现在真正的问题可能就是为什么有WndProc
多个实例在运行?
#include <windows.h>
#include <stdio.h>
HANDLE ghMutex=NULL;
enum hotkey {
bESC
};
static LRESULT CALLBACK WndProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam) // second message parameter
{
static enum class mode {init,signal,noise,search} Mode;
static HRESULT hResult;
static PRINTDLGEX pdx;
static LPPRINTPAGERANGE pPageRanges = NULL;
static enum class status {printing, stopped} Status;
static int jobId;
static HANDLE printerHd;
JOB_INFO_1A *JobInfo1;
static bool inited;
if(ghMutex==NULL){
ghMutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
printf("%d\n",(int)ghMutex);
if(ghMutex==NULL) return 0;
}
if(WaitForSingleObject(
ghMutex,
INFINITE)!=WAIT_OBJECT_0) return 0;
switch (uMsg)
{
case WM_TIMER:
{
if(!inited) {
pdx = PRINTDLGEX{0};
pPageRanges = NULL;
// Allocate an array of PRINTPAGERANGE structures.
pPageRanges = (LPPRINTPAGERANGE) GlobalAlloc(GPTR, 10 * sizeof(PRINTPAGERANGE));
if (!pPageRanges)
break;
// Initialize the PRINTDLGEX structure.
pdx.lStructSize = sizeof(PRINTDLGEX);
pdx.hwndOwner = GetDesktopWindow();
pdx.hDevMode = NULL;
pdx.hDevNames = NULL;
pdx.hDC = NULL;
pdx.Flags = PD_RETURNDC | PD_COLLATE | PD_NOPAGENUMS;
pdx.Flags2 = 0;
pdx.ExclusionFlags = 0;
pdx.nPageRanges = 0;
pdx.nMaxPageRanges = 10;
pdx.lpPageRanges = pPageRanges;
pdx.nMinPage = 1;
pdx.nMaxPage = 1000;
pdx.nCopies = 1;
pdx.hInstance = 0;
pdx.lpPrintTemplateName = NULL;
pdx.lpCallback = NULL;
pdx.nPropertyPages = 0;
pdx.lphPropertyPages = NULL;
pdx.nStartPage = START_PAGE_GENERAL;
pdx.dwResultAction = 0;
// Invoke the Print property sheet.
printf("called pdx\n");
hResult = PrintDlgEx(&pdx);
printf("pdx returned\n");
inited=1;
}
printf("HRES %d\n",(int)hResult);
if ((hResult == S_OK) && pdx.dwResultAction == PD_RESULT_PRINT)
{
// User clicked the Print button, so use the DC and other information returned in the
// PRINTDLGEX structure to print the document.
int ph=GetDeviceCaps(pdx.hDC,PHYSICALHEIGHT);
int pw=GetDeviceCaps(pdx.hDC,PHYSICALWIDTH);
int offX=GetDeviceCaps(pdx.hDC,PHYSICALOFFSETX);
int offY=GetDeviceCaps(pdx.hDC,PHYSICALOFFSETY);
int dimX=pw-2*offX;
int dimY=ph-2*offY;
DOCINFOA nao{sizeof(DOCINFOA),"test",NULL,NULL,0};
jobId=StartDoc(pdx.hDC,&nao);
StartPage(pdx.hDC);
////////////nothing
EndPage(pdx.hDC);
EndDoc(pdx.hDC);
}
} break;
case WM_CREATE:
// Initialize the window.
{
inited=false;
SetTimer(hwnd,1,2500,NULL);
}
break;
case WM_DESTROY:
// Clean up window-specific data objects.
{
CloseHandle(ghMutex);
ghMutex=NULL;
}
SendMessage(hwnd,WM_USER+1,0,0);
break;
case WM_HOTKEY:
{
DestroyWindow(hwnd);
}
break;
//
// Process other messages.
//
default:
ReleaseMutex(ghMutex); return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
ReleaseMutex(ghMutex);return 0;
}
void testPrinter()
{
HWND hwnd;
{
WNDCLASSA wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "";
wc.lpszClassName = "PinTest";
if (!RegisterClass(&wc))
return; //cannot register window class
hwnd=CreateWindowEx(0,"PinTest","topmost print testing window without borders and title bar",WS_VISIBLE|WS_BORDER,0,0,300,300,0,0,0,0);
RegisterHotKey(hwnd,bESC,0,VK_ESCAPE);
}
MSG recent;
BOOL result;
while((result=GetMessage(&recent,hwnd,0,0))&&result!=-1) { //bool can be -1 in MS world
if(recent.message==WM_USER+1) break;
TranslateMessage(&recent);
DispatchMessage(&recent);
}
return;
}
int main(){
testPrinter();
}