I am totally failing to understand the reason for this. When I compile it and run it, program continually opens printer selection dialogs. I know I can be mistaking something but I though that I can at least prevent this with mutex, why aren't mutexes preventing the multiple threads from executing? PrintDlgEx is a blocking procedure and I confirmed that there are multiple threads (????) running with debugging output. The good code would open print dialog only after previous one was closed.
The typical output of the following code running for 5 or so seconds is:
168
called pdx
called pdx
168
pdx returned
HRES 0
pdx returned
HRES 0
What definitely means that there are multiple threads running BUT I did not see those threads in ProcessExplorer. How can one thread run multiple instances of WndProc
?
So after it was pointed out that mutexes are thread-owned the real question now probably is why there are multiple instances of WndProc
running?
#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();
}