Help with some C++ printer code...

Windows specific forum
Karbon
PureBasic Expert
PureBasic Expert
Posts: 2010
Joined: Mon Jun 02, 2003 1:42 am
Location: Ashland, KY
Contact:

Help with some C++ printer code...

Post by Karbon »

I apologize for posting all of this but I am trying to understand exactly how it works and use the same method in PB..

I'm trying to batch print PDF files, something that this code will do if compiled but I'm failing to understand how it works..

It looks like it opens Acrobat Reader and uses a print "verb". I thought that was just something you could do to print text file on the command line (issue "print myfile.txt" - but if I do that on the command line here it printes the contents of the PDF, not the rendered PDF file. This code does seem to work, so if anyone can give me a hand porting it to PB and understanding how that ShellExecute is working I'd really really appreciate it!!!

Code: Select all

#include <stdio.h>
#include <windows.h>
#include <winspool.h>

#define TIMEOUT 60

int  multiplier=1;
HANDLE hProcessAdobe=0;
HWND hWndAdobe=0;
BOOL isRunning = FALSE;
BOOL wasRunning = TRUE;
char szAdobe[MAX_PATH];

// Callback for isAdobeRunning
BOOL CALLBACK EnumCallBack(HWND hwnd, LPARAM lParam)
{
	char s[MAX_PATH];
  
	// If window title contains match string
	GetWindowText (hwnd, s, MAX_PATH);
	if (strstr(s, (char *)lParam)) {
		// Set the hWnd
		hWndAdobe=hwnd;
		// Set our flag
		isRunning = TRUE;
		return FALSE;
	}
	else
	{
		isRunning = FALSE;
		return TRUE;
	}

}

// Determine if Acrobat or Reader is running
BOOL isAdobeRunning()
{
	// Search all windows for title starting with szWnd
	EnumWindows (EnumCallBack, (LPARAM)szAdobe);
	return(isRunning);
}

void usage(char *p) 
{
	printf("usage:\t%s [-p printer] [drive:][path]<filename>\n", p);
	printf("Specifies drive, directory, and/or file(s) to print.\n");
	printf("Prints to default printer unless [printer] specified.\n");
}

int pdfprint(char* fname, char* szAdobe, char* szPrinter)
{
	DWORD size=1024;
	SHELLEXECUTEINFO ei;
	DWORD lpExitCode;
	FILE *f;
	int i;
	int printed=0;
	long lSize;

	// Find the file's length
	f = fopen(fname, "r");
	if(f == NULL)
		return 0;

	fseek(f,0,SEEK_END);
	lSize=ftell(f);
	fclose(f);

	// Extend the timeout for each MB of filesize
	multiplier = (int)(lSize / 1000000)+1;

	// Set up the ShellExecute parameters
	ZeroMemory( &ei, sizeof(ei) );
	ei.cbSize = sizeof(ei);
	ei.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS;
	ei.nShow = SW_HIDE;

	// Open Acrobat/Reader if it's not running
	if(!isRunning)
	{
		wasRunning=FALSE;

		ei.lpVerb = "open";
		ei.lpFile = fname;
		ei.lpParameters = NULL;
		
		ShellExecuteEx(&ei);
		hProcessAdobe = ei.hProcess;

		for(i=0;i<TIMEOUT;i++)
		{
			Sleep(1000);
			if(isAdobeRunning())
				break;
		}
	}
	
	// If Printer was specified on command line
	if(strlen(szPrinter)>0) 
	{
		// Set verb and printer name
		ei.lpVerb = "printto";
		ei.lpParameters = szPrinter;
	}
	else
		// Otherwise, use default printer
		ei.lpVerb = "print";

	printf("Printing: '%s'\n", fname);

	// Start the print job
	ei.lpFile = fname;
	ShellExecuteEx (&ei);

	// Wait for print job to complete
	for(i=0;i<(TIMEOUT*multiplier);i++)
	{
		GetExitCodeProcess(ei.hProcess, &lpExitCode);
		if(lpExitCode!=STILL_ACTIVE)
		{
			printed = 1;
			break;
		}

		Sleep(1000);
	}

	// If timeout
	if(printed==0)
		printf("Timeout\n");

	return printed;
}

int main(int argc, char* argv[])
{
	char szPrinter[MAX_PATH];
	char szFile[MAX_PATH];
	char szPath[MAX_PATH];
	char *p;
	int i;
	int s=1;
	int nPrinted=0;	
	HANDLE hPrinter=0;
    WIN32_FIND_DATA find_data;
    HANDLE hFind;
	char *pattern;

	if (argc < 2)
	{
		usage(argv[0]);
		return 0;
	}

	*szPrinter='\0';

	// Check for printer 
	if( (stricmp(argv[1], "-p")==0) || (stricmp(argv[1],"/p")==0) )
	{
		s=3;
		strcpy(szPrinter, argv[2]);
		
		// Make sure printer name is valid
		if(OpenPrinter(szPrinter, &hPrinter, NULL)==0)
		{
			// If not valid, return
			printf("Printer not found: '%s'\n", szPrinter);
			return 0;
		}

		ClosePrinter(hPrinter);

		// Wrap printer name in double quotes to pass as arg
		// in case there are spaces in the name
		sprintf(szPrinter, "\"%s\"", argv[2]);
		printf("Printer: %s\n", szPrinter);

	}

	for(i=s;i<argc;i++)
	{

		// Expand any wildcards
		pattern = argv[i];
		hFind = FindFirstFile(pattern, &find_data);
		if (hFind != INVALID_HANDLE_VALUE)
		{
			do {

				// Construct full path to file
				strcpy(szPath, argv[i]);
				p = strrchr(szPath, '\\');
				if(p == NULL)
					*szPath = '\0';
				else
					*(p+1) = '\0';

				strcat(szPath, find_data.cFileName);

				// Get the path to the executable 
				ZeroMemory (szFile, MAX_PATH);

				// Make sure Adobe Acrobat/Reader is installed	
				FindExecutable(szPath, NULL, szFile);
				if (!szFile[0])
				{
					printf("'%s' not found or Adobe Acrobat or Reader not installed.\n", szPath);
					continue;
				}

				// Make sure it's a PDF file
				p = strrchr(szPath,'.');
				if(p==NULL)
				{
					printf("Not a PDF file: '%s'\n", szPath);
					continue;
				}

				if( (stricmp(p,".pdf")!=0) && (stricmp(p,".fdf")!=0) && (stricmp(p,".xfdf")!=0) )
				{
					printf("Not a PDF file: '%s'\n", szPath);	
					continue;
				}


				// Determine whether system uses Reader or Acrobat for PDF
				if (strstr(szFile, "AcroRd32"))
					strcpy (szAdobe, "Adobe Reader");
				else
					strcpy (szAdobe, "Adobe Acrobat");

				// Set flags if Acrobat/Reader already running
				isAdobeRunning();

				// Tell Acrobat/Reader to print the file
				nPrinted += pdfprint(szPath, szAdobe, szPrinter);

			} while (FindNextFile(hFind, &find_data));
		}

		FindClose(hFind);
	}

	// If Acrobat/Reader wasn't running when we started, terminate it
	if(!wasRunning)
	{
		if(hProcessAdobe)
		{
			// Politely ask Acrobat/Reader to quit
			for(i=0;i<10;i++)
			{
				if(isAdobeRunning())
					SendMessage (hWndAdobe, WM_CLOSE, 0, 0);
				else
					break;

				Sleep(1000);
			}

			// If it's still running, time to get rude
			if(isAdobeRunning())
				TerminateProcess(hProcessAdobe, 0);
		}
	}	

	printf("%d File(s) Printed\n", nPrinted);	
	return(nPrinted);
}
-Mitchell
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
Karbon
PureBasic Expert
PureBasic Expert
Posts: 2010
Joined: Mon Jun 02, 2003 1:42 am
Location: Ashland, KY
Contact:

Post by Karbon »

Actually, the confusion is clearing.. I think I might have it - just have to polish my winapi skills a bit..
-Mitchell
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
fweil
Enthusiast
Enthusiast
Posts: 725
Joined: Thu Apr 22, 2004 5:56 pm
Location: France
Contact:

Post by fweil »

Karbon,

Here is wheere I am now ...

Just it seems that I can't catch the exit code back from Acrobat, and it does not work well as it should ATM.

In the following code you have the possibility to retrieve if Acrobat is running or not, to launch it if it was not running and close it at the end, or just open the document if it was running and let it alive.

Also you have the translation of all parameters and structured information if I did not forget any.

What your posted code does is also to enum a set of files, as far as I understand this, which is not listed in my reply but it should not be hard to add.

Let me know if this helps ...

Code: Select all

#STILL_ACTIVE = $103
Timeout = 60

Global hWndAdobe.l

Procedure SeekForAdobe_Acrobat_Reader_Running(hwnd.l, lParam.l)
    Ret.l = GetWindowTextLength_(hwnd)
    sSave.s = Space(Ret)
    GetWindowText_(hwnd, sSave, Ret + 1)
    If FindString(sSave, "Adobe Reader", 1)
        hWndAdobe = hWnd
    EndIf
    ProcedureReturn #True
EndProcedure

  EnumWindows_(@SeekForAdobe_Acrobat_Reader_Running(), 0)
  
  
  Debug hWndAdobe
  File.s = "REGISTER.PDF"
  FileSize = FileSize(File)
  multiplier = (lSize / 1000000)+1
  Printer.s = "Primo PDF" ; Here a given printer name declared in your station / server

  If OpenPrinter_(@Printer, @hPrinter, #SW_HIDE)
      Debug "Printer found"
    Else
      Debug "Printer not found"
      Printer = "Canon S200" ; Here your default printer
  EndIf
  ClosePrinter_(hPrinter)
  
  If Printer = ""
      Printer = "print"
    Else
      Printer = "printto " + Printer
  EndIf

   ei.SHELLEXECUTEINFO
   ei\cbSize = SizeOf(SHELLEXECUTEINFO)
   ei\fMask = #SEE_MASK_FLAG_DDEWAIT | #SEE_MASK_NOCLOSEPROCESS
   ei\nShow = #SW_HIDE

  ShellExecute_(0, "open", File, Printer, "", 0)

  printed = #FALSE

  For i = 0 To Timeout * multiplier
    Delay(1000)
    If GetExitCodeProcess_(hWndAdobe, @ExitCode)
        If ExitCode <> #STILL_ACTIVE
            Debug "Printed"
            printed = #TRUE
            Break
        EndIf
    EndIf
  Next
  
  If printed = #FALSE
      Debug "Timeout"
  EndIf
  
  If hWndAdobe = 0 ; Adobe was not running at program start
      Debug "Acrobat was not running first : try to close it"
      EnumWindows_(@SeekForAdobe_Acrobat_Reader_Running(), 0)
      SendMessage_(hWndAdobe, #WM_CLOSE, 0, 0)
      Delay(1000)
      EnumWindows_(@SeekForAdobe_Acrobat_Reader_Running(), 0)
      If hWndAdobe <> 0
          Debug "Acrobat was not running first but still runs : try to kill it"
          TerminateProcess_(hWndAdobe, 0)
      EndIf
    Else
      Debug "Adobe was running at start : let it alive"
  EndIf
End
Rgrds
My avatar is a small copy of the 4x1.8m image I created and exposed at 'Le salon international du meuble à Paris' january 2004 in Matt Sindall's 'Shades' designers exhibition. The original laminated print was designed using a 150 dpi printout.
Karbon
PureBasic Expert
PureBasic Expert
Posts: 2010
Joined: Mon Jun 02, 2003 1:42 am
Location: Ashland, KY
Contact:

Post by Karbon »

Wow. Thank you very much!
-Mitchell
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
dell_jockey
Enthusiast
Enthusiast
Posts: 767
Joined: Sat Jan 24, 2004 6:56 pm

Post by dell_jockey »

Mitch,

back in the old days, we used to call the code you posted 'C', not C++ :D
cheers,
dell_jockey
________
http://blog.forex-trading-ideas.com
Karbon
PureBasic Expert
PureBasic Expert
Posts: 2010
Joined: Mon Jun 02, 2003 1:42 am
Location: Ashland, KY
Contact:

Post by Karbon »

Yeah, you're right.. This is the C code, I was looking at some C++ code too and got all confused..

I was more ignorant than usual yesterday - got this all straightened out now :-)
-Mitchell
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
Post Reply