Page 1 of 1

Virtual Printers Left Behind

Posted: Wed Aug 01, 2018 8:35 am
by steve.thresher
Can you offer any suggestions as to why virtual printers are persisting after a print job has been completed and even after a server has been rebooted?
Multiple PDF-XChange V6 printers.jpg

Re: Virtual Printers Left Behind

Posted: Wed Aug 01, 2018 8:51 am
by Will - Tracker Supp
Hi Steve,

Thanks for the post - Are you using an SDK to create these printers and serve them to users, or have you virtualized the end user printers?

Thanks,

Re: Virtual Printers Left Behind

Posted: Mon Aug 06, 2018 10:11 am
by steve.thresher
Here's a stripped down version of the code we're using:

Code: Select all

void print_pdf()
{
	//Sleep(20000);

	PXC6::IPXCControlExPtr	pFactory6;

	try
	{
		CLSID clsid;
		if (SUCCEEDED(CLSIDFromProgID(L"PXCComLib6.CPXCControlEx",&clsid)))
			pFactory6 = PXC6::IPXCControlExPtr(__uuidof(PXC6::CPXCControlEx));
	}
	catch (_com_error &e)
	{
		CString str;
		str.Format(L"COM exception %d generated when creating PDF-XChange factory",e.Error());
		AfxMessageBox(str);

		return;
	}
	catch (...)
	{
		return;
	}

	PXC6::IPXCPrinterPtr pPrinter6;

	try
	{
		pPrinter6 = pFactory6->Printer[L"",
			L"PDF-XChange Standard V6",

			// Licence details hidden as requested by Tracker support
			L"",
			L""];
	}
	catch (_com_error &e)
	{
		CString str;
		str.Format(L"COM exception %d generated when creating PDF-XChange printer",e.Error());

		AfxMessageBox(str);

		pFactory6.Release();
		return;
	}
	catch (...)
	{
		AfxMessageBox(L"Exception generated when creating PDF-XChange 6 printer");
		pFactory6.Release();
		return;
	}

	pPrinter6->ResetDefaults();
	pPrinter6->Option[L"Save.SaveType"] = L"Save";
	pPrinter6->Option[L"Save.ShowSaveDialog"] = L"No";

	TCHAR filespec[100];
	time_t now_time_t = time(0);
	tm now_tm;
	localtime_s(&now_tm,&now_time_t);
	wcsftime(filespec,sizeof(filespec),TEXT("E:\\TEMP\\PrintPDF-%Y%m%d_%H%M%S"),&now_tm);

	pPrinter6->Option[L"Save.File"] = filespec;// L"E:\\Temp\\PrintPDF.PDF";

	pPrinter6->Option[L"Save.WhenExists"] = L"Overwrite";
	pPrinter6->Option[L"Save.RunApp"] = FALSE;
	pPrinter6->Option[L"Overlay.Enabled"] = FALSE;
	pPrinter6->Option[L"Compression.Graphics"] = TRUE;
	pPrinter6->Option[L"Compression.Text"] = TRUE;
	pPrinter6->Option[L"Fonts.EmbedAll"] = FALSE;
	pPrinter6->Option[L"Saver.ShowProgress"] = FALSE;

	pPrinter6->ApplyOptions(0);

	HDC hDC;

	// Create the HDC for the printer
	if ((hDC = CreateDC(TEXT("WINSPOOL"),pPrinter6->GetName(),NULL,NULL)) != NULL)
	{
		// The StartDoc function starts the print job
		DOCINFO di = {sizeof(DOCINFO)};
		di.lpszDocName = TEXT("Print Job");

		if (StartDoc(hDC,&di) > 0)
		{
			// The StartPage function prepares the printer driver to accept data
			if (StartPage(hDC) > 0)
			{
				TCHAR szString[100] = {};

				wcsftime(szString,sizeof(filespec),TEXT("Printing from a service %d/%m/%Y %H:%M:%S"),&now_tm);
				TextOut(hDC,0,0,szString,lstrlen(szString));

				EndPage(hDC);
			}

			EndDoc(hDC);
		}

		//  Delete the HDC
		DeleteDC(hDC);
	}

	if (pPrinter6)
		pPrinter6.Release();

	if (pFactory6)
		pFactory6.Release();
}

Does this give you what you need to know?

Re: Virtual Printers Left Behind

Posted: Tue Aug 07, 2018 9:15 am
by steve.thresher
Any thoughts on this one?

Re: Virtual Printers Left Behind

Posted: Tue Aug 07, 2018 9:27 am
by Will - Tracker Supp
Hi Steve,

