最近在做安装包打包这一块,接触到了一种挺酷炫的技术,叫虚拟桌面技术。顾名思义,就是一个虚拟的桌面。那这个是有什么用呢?比如这样。让你去安装某个软件,但是我不想看到他的安装界面。有些软件是有静默安装,就是安装没有界面。但是有些软件是有界面的,而且,即使是没有界面的安装,他可能安装完成后会自动启动程序,你还是会看到界面。我想要的效果是:安装的过程中没有任何界面,包括安装完成后的软件启动界面我都不想看到。这个如何实现呢?可能有的人说,对应静默安装,我们可以在它启动后杀死这个进程。这确实可以,但是会闪一下,这是非常不友好的。那有没有好的办法呢?答案是有的。这时候就用到了虚拟桌面。
虚拟桌面就是创建一个虚拟的桌面,然后和安装软件的那个进程绑定起来,这样安装的过程就放到了虚拟的桌面上,这样,即使安装过程是有界面的,我们还是看不到任何的东西,这就完美的解决了无界面安装的问题。这里有篇文章:http://bbs.pediy.com/showthread.php?t=82537 介绍了如何使用这项技术。我下来也写了一个简单的程序,封装了一下功能,通过一个可执行文件的位置作为参数,来进行相应的启动,代码如下:
#ifndef _SETUPSOFTWARE
#define _SETUPSOFTWARE
using namespace std;
namespace myspace
{
class RCSetupWithVirtual
{
private:
/** 虚拟桌面句柄
*/
HDESK m_hDesk;
public:
RCSetupWithVirtual();
~RCSetupWithVirtual();
void StartupSetup(string fileName);
};
}
#endif // _SETUPSOFTWARE
#include <windows.h>
#include <Shlwapi.h>
#include <string>
#include <tchar.h>
#include "SetupSoftware.h"
#define RC_VIRTUAL_DESKTOP_NAME _T("my_first_virtual_desk")
using namespace std;
using namespace myspace;
RCSetupWithVirtual::RCSetupWithVirtual():m_hDesk(NULL)
{
m_hDesk = ::CreateDesktop(RC_VIRTUAL_DESKTOP_NAME, NULL, NULL, NULL, GENERIC_ALL, NULL);
if (m_hDesk == NULL)
{
int nError = GetLastError();
TCHAR szErrorInfo[MAX_PATH];
_stprintf_s(szErrorInfo, _T("error result is %d"), nError);
}
}
RCSetupWithVirtual::~RCSetupWithVirtual()
{
if (m_hDesk != NULL)
{
::CloseDesktop(m_hDesk);
m_hDesk = NULL;
}
}
void RCSetupWithVirtual::StartupSetup(string fileName)
{
if (!PathFileExists(fileName.c_str()))
return;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
//禁止等待子进程首次调用GetMessage时呈现等待鼠标
si.dwFlags |= STARTF_FORCEOFFFEEDBACK;
//虚拟桌面
if ((m_hDesk != NULL))
{
si.lpDesktop = RC_VIRTUAL_DESKTOP_NAME;
}
BOOL result = false;
int nLength = fileName.length();
TCHAR* sBuff = new TCHAR[nLength + 1];
memset(sBuff, 0, nLength + 1);
_tcscpy_s(sBuff, nLength+1, fileName.c_str());
result = ::CreateProcess(NULL, sBuff, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi);
if (!result)
{
int nError = GetLastError();
TCHAR szErrorInfo[MAX_PATH];
_stprintf_s(szErrorInfo, _T("error result is %d"), nError);
return;
}
if (pi.hThread)
{
::CloseHandle(pi.hThread);
pi.hThread = NULL;
}
if (pi.hProcess != NULL)
{
::CloseHandle(pi.hProcess);
}
}
#include <windows.h>
#include <tchar.h>
#include <string>
#include "SetupSoftware.h"
using namespace myspace;
using namespace std;
int APIENTRY WinMain(HINSTANCE hInstexe, HINSTANCE, PSTR nCmdLine, int nCmdShow)
{
RCSetupWithVirtual mytest;
string exePath = _T("C:\\Windows\\system32\\cacls.exe");
mytest.StartupSetup(exePath);
return 0;
}
程序运行后,查看任务浏览器的效果如下:
成功的启动了程序,但是不会看到任何的界面。这种技术对于后台进行任务处理或者干些猥琐的事情是再合适不过的了。不过有个问题需要注意,当程序运行结束后,虚拟桌面上的程序不会自动结束的,所以我们一般在最后需要手动把程序关掉。