Tuesday, August 26, 2008

Printing PDFs in background from code.

There are different ways to print pdfs from code. You could use the Acrobat COM objects, but that would require Acrobat Professional to be installed on the PC. One fail-safe way to do this would be using DDE to make acrobat do the job. This should work with both Acrobat Reader & Professional.

Below is a code snippet in c++ (MSVC) which does this. For brevity I've omitted the helper functions like GetDefaultPrinterName() and IsValidPrinter(). However if you need those I can post them too.
If you convert this to some other language, pls share it here.

Enjoy & Happy printing ....






STDMETHODIMP PrintPdfFile(BSTR FileName, BSTR PrinterName)
{
_bstr_t FilePath = FileName;
_bstr_t sPrinter = PrinterName;
_bstr_t sDriver = "winspool";
_bstr_t sPort = "";
char buf[256];
char szApp[] = "acroview";
char szTopic[] = "control";
char szCmd1[512];
char szCmd2[] = "[AppExit]";

//DDE Initialization
DWORD idInst=0;
UINT iReturn;

iReturn = DdeInitialize(&idInst, (PFNCALLBACK)DdeCallback,
APPCLASS_STANDARD APPCMD_CLIENTONLY, 0 );
if (iReturn!=DMLERR_NO_ERROR)
{
sprintf(buf, "DDE Initialization Failed: 0x%04x\n", iReturn);
::MessageBox(NULL, buf, "Print Error", MB_OK MB_ICONEXCLAMATION);
Sleep(1500);
return S_OK;
}

//DDE Connect to Server using given AppName and topic.
HSZ hszApp, hszTopic;
HCONV hConv;

hszApp = DdeCreateStringHandle(idInst, szApp, 0);
hszTopic = DdeCreateStringHandle(idInst, szTopic, 0);
hConv = DdeConnect(idInst, hszApp, hszTopic, NULL);
DdeFreeStringHandle(idInst, hszApp);
DdeFreeStringHandle(idInst, hszTopic);
if (hConv == NULL)
{
DWORD dwDDEErr = DdeGetLastError(idInst);
if(dwDDEErr != DMLERR_NO_CONV_ESTABLISHED){
sprintf(buf, "DDE Connection Failed: 0x%04x\n", dwDDEErr );
::MessageBox(NULL, buf, "Print Error", MB_OK MB_ICONEXCLAMATION);
Sleep(1500);
DdeUninitialize(idInst);
return S_OK;
}
else{
//Start DDE Server and wait for it to become idle.
char szPath[MAX_PATH];
HINSTANCE hExe = FindExecutable(FilePath, NULL, szPath);
if((int)hExe <= 32 ){
::MessageBox(NULL, "Acrobat could not be found on this computer. Printing cancelled", "Print Helper", MB_OK);
return S_OK;
}

HINSTANCE hRet = ShellExecute(0, "open", szPath, 0, 0, SW_HIDE);
if ((int)hRet < 33)
{
sprintf(buf, "Unable to Start DDE Server: 0x%04x\n", hRet);
::MessageBox(NULL, buf, "Print Error", MB_OK MB_ICONEXCLAMATION);
Sleep(1500); DdeUninitialize(idInst);
return S_OK;
}
hszApp = DdeCreateStringHandle(idInst, szApp, 0);
hszTopic = DdeCreateStringHandle(idInst, szTopic, 0);
hConv = NULL;
int iCount = 0;
do{
Sleep(5000);
hConv = DdeConnect(idInst, hszApp, hszTopic, NULL);
if(++iCount > 8)
break;
}while(hConv == NULL);

DdeFreeStringHandle(idInst, hszApp);
DdeFreeStringHandle(idInst, hszTopic);
if (hConv == NULL){
sprintf(buf, "DDE Connection Failed: 0x%04x\n", DdeGetLastError(idInst) );
::MessageBox(NULL, buf, "Print Error", MB_OK MB_ICONEXCLAMATION);
Sleep(1500);
DdeUninitialize(idInst);
return S_OK;
}
}
}

//Execute commands/requests specific to the DDE Server.
_bstr_t sDefaultPrinter = "";
if( (sPrinter.length() == 0) (sPrinter == (_bstr_t)(LPSTR)"default") ){

sDefaultPrinter = GetDefaultPrinterName(); // Helper function

if(sDefaultPrinter.length() == 0)
{
sprintf(buf, "Printer [%s]not defined and no default printer found", (LPSTR)sPrinter );
::MessageBox(NULL, buf, "Print Error", MB_OK MB_ICONEXCLAMATION);
return S_OK;
}
else
{
sPrinter = sDefaultPrinter;
}
}
else{
if( !IsValidPrinter(sPrinter, NULL) && !IsValidPrinter(sPrinter, (LPSTR)"") ) // Helper function
{
sDefaultPrinter = GetDefaultPrinterName();

if(sDefaultPrinter.length() == 0)
{
sprintf(buf, "Printer [%s] not defined and no default printer found", (LPSTR) sPrinter );
::MessageBox(NULL, buf, "Print Error", MB_OK MB_ICONEXCLAMATION);
return S_OK;
}
else
{
sprintf(buf, "WARNING : Printer [%s] not defined. \nDefault printer will be used.\n Contact administrator for configuring your printers.", (LPSTR)sPrinter );
::MessageBox(NULL, buf, "Configuration Error", MB_OK MB_ICONEXCLAMATION);
sPrinter = sDefaultPrinter;
}
}
}



sprintf(szCmd1, "[FilePrintToEx(\"%s\", \"%s\", \"%s\", \"%s\")]", (LPSTR)FilePath, (LPSTR) sPrinter, (LPSTR) sDriver, (LPSTR) sPort);

DDEExecute(idInst, hConv, szCmd1);
Sleep(3000);

//DDEExecute(idInst, hConv, szCmd2); // Use this to exit acrobat if needed.
//DDE Disconnect and Uninitialize.
DdeDisconnect(hConv);
DdeUninitialize(idInst);
return S_OK;
}


Thursday, April 24, 2008

Welcome.

I've created my account with blogger.com today. I'll keep sharing my experiences mostly on IT front as and when I come across anything that I feel is worth sharing.
So keep checking back!