Thanks for posting that and sorry for the response - I can't personally help in anyway here so I've forwarded it to the development team. I believe that the specific Dev needed is in the Canadian office, so it'll be a few hours at least before we hear back.

Thanks,

Re: Virtual Printers Left Behind

Posted: Tue Aug 07, 2018 5:06 pm
by Ivan - Tracker Software
Please add

Code: Select all

pFactory6->RemoveOrphanPrinters(L"", L"PDF-XChange Standard V6");
before call to pPrinter6 = pFactory6->Printer.

HTH

Re: Virtual Printers Left Behind

Posted: Wed Aug 08, 2018 1:46 pm
by steve.thresher
Hi Ivan,

Thanks for the response. I've been back to the source to add the suggested call to find the following commented out code:

// this is in the sample code but if you do this while other sessions are printing, you can remove their printers!
// if (m_pFactory6 != NULL)
// m_pFactory6->RemoveOrphanPrinters(L"", L"");

Our application can be run concurrently by multiple users on a server with remote desktop services. How does the RemoveOrphanPrinters() function determine that a printer is genuinely orphaned and not in use by another user?

Thanks,
Steve.

Re: Virtual Printers Left Behind

Posted: Wed Aug 08, 2018 1:48 pm
by steve.thresher
I've just searched the forums for RemoveOrphanedPrinters and found the following post that was created by my predecessor:

viewtopic.php?f=43&t=26825&p=104023&hil ... rs#p104023

It would appear the last fix to RemoveOrphanedPrinters was years before this issue was reported.

"version 4.0.157 release - 20-02-2009"
"A reported error or bug was fixed Resolved some issues with removing orphaned printers via SDK."

Re: Virtual Printers Left Behind

Posted: Mon Aug 13, 2018 6:05 am
by steve.thresher
Could someone please give me an update on this issue?

Re: Virtual Printers Left Behind

Posted: Thu Aug 16, 2018 9:08 am
by steve.thresher
Could someone please comment on whether this is still a known problem or if a fix has been put in place with newer versions of the product?

Re: Virtual Printers Left Behind

Posted: Thu Aug 16, 2018 9:13 am
by Tracker Supp-Stefan
Hello Steve,

Apologies for the delay here!
I did pass this topic to our devs asking for their comments and advise but have unfortunately not heard back yet. I have now nudged them a second time, and expect a reply within 24 hours.

We will post here as soon as there are any further news.

Regards,
Stefan

Re: Virtual Printers Left Behind

Posted: Thu Aug 16, 2018 5:08 pm
by Ivan - Tracker Software
Printers are left behind because at the moment printer is trying to be removed when the instance of IPXCControlEx released, but if the printer is busy at this moment it cannot be removed and will be left.
We are working on a better mechanism for automatically removing orphaned printers, and hope it will be available in one of the nearest builds of V7.

In the version you have, the best case is to wait while document will be saved. You can do that handling printer's events, or using

Code: Select all

IPXCPrinter::WaitForPrintEvent(event_DocumentSaved, 5000);
(5000 means "wait up to 5000ms").

HTH

Re: Virtual Printers Left Behind

Posted: Thu Aug 23, 2018 3:47 pm
by steve.thresher
I've added the suggested call and it appeared to be working on my development rig but, now the software is being distributed to our customers, we are seeing the function fail intermittently. The function appears to be returning the HRESULT E_ABORT with the stack is as follows:

KERNELBASE.dll!_RaiseException@16() Unknown
00031C.EXE!_com_issue_errorex(HRESULT hr, IUnknown * punk, const _GUID & riid) Line 66 C++
> 00031C.EXE!PXC6::IPXCPrinter6::WaitForPrintEvent(PXC6::PrintEvent event, long timeOut) Line 186 C++
00031C.EXE!view::DoPDFPrint(const char * doc_id, const char * doc_path, ddesign::PAPER_TYPE paper_type, std::vector<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > & printed) Line 564 C++
00031C.EXE!view::print_pdf() Line 414 C++
00031C.EXE!ddesign::InitInstance() Line 283 C++
00031C.EXE!AfxWinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, wchar_t * lpCmdLine, int nCmdShow) Line 37 C++
00031C.EXE!wWinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, wchar_t * lpCmdLine, int nCmdShow) Line 26 C++
00031C.EXE!invoke_main() Line 118 C++
00031C.EXE!__scrt_common_main_seh() Line 253 C++
00031C.EXE!__scrt_common_main() Line 296 C++
00031C.EXE!wWinMainCRTStartup() Line 17 C++
kernel32.dll!@BaseThreadInitThunk@12() Unknown
ntdll.dll!__RtlUserThreadStart() Unknown
ntdll.dll!__RtlUserThreadStart@8() Unknown

