Печать из процесса, порожденного из службы на сервере Windows 2008 - PullRequest
0 голосов
/ 29 июня 2018

Краткая версия:

Я написал небольшую программу для печати отчета. Эта программа исполняется с нашего проприетарного сервера, который работает как служба Windows. Он работает в нашей среде разработки, но не в сети наших клиентов.

Когда я пытаюсь получить доступ к системе печати в случае сбоя, я получаю ошибку «Нет принтера по умолчанию». Мы попросили клиента создать новую учетную запись для входа в систему, для которой был определен принтер по умолчанию, и перезапустить сервер с использованием этой учетной записи для входа. Та же ошибка.

Обратите внимание, что эта ошибка генерируется при попытке найти указанный принтер, а не при попытке печати на нем.

Есть ли способ убедить порожденный сервером процесс в том, что принтеры действительно существуют?

Длинная версия:

 In our "current" production environment, we have the following:

 1. a proprietary server that runs as a service under windows.
 2. a desktop client 
    --> accesses data via that service
    --> uses fastreport4 to generate reports
    --> developed using C++Builder6 (and VCL)
 3. a PocketPC-based application that runs on scanning devices
    --> uses Apache to communicate with the service
    --> also uses Apache to poke a cgi-bin application that will bring up
        the desktop app in stealth mode, run a report, and print it.

Мне было поручено заново реализовать функциональность Pocket-PC на устройстве сканирования на базе Android и удалить слой Apache из архитектуры. В приложении для Android я написал коммуникационный слой для прямого доступа к серверу (службе) (так же, как это делает рабочий стол). Сервер имеет возможность выполнять приложения, поэтому я написал небольшую для сбора данных и вызова fastreport для форматирования и печати. ​​

Отлично работает. Нет проблем. ... в нашей среде разработки. Он работает в нашей офисной сети с сервером, работающим в системе Windows 7. Он работает при запуске из командной строки на сервере Windows 2008 нашего клиента. Не работает при запуске из сервиса на сервере клиента.

Так вот код. В моей текущей ревизии у меня есть операторы try / catch и debug для печати (почти) каждой строки кода. Я удалил их для удобства чтения.

bool __fastcall TFormReportRunner::mySetPrinter(const char* name)
{
    char pDevice[MAX_PATH];
    char pDriver[MAX_PATH];
    char APort[100];
    UINT ADeviceMode;
    bool printerFound = false;
    bool errorFound = false;

    String PrinterPort = String(name).UpperCase();
    TPrinter* Prntr;

    // I added this bit to see if it helps. Seems to make no difference
    bool rc = SetDefaultPrinter("");

    Prntr = Printer();
    if (Prntr == NULL)
    {
        LogErrorMsg("Printer() returned null.");
        return false;
    }

    int i = Prntr->Printers->Count - 1;
    for (; i >= 0; i--)
    {
        // In the failing case, this next statement is the one that causes an exception.
        Prntr->PrinterIndex = i;
        Prntr->GetPrinter(pDevice, pDriver, APort, ADeviceMode);

        DWORD SizeNeeded = 0;
        HANDLE PrinterHandle;
        if (OpenPrinter(pDevice, &PrinterHandle, NULL) == 0)
        {
            LogErrorMsg("Could not open printer");
            return false;
        }

        GetPrinter(PrinterHandle, 2, NULL, 0, &SizeNeeded);

        if (SizeNeeded == 0)
        {     
            ClosePrinter(PrinterHandle);
            LogErrorMsg("Could not retrieve printer info size");
            return false;
        }

        PRINTER_INFO_2 PrinterInfo2;
        char* buffer = new char[SizeNeeded];
        if (GetPrinter(PrinterHandle, 2, buffer, SizeNeeded, &SizeNeeded) == 0)
        {
            ClosePrinter(PrinterHandle);
            delete [] buffer;
            LogErrorMsg("Could not retrieve printer info");
            return false;
        }

        String PortName = ((PRINTER_INFO_2*)buffer)->pPortName;

        delete [] buffer;
        ClosePrinter(PrinterHandle);

        if (PrinterPort == PortName)
        {
            frxReport1->PrintOptions->Printer = pDevice;
            break;
        }
    }
    Prntr->PrinterIndex = i;
    return true;
}

