How to properly install virtual printer using WinAPI on Win x64?
I am trying to install virtual printer from C++ console program using WinAPI calls. It works fine on Windows XP, but on Windows 7 x64 there are some processes which lock files in system folders, required for install. I think they appear only on x64 Windows systems, but I haven't tested it with Windows XP x64.
These are processes splwow64.exe and PrintIsolationHost.exe. I tried to kill them programmaticly and it turns out well (well, for terminating PrintIsolationHost.exe I've set a Debug Privileges, 'coz it's system process) but I have started to think there is probably something wrong with my code if it doesn't work in this way. Apparently there must be some way of installing without terminating any system processes.
The code is something like that:
BOOL res = FALSE;
printf("Run install:\n\n");
// Set debug privilages to current process
HANDLE hTokenThis( NULL );
OpenProcessToken( GetCurrentProcess(), TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hTokenThis );
SetPrivilege( hTokenThis, SE_DEBUG_NAME, TRUE );
printf("Stop s开发者_StackOverflowpooler service...\r\n");
if(!StopService("spooler"))
return FALSE;
// Stop splwow64.exe and PrintIsolationHost.exe - it can prevent some files to be copied
HANDLE process = GetProcessByName( "splwow64.exe" );
if (process)
TerminateProcess( process, 0 );
// Stop PrintIsolationHost.exe (it runs under SYSTEM and requires debug rights to be stopped)
process = GetProcessByName( "PrintIsolationHost.exe" );
if (process)
TerminateProcess( process, 0 );
// Continue install
printf("Copy driver file...\r\n");
if(!CopyInstFile())
{
return FALSE;
}
printf("Start spooler service...\r\n");
if(!StartServices("spooler"))
return FALSE;
printf("Add Port...\r\n");
res = AddPort();
ERROR_CHECK_EXIT(res)
printf("Add Driver...\r\n");
res = AddDriver();
ERROR_CHECK_EXIT(res)
printf("Add print Processor...\r\n");
res = AddProcessor();
ERROR_CHECK_EXIT(res)
printf("Add printer...\r\n");
res = AddPrint();
ERROR_CHECK_EXIT(res)
The functions which install various stuff:
BOOL CPrintInstal::AddDriver()
{
DRIVER_INFO_3 driverInfo;
memset(&driverInfo,0,sizeof(driverInfo ));
driverInfo.cVersion = 3;
driverInfo.pName = PRINTERDRIVERNAME;
driverInfo.pEnvironment = NULL;//"Windows NT x86";
driverInfo.pDriverPath="UNIDRV.DLL";
driverInfo.pDataFile=PDFCONVERTED_GPD;
driverInfo.pConfigFile= "UNIDRVUI.DLL";
driverInfo.pHelpFile= "UNIDRV.HLP";
driverInfo.pDependentFiles = NULL;
driverInfo.pDefaultDataType=NULL;
return AddPrinterDriver(NULL,3,(LPBYTE)&driverInfo);
}
BOOL CPrintInstal::AddPrint()
{
PRINTER_INFO_2 printInfo;
memset(&printInfo,0,sizeof(PRINTER_INFO_2));
printInfo.pServerName=NULL;
printInfo.pPrinterName=PRINTERNAME;
printInfo.pShareName=NULL;
printInfo.pPortName=PORTNAME_A;
printInfo.pPrintProcessor =PRINTPROCESSORNAME;
printInfo.pDatatype = "NT EMF 1.008";
printInfo.pDriverName =PRINTERDRIVERNAME;
printInfo.Attributes = PRINTER_ATTRIBUTE_LOCAL | PRINTER_ATTRIBUTE_QUEUED | PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS;
SetLastError(0);
HANDLE handle = AddPrinter(NULL,2,(LPBYTE)&printInfo);
if(handle == NULL)
{
if(GetLastError()!=1802)
return FALSE;
}
ClosePrinter(handle);
return TRUE;
}
There are more of them and some are really long, so I won't post it here if it's not needed.
Is there any way to prevent system lock files and force printer install?
P.S. I stop spooler service while copying files and then run it before any calls to WinAPI.
P.P.S It's not my code. It's legacy code which we need to maintain for the customer.No, there's no way to prevent files from being locked. Even if you stop the spooler, splwow64 and everything else you can think of, there's still the possibility some other program will have one of your DLLs open. This is especially true since you're using UNIDRV because it's used by many other printer drivers.
The MoveFileEx function is the only reliable solution. If any of your file copies fail due to an access denied error, use MoveFileEx with the MOVEFILE_DELAY_UNTIL_REBOOT option and prompt the user to reboot. You can also put your installer in the registry RunOnce key (prefixed by an exclamation mark) to guarantee it will continue the install after the reboot. This will be a significant change to your installer, but it's the only reliable approach.
精彩评论