首页 > 解决方案 > 从 Windows 2008 服务器上的服务产生的进程打印

问题描述

简短版本:

我写了一个小程序来打印报告。该程序是从我们的专有服务器执行的,该服务器作为 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.

我的任务是在基于 Android 的扫描设备上重新实现 Pocket-PC 功能,并从架构中删除 Apache 层。在 Android 应用程序中,我编写了一个通信层来直接访问服务器(服务)(与桌面相同)。服务器具有执行应用程序的能力,所以我写了一个小程序来收集数据,并调用 fastreport 来格式化和打印它。

效果很好。没问题。...在我们的开发环境中。它适用于我们的办公网络,服务器运行在 Windows 7 系统上。当从我们客户的 Windows 2008 服务器上的命令行运行时,它可以工作。从客户服务器上的服务运行时,它不起作用。

所以这里是代码。在我当前的版本中,我在(几乎)每一行代码中都有 try/catch 和调试打印语句。为了便于阅读,我删除了它们。

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

一位客户的 IT 人员说,为了让 Apache 版本正常工作,他们必须以管理员身份使用定义的默认打印机运行 Apache,并让该管理员帐户登录以进行打印。他怀疑如果我们以相同的配置运行我们的服务,它将开始工作。我无法在我们的网络上复制它。无论是否有人当前登录系统,我的管理员帐户始终有效。但这是 Windows 7/Professional,而不是服务器版本。

这必须是可能的...... Apache 正在这样做。如果它可以找到打印机并打印到它,我应该可以,对吧?

任何提示或帮助将不胜感激。任何事物。真的。:) 谢谢,-凯伦

编辑:添加服务器端代码。

先说几点。一,这是 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;
}

标签: c++printingwindows-servicesvclfastreport

解决方案


推荐阅读