Can anyone offer a suggestion as to why this sometimes fails?

Re: Virtual Printers Left Behind

Posted: Thu Aug 23, 2018 9:52 pm
by Ivan - Tracker Software
E_ABORT is returned when during specified wait period the request even had not happened.
Also please note, you have to handle com exceptions if you are using non-raw imports.

Re: Virtual Printers Left Behind

Posted: Fri Aug 24, 2018 8:19 am
by steve.thresher
Could you please expand on the last comment about handling com errors in non-raw imports?

Re: Virtual Printers Left Behind

Posted: Mon Sep 03, 2018 10:07 am
by steve.thresher
Is this how the call should be handled?

Code: Select all

				try
				{
					// This will throw an E_ABORT exception if the event is not received in time
					HRESULT hr = m_pPrinter6->WaitForPrintEvent(PXC6::PrintEvent::event_DocumentSaved,20000);
					if (FAILED(hr))
						LOGWRITE('Y',CXD_STR().catf("Error %dword%,4 while waiting for the document saved event",(TXD_DWORD)hr).c_str());
					else
						LOGWRITE('Y',"Document saved event received");
				}
				catch (_com_error e)
				{
					LOGWRITE('Y',CXD_STR().catf("IPXCPrinter6::WaitForPrintEvent threw an exception. HRESULT %dword%,4 - %str%",e.Error(),(const char *)e.ErrorMessage()).c_str());
				}

Re: Virtual Printers Left Behind

Posted: Mon Sep 03, 2018 5:06 pm
by Ivan - Tracker Software
Thanks, Steve,

Yes, your code is correct, just if (FAILED) case will never work, as any fauilre will trigger an exception. That's because when a non-raw import is used, the compiler makes wraps original interface functions with some error handling code. For example, here is how WaitForPrintEvent looks like in this case:

Code: Select all

inline HRESULT IPXCPrinter::WaitForPrintEvent ( enum PrintEvent event, long timeOut ) {
    HRESULT _hr = raw_WaitForPrintEvent(event, timeOut);
    if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
    return _hr;
}
As you can see, in case of error code returned by the original (raw) function, an exception will be triggered, and you have to handle it like Steve shows above.

Re: Virtual Printers Left Behind

Posted: Wed Sep 05, 2018 2:50 pm
by steve.thresher
I've had to remove the WaitForPrintEvent call as it appears to be causing more problems than it solves. The issues are occurring on a server with remote desktop services where multiple users are creating a virtual printer simultaneously. pdfSaver6 is launched but no PDF file is created. Is it possible for one user to receive the 'documenSaved' event for another user? I'm really stuck on how to move forwards with this issue. Would you be able to provide a debug copy of pdfSaver6.exe and I'll get a process dump to see where the process is stuck?

Re: Virtual Printers Left Behind

Posted: Mon Sep 10, 2018 11:47 am
by steve.thresher
Is there some kind of logging I could switch on that would help to identify why pdfsaver6 sometimes fails to produce a document? I really need to get to the bottom of this problem so some kind of response would be appreciated.

Re: Virtual Printers Left Behind

Posted: Mon Sep 10, 2018 9:48 pm
by Ivan - Tracker Software
Yes, I can provide you a debug version of the pdfSaver6.exe.
This version generates debug outputs that can be collected by sysinternals' (Microsoft) utility Debug View.
Please send me an email (ivan@tracker-software.com) with your system details (I need to know if it is 32- or 64-bit windows), and I will reply with a link to download the debug version and instructions.

Re: Virtual Printers Left Behind

Posted: Wed Sep 12, 2018 8:21 am
by steve.thresher
Hi Ivan,

I've emailed the requested information.

Re: Virtual Printers Left Behind

Posted: Tue Sep 18, 2018 10:49 am
by steve.thresher
I've managed to put together a simple project that shows the hang.

PrintPDF.zip contains a solution that builds PrintPDF,exe and SampleService.exe. All outputs are hard coded to E:\TEMP.

PrintPDF.exe creates a PDF named with PrintPDF-date-time-tickcount.PDF with a single page showing the filename.
SampleService.EXE launches 4 copies of PrintPDF.EXE when started and then stops.

If you build the attached solution you have 2 options to demonstrate the error I'm seeing:

1. Open the debug folder and quickly launch 4 copies of PrintPDF.exe (I use the return key with the EXE highlighted). You will see 1 PDF file is created but the other three PDF's are not created and the processes along with pdfSaver.exe are hung. The only solution is to terminate pdfSaver6.exe.

