如何在Win x64上使用WinAPI正确安装虚拟打印机?

时间:2011-10-14 17:36:48

标签: c++ windows winapi installation printers

我正在尝试使用WinAPI调用从C ++控制台程序安装虚拟打印机。它在Windows XP上运行良好,但在Windows 7 x64上有一些进程可以锁定系统文件夹中的文件,这是安装所必需的。我认为它们只出现在x64 Windows系统上,但我还没有使用Windows XP x64进行测试。

这些是进程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.S这不是我的代码。这是我们需要为客户维护的遗留代码。

1 个答案:

答案 0 :(得分:2)

不,没有办法阻止文件被锁定。即使你停止假脱机程序,splwow64以及你能想到的其他一切,仍然有可能其他程序会打开你的一个DLL。由于您使用的是UNIDRV,因此它被许多其他打印机驱动程序使用时尤其如此。

MoveFileEx功能是唯一可靠的解决方案。如果由于访问被拒绝错误导致任何文件副本失败,请使用带有MOVEFILE_DELAY_UNTIL_REBOOT选项的MoveFileEx并提示用户重新启动。您还可以将安装程序放在注册表RunOnce密钥(以感叹号为前缀)中,以确保它在重新启动后继续安装。这将是对安装程序的重大改变,但这是唯一可靠的方法。