Windows后台服务启动UI程序以默认打开文件的方式打开文件

2 篇文章 0 订阅
1 篇文章 0 订阅

背景

公司需要开发一个功能:编写一个Windows后台服务程序在开机自动运行。在运行过程中需要接收本地Web前端发送过来的文件链接,下载到本地后进行打开。下载文件已经到本地了,可是在打开文件这里踩了不少的坑。在这里进行分享。

Windows服务Session隔离

Windows后台服务启动带UI程序时,会发现程序明明已经在运行了,可是却不见UI界面。这是因为Windows有Session隔离,感兴趣的可以搜索这个。通常我们只需要创建一个进程就可以了,但是Windows后台服务启动UI程序不能直接CreateProcess(),否则因为service session,程序UI不能看见,所以 我们需要拿到当前explorer.exe的token,然后CreateProcessAsUser模拟当前用户启动进程这样就可以显示界面了。

#include <Windows.h>
#include <TlHelp32.h>
#include <tchar.h>
#include <shellapi.h>

#include <QString>

#include <UserEnv.h>
#include <QFile>
#include <QDir>
#include <QDebug>
#include <QGuiApplication>

#include <tchar.h>

#pragma comment(lib,"urlmon.lib")
#pragma comment(lib,"ws2_32.lib")

// 第一步,得到explorer.exe环境的token
DWORD INTER_GetExplorerToken(PHANDLE phExplorerToken)
{
    DWORD  dwStatus                 = ERROR_FILE_NOT_FOUND;
    BOOL   bRet                     = FALSE;
    HANDLE hProcess                 = NULL;
    HANDLE hProcessSnap             = NULL;
    char   szExplorerPath[MAX_PATH] = { 0 };
    char   FileName[MAX_PATH]       = { 0 };
    PROCESSENTRY32 pe32             = { 0 };

    try
    {
        hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

        if (hProcessSnap == INVALID_HANDLE_VALUE)
        {
            dwStatus = GetLastError();
        }
        else
        {
            pe32.dwSize = sizeof(PROCESSENTRY32);
            int bMore = ::Process32First(hProcessSnap, &pe32);

            while (bMore)
            {
                if (::wcscmp(pe32.szExeFile, _T("explorer.exe")) == 0)
                {
                    hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);

                    if (OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, phExplorerToken))
                    {
                        dwStatus = 0;
                    }
                    else
                    {
                        dwStatus = GetLastError();
                    }
                    break;
                }
                bMore = ::Process32Next(hProcessSnap, &pe32);
            }
        }
    }
    catch (...)
    {}
    if (hProcess)
    {
        CloseHandle(hProcess);
    }

    if (hProcessSnap)
    {
        CloseHandle(hProcessSnap);
    }

    return dwStatus;
}

// 第二步,启动程序
void RunProcess(LPWSTR szExeFile)
{
    HANDLE hToken = NULL;

    if (INTER_GetExplorerToken(&hToken) == 0)
    {
        LPVOID      lpEnvironment = NULL;

        if (!CreateEnvironmentBlock(&lpEnvironment, hToken, TRUE))
        {
            qDebug() << "create environment failed";
            CloseHandle(hToken);
            return;
        }

        PROCESS_INFORMATION pi = { 0 };
        STARTUPINFO si         = { sizeof(si) };
        si.wShowWindow = SW_SHOW;
        CreateProcessAsUser(hToken, NULL, szExeFile, NULL, NULL, FALSE,
                            NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT, lpEnvironment, NULL, &si,
                            &pi);
    }
}

文件打开

好了,现在既然后台服务能启动一个带UI的程序了,但是怎么以默认的打开方式打开文件呢?新建一个带打开文件的程序,这个程序主要负责解析启动时传入的文件路径并且以默认打开方式打开。这里提供了这个程序的QtCreater的工程:以默认的方式打开文件的可执行程序

后台服务函数调用方式

将打开文件的程序与后台服务程序放在同一级目录下

QString strAppPath = qApp->applicationDirPath();
QString strParam = strAppPath + "/ExcuteOpenFile.exe D:/TestOpenDoc.doc";
RunProcess((LPWSTR)strParam.toStdWString().c_str());

后记

其实实现这个打开文件的功能,想到了很多,有通过获取文件后缀后再注册表中找可以打开的文件的路径,然后以这个程序来打开文件,尝试后发现并不可取。因为Windows后台服务的Session的隔离的原因,让我没法在后台服务中直接打开文件。只能写一个可以传入参数的可执行UI程序来打开文件。

以上就是我的分享了!!!!

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值