2011-10-14 46 views
3

我正在嘗試使用WinAPI調用從C++控制檯程序安裝虛擬打印機。它在Windows XP上運行良好,但在Windows 7 x64上有一些進程會鎖定系統文件夾中的文件,這些文件是安裝所必需的。我認爲它們只出現在x64的Windows系統上,但我沒有用Windows XP x64進行測試。如何在Win x64上使用WinAPI正確安裝虛擬打印機?

這些是進程splwow64.exe和PrintIsolationHost.exe。我試圖通過程序化方式殺死它們,結果很好(當然,因爲終止了PrintIsolationHost.exe,我設置了調試權限,因爲它是系統進程),但是我開始認爲如果代碼不正確,可能會出現問題不以這種方式工作。顯然,必須有一些安裝方式,而無需終止任何系統進程。

的代碼是類似的東西:

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 spooler 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) 

其中安裝各種東西的功能:

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; 
} 

有更多的人,有些是很長,所以我不會發布它這裏如果不需要。

有沒有什麼辦法來防止系統鎖定文件和強制打印機安裝?

P.S.我在複製文件時停止假脫機程序服務,然後在對WinAPI進行任何調用之前運行它。
P.P這不是我的代碼。這是我們需要爲客戶維護的遺留代碼。

+0

你有沒有想出一個解決方案,你願意分享嗎? – agarcian

+0

@agarcian很久以前,我不記得我使用了什麼確切的解決方案,但我認爲它是在下面的單一答案中描述的解決方案 - 使用註冊表分支並在重新啓動後運行安裝程序或使用MoveFileEx。 –

+0

此代碼是否安裝虛擬打印機驅動程序或是否模擬虛擬打印機(例如,當我們打印虛擬驅動程序時應使用可用打印機列出) –

回答

2

不,不能阻止文件被鎖定。即使您停止了後臺打印程序,splwow64以及其他任何您可以想到的內容,仍有可能其他程序會打開其中一個DLL。由於您使用的是UNIDRV,因此許多其他打印機驅動程序都使用它,因此尤其如此。

MoveFileEx功能是唯一可靠的解決方案。如果任何文件副本由於訪問被拒絕錯誤而失敗,請使用MoveFileEx和MOVEFILE_DELAY_UNTIL_REBOOT選項並提示用戶重新引導。您還可以將安裝程序放在註冊表的RunOnce鍵(帶有感嘆號的前綴),以確保重新啓動後它將繼續安裝。這將對您的安裝程序產生重大影響,但這是唯一可靠的方法。

+0

重新啓動後spoller是否工作,以便我可以調用所有API並安裝打印機? –

+0

是的,假脫機程序將在您的安裝程序之前啓動。 –

+2

迂腐筆記:不會[RunOnce](http://msdn.microsoft.com/en-us/library/aa376977 \(v = vs.85 \).aspx)鍵(值前綴爲!! ')是一個更合適的地方? – user786653

相關問題