Thread: How can I set windows printer configuration in c?

  1. #1
    Registered User
    Join Date
    Feb 2011
    Posts
    96

    How can I set windows printer configuration in c?

    I'm writing an app. in c that can print.
    This is a php 7 extension for printing in windows.
    Here is another php extension link for the newer php 7.

    I can't get certain options set which are in the DEVMODE structure.
    I set the values in the in the DEVMODE object but my Brother HL-1850 printer completely ignores them.
    I've verified the constants that are used and they are all correct.
    I checked the value of the option settings and they are all correct.
    I tried calling the VALID_OPTIONS option (code below) after setting all the options but it made no difference.
    It uses Windows functions: DocumentProperties and SetPrinter.

    The printer will print the text but always in portrait without regard to copies, paper source, orientation or papersize.

    How can I make the printer set the options to the values I want?

    Copies = 2
    Paper Source = "MP Tray"
    Paper Size = DMPAPER_ENV_10
    Orientation = DMORIENT_LANDSCAPE

    Code:
    PHP_FUNCTION(printer_set_option)
    {
    	DWORD dwNeeded =0;
    	PRINTER_DEFAULTS pd;
    	zval *arg1, *arg2, *arg3;
    	printer *resource;
    	char sRtn[250] = "Empty";
    
    	if( zend_get_parameters_ex(3, &arg1, &arg2, &arg3) == FAILURE ) {
    		WRONG_PARAM_COUNT;
    	}
    
    	if ((resource = (printer *)zend_fetch_resource_ex(arg1, "Printer Handle", le_printer)) == NULL) 
    	{
    		RETURN_FALSE;
    	}
    	convert_to_long_ex(arg2);
    
    	memset(&pd,0,sizeof(pd));
    	pd.DesiredAccess = PRINTER_ALL_ACCESS;
    	SetLastError(0);
    
    	switch(Z_LVAL_P(arg2)) {
    		case COPIES:
    			convert_to_long_ex(arg3);
    			resource->pi2->pDevMode->dmCopies=(short)Z_LVAL_P(arg3);
    			resource->dmModifiedFields|=DM_COPIES;
    			//sprintf(sRtn, "Copies: %lu", resource->pi2->pDevMode->dmCopies);
    			break;
    
    		case MODE:
    			convert_to_string_ex(arg3);
    			if (resource->info.lpszDatatype) {
    				efree((char *)resource->info.lpszDatatype);
    			}
    			resource->info.lpszDatatype		= estrdup(Z_STRVAL_P(arg3));
    			resource->info.cbSize			= sizeof(resource->info);
    			break;
    
    		case TITLE:
    			convert_to_string_ex(arg3);
    			if (resource->info.lpszDocName) {
    				efree((char *)resource->info.lpszDocName);
    			}
    			resource->info.lpszDocName		= estrdup(Z_STRVAL_P(arg3));
    			resource->info.cbSize			= sizeof(resource->info);
    			break;
    
    		case OUTPUT_FILE:
    			convert_to_string_ex(arg3);
    			if (resource->info.lpszOutput) {
    				efree((char *)resource->info.lpszOutput);
    			}
    			resource->info.lpszOutput		= estrdup(Z_STRVAL_P(arg3));
    			resource->info.cbSize			= sizeof(resource->info);
    			break;
    
    		case ORIENTATION:
    			convert_to_long_ex(arg3);
    			resource->pi2->pDevMode->dmOrientation=(short)Z_LVAL_P(arg3);
    			resource->dmModifiedFields|=DM_ORIENTATION;
    			//sprintf(sRtn, "Orientation: %lu", resource->pi2->pDevMode->dmOrientation);    
    			break;
    
    		case YRESOLUTION:
    			convert_to_long_ex(arg3);
    			resource->pi2->pDevMode->dmYResolution = (short)Z_LVAL_P(arg3);
    			resource->dmModifiedFields|=DM_YRESOLUTION;
    			break;
    		
    		case XRESOLUTION:
    			convert_to_long_ex(arg3);
    			resource->pi2->pDevMode->dmPrintQuality = (short)Z_LVAL_P(arg3);
    			resource->dmModifiedFields|=DM_PRINTQUALITY;
    			break;
    			
    		case PAPER_BIN:
    			convert_to_long_ex(arg3);
    			resource->pi2->pDevMode->dmDefaultSource = (short)Z_LVAL_P(arg3);
    			resource->dmModifiedFields|=DM_DEFAULTSOURCE;
    			//sprintf(sRtn, "Paper Bin: %lu", resource->pi2->pDevMode->dmDefaultSource);
    			break;
    
    		case PAPER_SIZE:
    			convert_to_long_ex(arg3);
    			resource->pi2->pDevMode->dmPaperSize = (short)Z_LVAL_P(arg3);
    			resource->dmModifiedFields|=DM_PAPERSIZE;
    			//sprintf(sRtn, "Paper Size: %lu", resource->pi2->pDevMode->dmPaperSize);
    			break;
    
    		case PAPER_LENGTH:
    			convert_to_long_ex(arg3);
    			resource->pi2->pDevMode->dmPaperLength = (short)(Z_LVAL_P(arg3) * 10);
    			resource->dmModifiedFields|=DM_PAPERLENGTH;
    			break;
    
    		case PAPER_WIDTH:
    			convert_to_long_ex(arg3);
    			resource->pi2->pDevMode->dmPaperWidth	= (short)(Z_LVAL_P(arg3) * 10);
    			resource->dmModifiedFields |=  DM_PAPERWIDTH;
    			break;
    
    		case SCALE:
    			convert_to_long_ex(arg3);
    			resource->pi2->pDevMode->dmScale		= (short)Z_LVAL_P(arg3);
    			resource->dmModifiedFields |= DM_SCALE;
    			break;
    
    		case BG_COLOR:
    			convert_to_string_ex(arg3);
    			SetBkColor(resource->dc, hex_to_rgb(Z_STRVAL_P(arg3)));
    			break;
    
    		case TEXT_COLOR:
    			convert_to_string_ex(arg3);
    			SetTextColor(resource->dc, hex_to_rgb(Z_STRVAL_P(arg3)));
    			break;
    
    		case TEXT_ALIGN:
    			convert_to_string_ex(arg3);
    			SetTextAlign(resource->dc, Z_LVAL_P(arg3));
    			break;
    			
    		case VALID_OPTIONS:
    			resource->pi2->pSecurityDescriptor=NULL;
    			resource->pi2->pDevMode->dmFields=resource->dmModifiedFields;
    			resource->dmModifiedFields=0;
    			DocumentProperties(NULL,resource->handle,resource->name,resource->pi2->pDevMode,resource->pi2->pDevMode,DM_IN_BUFFER | DM_OUT_BUFFER);
    			SetPrinter(resource->handle,2,(LPBYTE)resource->pi2,0);
    			SendMessageTimeout(HWND_BROADCAST,WM_DEVMODECHANGE,0L,(LPARAM)(LPCSTR)resource->name,SMTO_NORMAL,1000,NULL);
    			break;
    		default:
    			php_error_docref(NULL TSRMLS_CC, E_WARNING, "printer.set.option: unknown option");
    			RETURN_FALSE;
    	}
    
    	RETURN_TRUE;
    }
    Code:
    PHP_FUNCTION(printer_open)
    {
    	zval *arg1;
    	printer *resource;
    
    	int argc = ZEND_NUM_ARGS();
    
    	resource = (printer *)emalloc(sizeof(printer));
    	resource->dmModifiedFields = 0;
    
    	if( argc == 1 && zend_get_parameters_ex(1, &arg1) != FAILURE ) {
    		convert_to_string_ex(arg1);
    		resource->name = Z_STRVAL_P(arg1);
    	}
    	else if( argc == 0 ) {
    		resource->name = PRINTER7_G(default_printer);
    	}
    	else {
    		WRONG_PARAM_COUNT;
    	}
    
    	if (OpenPrinter(resource->name, &resource->handle, NULL) != 0) {
    		resource->pi2 = (PRINTER_INFO_2 *)emalloc(sizeof(PRINTER_INFO_2));
    		resource->pi2->pDevMode = (DEVMODE *)emalloc(DocumentProperties(NULL, NULL, resource->name, NULL, NULL, 0));
    		if (DocumentProperties(NULL, resource->handle, resource->name, resource->pi2->pDevMode, NULL, DM_OUT_BUFFER) == IDOK) {
    			resource->info.lpszDocName	= estrdup("PHP generated Document");
    			resource->info.lpszOutput	= NULL;
    			resource->info.lpszDatatype = estrdup("TEXT");
    			resource->info.fwType		= 0;
    			resource->info.cbSize		= sizeof(resource->info);
    			resource->dc = CreateDC(NULL, resource->name, NULL, resource->pi2->pDevMode);
    			RETURN_RES(zend_register_resource(resource, le_printer));
    		}
    	}
    	else {
    		php_error_docref(NULL TSRMLS_CC, E_WARNING, "couldn't connect to the printer [%s]", resource->name);
    		RETURN_FALSE;
    	}
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    DocumentProperties specifies pDeviceName as an LPTSTR
    > _In_ LPTSTR pDeviceName,

    Because in some places, you treat it as a narrow string
    SendMessageTimeout(HWND_BROADCAST,WM_DEVMODECHANGE ,0L,(LPARAM)(LPCSTR)resource->name,SMTO_NORMAL,1000,NULL);

    And others, you treat it as a potentially wide string
    resource->pi2->pDevMode = (DEVMODE *)emalloc(DocumentProperties(NULL, NULL, resource->name, NULL, NULL, 0));

    It's worth checking:
    - are you compiling in UNICODE mode (it's the default for several recent versions of visual studio)
    - is PHP passing the right thing?
    You may need appropriate wide/narrow string conversions in a place or two. Simply throwing in casts the make the compiler STFU is NOT the way to do it.


    > resource = (printer *)emalloc(sizeof(printer));
    Does emalloc guarantee to initialise the allocated block to all zeros?

    Because if it doesn't, this kind of code breaks.
    > if (resource->info.lpszOutput)

    You could be trying to free a garbage pointer, and that will just ruin your day.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Feb 2011
    Posts
    96
    I've tried a few more things with no success.
    I changed the DocumentProperties function in VALID_OPTIONS so that it ran twice, once to input the DEVMODE object and again to retrieve it.
    I added a return string to show the values. They are set to the printer's defaults, not the values that I set.
    I tried it again using the original DocumentProperties call with both input & output for DEVMODE.
    Again, no success.
    It returned the printer's default values, not the values I set.

    Any help would be greatly appreciated.

    Code:
    case VALID_OPTIONS:
    	resource->pi2->pSecurityDescriptor=NULL;
    	resource->pi2->pDevMode->dmFields=resource->dmModifiedFields;
    	resource->dmModifiedFields=0;
    	DocumentProperties(NULL,resource->handle,resource->name,resource->pi2->pDevMode,resource->pi2->pDevMode,DM_IN_BUFFER | DM_OUT_BUFFER);
    	//DocumentProperties(NULL,resource->handle,resource->name,NULL,resource->pi2->pDevMode,DM_IN_BUFFER);
    	SetPrinter(resource->handle,2,(LPBYTE)resource->pi2,0);
    	SendMessageTimeout(HWND_BROADCAST,WM_DEVMODECHANGE,0L,(LPARAM)(LPCSTR)resource->name,SMTO_NORMAL,1000,NULL);
    	//DocumentProperties(NULL,resource->handle,resource->name,resource->pi2->pDevMode,NULL,DM_OUT_BUFFER);
    	
    	sprintf(sRtn, "Printer Options Set: \r\nCopies: %lu \r\nOrientation: %lu \r\nPaper Bin: %lu \r\nPaper Size: %lu", 
    			resource->pi2->pDevMode->dmCopies,
    			resource->pi2->pDevMode->dmOrientation,
    			resource->pi2->pDevMode->dmDefaultSource,
    			resource->pi2->pDevMode->dmPaperSize);
    	break;

  4. #4
    Registered User
    Join Date
    Feb 2011
    Posts
    96
    Thanks Salem. You've been here a *long* time and you helped me with something unrelated to this about 4 or 5 years ago.
    The code here is real old code, not written by me. It may have worked once but not now.
    Clearly, I'm not a c programmer. I'm trying to learn fast though)
    I need this extension to work for a client.

    I am compiling in VS 14 (2015) but I'm running nmake set up for php7.
    I don't know if I'm compiling in UNICODE or not.

    I've changed emalloc to ecalloc which is supposed to initialize with 0. I'm not sure if I'm using it right though.

    I should add that the header for my extension defines the printer.name (resource->name) as LPTSTR, so I'm not sure what you mean by 'wide string'. UNICODE?
    Code:
    typedef struct 
    {
    	HANDLE handle;
    	LPTSTR name;
    	DOCINFO info;
    	HDC dc;
    	PRINTER_INFO_2 *pi2;
    	DWORD dmModifiedFields;
    } printer;
    It compiled OK and I tested it.
    No change, it still returns the defaults of the printer, not the changes I made.

    Here is the new code:
    Code:
    case VALID_OPTIONS:
    	resource->pi2->pSecurityDescriptor=NULL;
    	resource->pi2->pDevMode->dmFields=resource->dmModifiedFields;
    	resource->dmModifiedFields=0;
    	DocumentProperties(NULL,resource->handle,resource->name,resource->pi2->pDevMode,resource->pi2->pDevMode,DM_IN_BUFFER | DM_OUT_BUFFER);
    	//DocumentProperties(NULL,resource->handle,resource->name,NULL,resource->pi2->pDevMode,DM_IN_BUFFER);
    	SetPrinter(resource->handle,2,(LPBYTE)resource->pi2,0);
    	//SendMessageTimeout(HWND_BROADCAST,WM_DEVMODECHANGE,0L,(LPARAM)(LPCSTR)resource->name,SMTO_NORMAL,1000,NULL);
    	SendMessageTimeout(HWND_BROADCAST,WM_DEVMODECHANGE,0L,(LPARAM)resource->name,SMTO_NORMAL,1000,NULL);
    	//DocumentProperties(NULL,resource->handle,resource->name,resource->pi2->pDevMode,NULL,DM_OUT_BUFFER);
    	
    	sprintf(sRtn, "Printer Options Set: \r\nCopies: %lu \r\nOrientation: %lu \r\nPaper Bin: %lu \r\nPaper Size: %lu", 
    			resource->pi2->pDevMode->dmCopies,
    			resource->pi2->pDevMode->dmOrientation,
    			resource->pi2->pDevMode->dmDefaultSource,
    			resource->pi2->pDevMode->dmPaperSize);
    	break;
    Code:
    PHP_FUNCTION(printer_open)
    {
    	zval *arg1;
    	printer *resource;
    	size_t DevModeSize;
    	size_t PrinterSize = sizeof(printer);
    	int argc = ZEND_NUM_ARGS();
    
    	//resource = (printer *)emalloc(sizeof(printer));
    	resource = (printer *)ecalloc(PrinterSize, PrinterSize);			
    	resource->dmModifiedFields = 0;
    
    	if( argc == 1 && zend_get_parameters_ex(1, &arg1) != FAILURE ) {
    		convert_to_string_ex(arg1);
    		resource->name = Z_STRVAL_P(arg1);
    	}
    	else if( argc == 0 ) {
    		resource->name = PRINTER7_G(default_printer);
    	}
    	else {
    		WRONG_PARAM_COUNT;
    	}
    	/*
    	if (OpenPrinter(resource->name, &resource->handle, NULL) != 0) {
    		resource->pi2 = (PRINTER_INFO_2 *)emalloc(sizeof(PRINTER_INFO_2));
    		resource->pi2->pDevMode = (DEVMODE *)emalloc(DocumentProperties(NULL, NULL, resource->name, NULL, NULL, 0));
    		if (DocumentProperties(NULL, resource->handle, resource->name, resource->pi2->pDevMode, NULL, DM_OUT_BUFFER) == IDOK) {
    			resource->info.lpszDocName	= estrdup("PHP generated Document");
    			resource->info.lpszOutput	= NULL;
    			resource->info.lpszDatatype = estrdup("TEXT");
    			resource->info.fwType		= 0;
    			resource->info.cbSize		= sizeof(resource->info);
    			resource->dc = CreateDC(NULL, resource->name, NULL, resource->pi2->pDevMode);
    			RETURN_RES(zend_register_resource(resource, le_printer));
    		}
    	}
    	*/
    	if (OpenPrinter(resource->name, &resource->handle, NULL) != 0) {
    		DevModeSize = DocumentProperties(NULL, NULL, resource->name, NULL, NULL, 0);
    		resource->pi2 = (PRINTER_INFO_2 *)ecalloc(sizeof(PRINTER_INFO_2),sizeof(PRINTER_INFO_2));
    		resource->pi2->pDevMode = (DEVMODE *)ecalloc(DevModeSize,DevModeSize);
    		if (DocumentProperties(NULL, resource->handle, resource->name, resource->pi2->pDevMode, NULL, DM_OUT_BUFFER) == IDOK) {
    			resource->info.lpszDocName	= estrdup("PHP generated Document");
    			resource->info.lpszOutput	= NULL;
    			resource->info.lpszDatatype = estrdup("TEXT");
    			resource->info.fwType		= 0;
    			resource->info.cbSize		= sizeof(resource->info);
    			resource->dc = CreateDC(NULL, resource->name, NULL, resource->pi2->pDevMode);
    			RETURN_RES(zend_register_resource(resource, le_printer));
    		}
    	}
    	else {
    		php_error_docref(NULL TSRMLS_CC, E_WARNING, "couldn't connect to the printer [%s]", resource->name);
    		RETURN_FALSE;
    	}
    }
    Last edited by MAtkins; 07-06-2016 at 03:46 PM.

  5. #5
    Registered User
    Join Date
    Feb 2011
    Posts
    96
    Revision: I'm getting the correct option values both before and after I I set the values using DocumentProperties.
    Still, the printer completely ignores them.

    Also, I changed this line in printer_open to exactly match the type defined in PRINTER_INFO_2 for DEVMODE:
    Code:
    resource->pi2->pDevMode = (LPDEVMODE *)emalloc(DocumentProperties(NULL, resource->handle, resource->name, NULL, NULL, 0));
    Here's a how to link. My code looks like it should work.

    Code:
    case VALID_OPTIONS:
    	bfrCopies = resource->pi2->pDevMode->dmCopies;
    	bfrOrientation = resource->pi2->pDevMode->dmOrientation;
    	bfrPaperSource = resource->pi2->pDevMode->dmDefaultSource;
    	bfrPaperSize = resource->pi2->pDevMode->dmPaperSize;
    	
    	resource->pi2->pSecurityDescriptor=NULL;
    	resource->pi2->pDevMode->dmFields=resource->dmModifiedFields;
    	resource->dmModifiedFields=0;
    	DocumentProperties(NULL,resource->handle,resource->name,resource->pi2->pDevMode,resource->pi2->pDevMode,DM_IN_BUFFER | DM_OUT_BUFFER);
    	SetPrinter(resource->handle,2,(LPBYTE)resource->pi2,0);
    	SendMessageTimeout(HWND_BROADCAST,WM_DEVMODECHANGE,0L,(LPARAM)resource->name,SMTO_NORMAL,1000,NULL);
    						
    	sprintf(sRtn, "Option values before setting:\r\nCopies: %lu \r\nOrientation: %lu \r\nPaper Bin: %lu \r\nPaper Size: %lu\r\nPrinter\r\n\r\nOptions Set: \r\nCopies: %lu \r\nOrientation: %lu \r\nPaper Bin: %lu \r\nPaper Size: %lu", 
    			bfrCopies,
    			bfrOrientation,
    			bfrPaperSource,
    			bfrPaperSize,
    			resource->pi2->pDevMode->dmCopies,
    			resource->pi2->pDevMode->dmOrientation,
    			resource->pi2->pDevMode->dmDefaultSource,
    			resource->pi2->pDevMode->dmPaperSize);
    	break;

  6. #6
    Registered User
    Join Date
    Feb 2011
    Posts
    96

    Lightbulb

    I solved this one on my own.
    The problem was that the function TextOutEx is part of the Windows gdi.
    When I 'set' the option changes in VALID_OPTIONS I needed to reset the device context so that the DEVMODE for the context included the changes.
    I added one line to the VALID_OPTIONS part of the switch. That updated the device context's DEVMODE and solved my problem.

    Now, as long as (in php) I call the VALID_OPTIONS option of the function, printer_set_option the printer responds to the changes.

    Code:
    case VALID_OPTIONS:
    	resource->pi2->pSecurityDescriptor=NULL;
    	resource->pi2->pDevMode->dmFields=resource->dmModifiedFields;
    	resource->dmModifiedFields=0;
    	DocumentProperties(NULL,resource->handle,resource->name,resource->pi2->pDevMode,resource->pi2->pDevMode,DM_IN_BUFFER | DM_OUT_BUFFER);
    	ResetDC(resource->dc, resource->pi2->pDevMode);
    	SetPrinter(resource->handle,2,(LPBYTE)resource->pi2,0);
    	SendMessageTimeout(HWND_BROADCAST,WM_DEVMODECHANGE,0L,(LPARAM)resource->name,SMTO_NORMAL,1000,NULL);
    						
    	break;

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Configuration tool
    By Nickvt in forum C Programming
    Replies: 12
    Last Post: 09-29-2014, 06:58 AM
  2. Replies: 0
    Last Post: 03-21-2009, 12:23 PM
  3. Communicating with windows shared printer
    By Chronom1 in forum Windows Programming
    Replies: 0
    Last Post: 09-25-2006, 07:15 AM
  4. Replies: 1
    Last Post: 09-22-2003, 01:40 PM
  5. looking for files configuration
    By frigga in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 11-21-2002, 08:55 AM

Tags for this Thread