Windows Vista C++ application is unable to print out documents


             



Hi there,


I know some of you have been waiting for a while before I made my first technical post. I’ve been busy helping you guys solving development issues, isn’t that a good justification? J


Today, I’m going to give you an example of a typical scenario application’s developer faces with when a new version of Windows is released and we discover that our application that was working perfectly fine on previous version now has a completely different behavior.


When that happens, we usually think that because our code was working fine before it means that something is going wrong with this new version of Windows. That can be true but experience shows that most of the time, we’ve to reconsider our assumption. To insure application backward compatibility, this is very unlikely that an API with the exact same name and parameter has his behavior changed from a version of Windows to another.


I had a customer who was facing the following issue:


PROBLEM:


He has written a native C++ application to print out his documents. The program has its own feature to connect a printer on network and printing out the documents. The application is working fine on Windows XP for years, but it seems that it is not compatible with Windows Vista. He’s getting an "invalid handle" error.


EXPECTATIONS / AGREED RESOLUTION:


What is happening? How to get rid of this issue?


ENVIRONMENT:


Windows Vista


Shared printed accessible from any machines from local area network


SUMMARY OF TROUBLESHOOTING:


In such circumstances the first thing we need to find out is what API’s call generates the error.


This can be done either by tracing the application with a debugger or by taking a process memory dump when the issue occurs. I’ll explain in a later post both of these different approaches.


The error was returned by calling the CreateFile API (http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx ).


C++


HANDLE WINAPI CreateFile(


  __in      LPCTSTR lpFileName,


  __in      DWORD dwDesiredAccess,


  __in      DWORD dwShareMode,


  __in_opt  LPSECURITY_ATTRIBUTES lpSecurityAttributes,


  __in      DWORD dwCreationDisposition,


  __in      DWORD dwFlagsAndAttributes,


  __in_opt  HANDLE hTemplateFile


);


 


This function creates or opens a file or I/O device and returns a handle that can be used to access the file or device for various types of I/O depending on the file or device and the flags and attributes specified.


The game is now to understand why the call fails on Windows Vista returning VALID_HANDLE_VALUE.


Reading the documentation we should have a look at the “return value” section.


It says the following:


Return Value :


If the function succeeds, the return value is an open handle to the specified file, device, named pipe, or mail slot.


If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError().


We could see that the ERROR_FILE_NOT_FOUND was returned by GetLastError(). This makes us think that for any reason, the API is not able to access the target file. At this step we can try to find in the documentation any hints that may lead us to any root cause, for instance any implementation changes or restriction coming with Windows Vista. Any reference like this one: http://support.microsoft.com/kb/942448/en-us (Changes to the file system and to the storage stack to restrict direct disk access and direct volume access in Windows Vista and in Windows Server 2008).


The ultimate path to follow is to read all the information provided by the documentation regarding ERROR_FILE_NOT_FOUND. We are lucky more details regarding this error can be found in the documentation in the “Opening LPT Ports” section. It’s said that specifying OPEN_EXISTING as dwCreationDisposition parameter will cause the function to fail when called on Windows Vista or Windows 2008 server to open an LPT port that is mapped to a network share. GetLastError() returns ERROR_FILE_NOT_FOUND.


The customer’s application was calling the API with the following parameters:


C++


CreateFile(“\\MyServer\MyPrinter” , FILE_FLAG_OVERLAPPED, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);


 


At this step we can notice that this is actually a known issue. To avoid this you should use the OPEN_ALWAYS flag instead that will force the driver to start the device so that the WriteFile interface is available. The code was modified that way:


C++


CreateFile(“\\MyServer\MyPrinter” , FILE_FLAG_OVERLAPPED, FILE_SHARE_WRITE, 0, OPEN_ALWAYS, 0, 0);


 


 With this solution the application was able to run successfully on both version of the operating system.


To put it in a nutshell, when developing an application the first thing you should do is to read carefully the documentation and use the appropriate parameters. Most of the time this will prevent you for facing to this kind of issues. If any system change is susceptible to have an impact on an API, the documentation may mention it. If this is not the case, please don’t hesitate to raise the issue on the article in the appropriate section.


I hope that you found this post useful.

Cheers,

Skip to main content