Один из ИТ-специалистов заказчика говорит, что для работы версии Apache необходимо запустить Apache в качестве администратора с определенным принтером по умолчанию И зарегистрировать эту учетную запись администратора для печати. Он подозревает, что если мы запустим наш сервис в той же конфигурации, он начнет работать. Я не смог повторить это в нашей сети. Моя учетная запись администратора всегда работает независимо от того, вошел ли кто-либо в систему в данный момент или нет. Но это Windows 7 / Professional, а не версия сервера.

Это должно быть возможно ... Апач делает это. Если он сможет найти принтер и распечатать его, я смогу, верно?

Будем весьма благодарны за любые подсказки или помощь. Что-нибудь. В самом деле. :) Спасибо, -Karen

Редактировать: добавление серверного кода.

Сначала пара нот. Во-первых, это было написано 20 лет назад (кем-то другим). Во-вторых, это НЕ приложение VCL (и было скомпилировано с помощью компилятора Microsoft). Три, мы не будем это менять. Перекомпиляция с текущими компиляторами СЛИШКОМ опасна для чего-то, что иначе работает.

int myServer::RunProcess2(ClientCall *call, vector<string> &args, vector<string> &env, const char* input, unsigned int insize,
                              string *output, string *error)
{
    CancelProcess2();   // only one process allowed per connection
    string cmdline;
    for (unsigned int i = 0; i < args.size(); i++)
    {
        if (i != 0)
            cmdline += ' ';
        cmdline += args[i];
    }

    env.push_back(EnvPATH);
    int size = 1;
    for (unsigned int i = 0; i < env.size(); i++)
    {
        size += env[i].size() + 1;
    }
    char *environment = (char*)malloc(size);
    if (environment == NULL)
    {
        call->error = "Could not allocate memory for process environment variables";
        return 0;
    }
    char *ptr = environment;
    for (unsigned int i = 0; i < env.size(); i++)
    {
        size = env[i].size() + 1;
        memcpy(ptr, env[i].c_str(), size);
        ptr += size;
    }
    ptr[0] = '\0';

    HANDLE hInputReadPipe = NULL, hInputWritePipe = NULL;
    HANDLE hReadPipe, hWritePipe;
    HANDLE hErrorReadPipe, hErrorWritePipe;
    SECURITY_ATTRIBUTES sa;
    sa.nLength              = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle       = true;

    // create output pipe
    if (CreatePipe(&hReadPipe, &hWritePipe, &sa, 4096) == 0)
    {
        free(environment);
        call->error = "Error creation Pipe";
        return 0;
    }
    // create error pipe
    if (CreatePipe(&hErrorReadPipe, &hErrorWritePipe, &sa, 4096) == 0)
    {
        CloseHandle(hReadPipe);
        CloseHandle(hWritePipe);
        free(environment);
        call->error = "Error creating Pipe";
        return 0;
    }

    if (insize > 0)
    {
        // create input pipe
        if (CreatePipe(&hInputReadPipe, &hInputWritePipe, &sa, 4096) == 0)
        {
            CloseHandle(hReadPipe);
            CloseHandle(hWritePipe);
            CloseHandle(hErrorReadPipe);
            CloseHandle(hErrorWritePipe);
            free(environment);
            call->error = "Error creating Pipe";
            return 0;
        }
    }

    STARTUPINFO si;
    memset(&si, 0, sizeof(si));
    si.cb          = sizeof(si);
    si.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.wShowWindow = SW_HIDE;
    si.hStdOutput  = hWritePipe;
    si.hStdError   = hErrorWritePipe;
    si.hStdInput   = hInputReadPipe;

    PROCESS_INFORMATION pi;
    if (CreateProcess(NULL, (char*)cmdline.c_str(), NULL, NULL, true, 0, environment, NULL, &si, &pi) == 0)
    {
        CloseHandle(hErrorReadPipe);
        CloseHandle(hErrorWritePipe);
        CloseHandle(hReadPipe);
        CloseHandle(hWritePipe);
        if (hInputReadPipe != NULL)
        {
            CloseHandle(hInputReadPipe);
            CloseHandle(hInputWritePipe);
        }
        free(environment);
        call->error = string("Error executing command: ") + cmdline + "\n" + GetErrorText();
        return 0;
    }

    report_handle = pi.hProcess;

    CloseHandle(hErrorWritePipe);
    CloseHandle(hWritePipe);
    if (hErrorReadPipe != NULL)
        CloseHandle(hInputReadPipe);
    char buffer[4097];
    DWORD BytesAvail;
    DWORD BytesRead = 0;
    DWORD BytesWritten = 0;
    DWORD BytesToRead = sizeof(buffer) - 1;
    DWORD BytesToWrite = insize;
    bool finished_readpipe = false, finished_errorpipe = false;
    bool finished_inputpipe = (insize == 0);
    int wait_time = 1;
    bool error_occurred = false;
    while (finished_readpipe == false || finished_errorpipe == false || finished_inputpipe == false)
    {
        if (finished_inputpipe == false)
        {
            if (BytesToWrite <= 0)
            {
                CloseHandle(hInputWritePipe);
                hInputWritePipe = NULL;
                finished_inputpipe = true;
                continue;
            }
            BytesAvail = 1000;
            /*if (PeekNamedPipe(hInputWritePipe, NULL, NULL, NULL, &BytesAvail, NULL) == 0)
            {
                DWORD temp = GetLastError();
                // pipe has been closed
                finished_inputpipe = true;
                continue;
            }*/
            if (BytesAvail > 0)
            {
                if (BytesAvail > BytesToWrite)
                    BytesAvail = BytesToWrite;
                if (WriteFile(hInputWritePipe, input, BytesAvail, &BytesWritten, NULL) == 0)
                {            
                    if (GetLastError() == ERROR_NO_DATA)
                    {
                        int a = 2; // Pipe was closed (normal exit path).
                    }
                    finished_inputpipe = true;
                    continue;
                }

                input += BytesWritten;
                BytesToWrite -= BytesWritten;

                if (BytesToWrite == 0)
                {
                    finished_inputpipe = true;
                }
                continue;
            }
        }
        if (finished_readpipe == false)
        {
            while (true)
            {
                if (PeekNamedPipe(hReadPipe, NULL, NULL, NULL, &BytesAvail, NULL) == 0)
                {
                    // pipe has been closed
                    finished_readpipe = true;
                    break;
                }
                if (BytesAvail <= 0)
                    break;
                if (BytesAvail > sizeof(buffer) - 1)
                    BytesAvail = sizeof(buffer) - 1;
                if (ReadFile(hReadPipe, buffer, BytesAvail, &BytesRead, NULL) == 0)
                {
                    finished_readpipe = true;
                    break;
                }

                if (BytesRead == 0)
                {
                    finished_readpipe = true;
                    break;
                }
                buffer[BytesRead] = '\0';
                *output += buffer;

                if (output->length() >= MAX_PROCESS_OUTPUT)
                {
                    finished_inputpipe = true;
                    finished_readpipe = true;
                    finished_errorpipe = true;
                    error_occurred = true;
                    call->error = "Output limit reached";
                }
            }
            if (finished_readpipe == true)
                continue;
        }
        if (finished_errorpipe == false)
        {
            while (true)
            {
                if (PeekNamedPipe(hErrorReadPipe, NULL, NULL, NULL, &BytesAvail, NULL) == 0)
                {
                    // pipe has been closed
                    finished_errorpipe = true;
                    break;
                }
                if (BytesAvail <= 0)
                    break;
                if (BytesAvail > sizeof(buffer) - 1)
                    BytesAvail = sizeof(buffer) - 1;
                if (ReadFile(hErrorReadPipe, buffer, BytesAvail, &BytesRead, NULL) == 0)
                {
                    finished_errorpipe = true;
                    break;
                }
                if (BytesRead == 0)
                {
                    finished_errorpipe = true;
                    break;
                }
                buffer[BytesRead] = '\0';
                *error += buffer;

                if (error->length() >= MAX_PROCESS_OUTPUT)
                {
                    finished_inputpipe = true;
                    finished_readpipe = true;
                    finished_errorpipe = true;
                    error_occurred = true;
                    call->error = "Error output limit reached";
                }
            }
            if (finished_errorpipe == true)
                continue;
        }
        // don't tie up the server
        if (wait_time < 100)
            wait_time++;
        Sleep(wait_time);
    }
    if (error_occurred == false)
        WaitForSingleObject(pi.hProcess, INFINITE);
    process_mutex.lock();
    report_handle = NULL;
    process_mutex.unlock();
    DWORD exit_code = 0;
    GetExitCodeProcess(pi.hProcess, &exit_code);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    CloseHandle(hReadPipe);
    CloseHandle(hErrorReadPipe);
    if (hInputWritePipe != NULL)
        CloseHandle(hInputWritePipe);
    free(environment);

    return exit_code;
}
...