2. Install and start the sample service which will produce the same state as option 1.

I've attached a DbgView log for one of these runs. Please let me know if you required any further information.

Re: Virtual Printers Left Behind

Posted: Tue Sep 18, 2018 4:40 pm
by Ivan - Tracker Software
I can reproduce the issue, will take a look where the problem is.
But the biggest issue is that it is V6 of the driver, while we do provide now V7

Re: Virtual Printers Left Behind

Posted: Tue Sep 18, 2018 7:33 pm
by Ivan - Tracker Software
I found that the issue is on our WaitForPrintEvent implementation when it is called from multiple processes.
We are going to fix that issue, but the fix will only be included in V7.

So, to avoid that problem, I implemented the printer's events listening in your sample. Please find your modified PrintPDF sample in attachments.
Hope that helps.

P.S. It has been quite a while since I worked with MFC, so please be forgiving for my code :)

Re: Virtual Printers Left Behind

Posted: Tue Sep 18, 2018 10:24 pm
by steve.thresher
Thankyou for the quick turnaround. I'll give it a go.

Re: Virtual Printers Left Behind

Posted: Wed Sep 19, 2018 8:40 am
by Tracker Supp-Stefan
Thanks Steve!

Please do let us know how it goes!

Cheers,
Stefan

Re: Virtual Printers Left Behind

Posted: Mon Sep 24, 2018 10:55 am
by steve.thresher
I've had a go at implementing the suggested alternative to WaitForPrintEvent but I'm still seeing instances where the document saved event is not received causing the manual loop to run until timeout (2 mins) before continuing. I have a DbgView log file which I've attached. I also have a dump of the pdfSaver6.exe process when my process was waiting for the document saved event but it's too large to upload (41MB). Would this help with the diagnosis?

Re: Virtual Printers Left Behind

Posted: Tue Sep 25, 2018 5:15 pm
by Ivan - Tracker Software
Did you trace only OnFileSaved event, or other events too? I'm wondering if OnError event was fired or not.

Re: Virtual Printers Left Behind

Posted: Wed Sep 26, 2018 11:02 am
by steve.thresher
Yes, OnError was traced as well:

IMPLEMENT_DYNAMIC(CPrinterEvents, CCmdTarget)

CPrinterEvents::CPrinterEvents()
{
m_dwConnectionCookie = 0;
m_hEnvent = INVALID_HANDLE_VALUE;
m_pPrinter = nullptr;
//
EnableAutomation();
}

CPrinterEvents::~CPrinterEvents()
{
Detach();
}

void CPrinterEvents::Attach(HANDLE hEvent, PXC6::IPXCPrinter6 *pPrinter)
{
m_hEnvent = hEvent;
m_pPrinter = pPrinter;
AfxConnectionAdvise(pPrinter, PXC6::DIID__IPXCPrinterEvents6, this->GetIDispatch(FALSE), FALSE, &m_dwConnectionCookie);
}

void CPrinterEvents::Detach()
{
if (m_pPrinter)
{
AfxConnectionUnadvise(m_pPrinter, PXC6::DIID__IPXCPrinterEvents6, this->GetIDispatch(FALSE), FALSE, m_dwConnectionCookie);
}
TRACE(L"Detach\n");
}

void CPrinterEvents::OnStartDoc (long JobID, BSTR lpszDocName, BSTR lpszAppName)
{
UNREFERENCED_PARAMETER(JobID);
UNREFERENCED_PARAMETER(lpszDocName);
UNREFERENCED_PARAMETER(lpszAppName);
TRACE(L"OnStartDoc\n");
}

void CPrinterEvents::OnStartPage (long JobID, long nPageNumber)
{
UNREFERENCED_PARAMETER(JobID);
UNREFERENCED_PARAMETER(nPageNumber);
TRACE(L"OnStartPage\n");
}

void CPrinterEvents::OnEndPage (long JobID, long nPageNumber)
{
UNREFERENCED_PARAMETER(JobID);
UNREFERENCED_PARAMETER(nPageNumber);
TRACE(L"OnEndPage\n");
}

void CPrinterEvents::OnEndDoc (long JobID, long nResult)
{
UNREFERENCED_PARAMETER(JobID);
UNREFERENCED_PARAMETER(nResult);
TRACE(L"OnEndDoc\n");
}

void CPrinterEvents::OnFileSaved (long JobID, BSTR lpszFileName)
{
TRACE(L"OnFileSaved\n");
UNREFERENCED_PARAMETER(JobID);
UNREFERENCED_PARAMETER(lpszFileName);
if (m_hEnvent != INVALID_HANDLE_VALUE)
SetEvent(m_hEnvent);
}

