Как правильно установить виртуальный принтер с помощью WinAPI на Win x64? - PullRequest
3 голосов
/ 14 октября 2011

Я пытаюсь установить виртуальный принтер из консольной программы C ++, используя вызовы WinAPI.Он отлично работает в Windows XP, но в Windows 7 x64 есть некоторые процессы, которые блокируют файлы в системных папках, необходимые для установки.Я думаю, что они появляются только в 64-разрядных системах 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;
}

Их больше, а некоторые очень длинные, поэтому я не буду публиковать их здесь, если они не нужны.

Есть ли способ предотвратить блокировку файлов системы и принудительную установку принтера?

PS Я прекращаю службу спулера при копировании файлов, а затем запускаю его перед любыми вызовами WinAPI.
PPS Это не мой код.Это устаревший код, который нам нужно сохранить для клиента.

1 Ответ

2 голосов
/ 15 октября 2011

Нет, нет способа предотвратить блокировку файлов.Даже если вы остановите спулер, splwow64 и все остальное, о чем вы только можете подумать, все же есть вероятность, что в какой-то другой программе будет открыта одна из ваших DLL.Это особенно верно, поскольку вы используете UNIDRV, потому что он используется многими другими драйверами принтера.

Функция MoveFileEx является единственным надежным решением.Если какая-либо из ваших копий файлов завершится неудачно из-за ошибки в доступе, используйте MoveFileEx с параметром MOVEFILE_DELAY_UNTIL_REBOOT и предложите пользователю перезагрузиться.Вы также можете поместить свой установщик в ключ реестра RunOnce (с префиксом восклицательного знака), чтобы гарантировать, что он продолжит установку после перезагрузки.Это будет значительным изменением для вашего установщика, но это единственный надежный подход.

...