void CPrinterEvents::OnFileSent (long JobID, BSTR lpszFileName)
{
TRACE(L"OnFileSent\n");
UNREFERENCED_PARAMETER(JobID);
UNREFERENCED_PARAMETER(lpszFileName);
}

void CPrinterEvents::OnError (long JobID, long dwErrorCode)
{
TRACE(L"OnError\n");
UNREFERENCED_PARAMETER(JobID);
UNREFERENCED_PARAMETER(dwErrorCode);
if (m_hEnvent != INVALID_HANDLE_VALUE)
SetEvent(m_hEnvent);
}

void CPrinterEvents::OnDocSpooled (long JobID, BSTR lpszDocName, BSTR lpszAppName)
{
TRACE(L"OnDocSpooled\n");
UNREFERENCED_PARAMETER(JobID);
UNREFERENCED_PARAMETER(lpszDocName);
UNREFERENCED_PARAMETER(lpszAppName);
}

//////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CPrinterEvents, CCmdTarget)
END_MESSAGE_MAP()

BEGIN_DISPATCH_MAP(CPrinterEvents, CCmdTarget)
DISP_FUNCTION_ID(CPrinterEvents, "OnStartDoc", 1, OnStartDoc, VT_EMPTY, VTS_I4 VTS_BSTR VTS_BSTR)
DISP_FUNCTION_ID(CPrinterEvents, "OnStartPage", 2, OnStartPage, VT_EMPTY, VTS_I4 VTS_I4)
DISP_FUNCTION_ID(CPrinterEvents, "OnEndPage", 3, OnEndPage, VT_EMPTY, VTS_I4 VTS_I4)
DISP_FUNCTION_ID(CPrinterEvents, "OnEndDoc", 4, OnEndDoc, VT_EMPTY, VTS_I4 VTS_I4)
DISP_FUNCTION_ID(CPrinterEvents, "OnFileSaved", 5, OnFileSaved, VT_EMPTY, VTS_I4 VTS_BSTR)
DISP_FUNCTION_ID(CPrinterEvents, "OnFileSent", 6, OnFileSent, VT_EMPTY, VTS_I4 VTS_BSTR)
DISP_FUNCTION_ID(CPrinterEvents, "OnError", 7, OnError, VT_EMPTY, VTS_I4 VTS_I4)
DISP_FUNCTION_ID(CPrinterEvents, "OnDocSpooled", 8, OnDocSpooled, VT_EMPTY, VTS_I4 VTS_BSTR VTS_BSTR)
END_DISPATCH_MAP()

BEGIN_INTERFACE_MAP(CPrinterEvents, CCmdTarget)
INTERFACE_PART(CPrinterEvents, PXC6::DIID__IPXCPrinterEvents6, Dispatch)
END_INTERFACE_MAP()

Re: Virtual Printers Left Behind

Posted: Thu Sep 27, 2018 5:17 pm
by Ivan - Tracker Software
Yes, I remember this code. I just wondered because there is no other trace from it except "OnFileSaved" and "Detach".
Please send me the pdfSaver's dump file. you can upload it on our server. here is KB how to do that https://www.pdf-xchange.com/knowle ... le-service

Re: Virtual Printers Left Behind

Posted: Tue Oct 02, 2018 8:31 am
by steve.thresher
Hi,

The dump file has now been uploaded as: pdfSaver6 - PDF-XChange Drivers API SDK - Virtual Printers Left Behind.zip

Re: Virtual Printers Left Behind

Posted: Tue Oct 02, 2018 7:01 pm
by Ivan - Tracker Software
Thanks for the files. Will work on that issue

Re: Virtual Printers Left Behind

Posted: Thu Oct 11, 2018 7:57 am
by steve.thresher
Have you managed to make any progress on this issue?

Re: Virtual Printers Left Behind

Posted: Mon Oct 15, 2018 7:33 pm
by Ivan - Tracker Software
Not much. I cannot reproduce it locally, and cannot understand yet why it happens on your side.
Can you check if the latest version of the driver (V7.0.327.0) has the same issue in your environment?

Re: Virtual Printers Left Behind

Posted: Wed Oct 17, 2018 10:27 am
by steve.thresher
Are there some test licence details I can use as I only have a licence for V6?

Re: Virtual Printers Left Behind

Posted: Wed Oct 17, 2018 11:24 pm
by Ivan - Tracker Software
If your maintenance still valid, you can use your license for V7.
Otherwise or without a license, you will have a demo labels, but that should not be too critical for testing purposes, I believe.