65.9K
CodeProject 正在变化。 阅读更多。
Home

如何在 Vista 中提升您的应用程序在 Windows 启动时运行

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.50/5 (5投票s)

2008年5月17日

CPOL

2分钟阅读

viewsIcon

70695

一篇关于在 Vista 中提升应用程序在 Windows 启动时运行的文章。

引言

本文档描述了如何在 Vista 系统启动时提升你的程序。提升应用程序很容易,但将应用程序注册到启动项并不容易。

背景

阅读本文档需要读者具备一定的背景知识。
首先,理解 Vista 的 UAC 非常重要。UAC 太复杂,难以理解。因此,本文档不包含关于 UAC 的任何信息。
其次,需要 MFC 和 API 知识,因为本文档的示例代码使用了 MFC 和 API。

Vista 和 Windows 启动

许多程序需要在 Windows 启动时运行。

在 Windows XP 中,在启动时运行并不是什么大问题。但在 Windows Vista 中,它成了一个大问题。Windows Vista 的新保护功能限制了想要以管理员身份运行的启动程序。(它需要提升权限。)

如果你的应用程序不需要管理员权限,那么迁移到 Windows Vista 就不需要做任何事情。但是,如果你的应用程序需要管理员权限,那么你的应用程序将无法在启动时运行,因为 Vista 的新保护机制会阻止你的程序。

似乎在 Vista 的 Windows 启动时运行具有管理员权限的程序是不可能的。但实际上有一种方法可以做到这一点(即使它与 XP 不同)。

本文档描述了 Windows Vista 的保护机制以及解决我们问题的一种可能方法。

另一种方法

为了找到另一种方法,我们必须考虑保护软件的架构。从以下原则开始:

“Windows Vista 允许运行不需要管理员权限的软件。”

因此,一种可能的方法如下:

  • 我们需要创建一个不需要管理员权限的普通程序。(新的保护机制不会阻止非特权应用程序。)
  • 该程序通常需要使用 CreateProcess 提升自身权限并终止。

以下伪代码展示了该方法:

void Main()
{
    if(IsVista() == TRUE && Elevation() == FALSE) {
        ElevationItself();
        Terminate();
    }
}

C++ 代码 (MFC)

伪代码很简单,但实际代码却不然。

CString g_szProgramFolder;
CString g_szCmdLine;

BOOL RunAsAdministrator(LPSTR lpszFileName, LPSTR lpszDirectory)
{
    SHELLEXECUTEINFOA TempInfo = {0};

    TempInfo.cbSize = sizeof(SHELLEXECUTEINFOA);
    TempInfo.fMask = 0;
    TempInfo.hwnd = NULL;
    TempInfo.lpVerb = "runas";
    TempInfo.lpFile = lpszFileName;
    TempInfo.lpParameters = "runasadmin";
    TempInfo.lpDirectory = lpszDirectory;
    TempInfo.nShow = SW_NORMAL;

    BOOL bRet = ::ShellExecuteExA(&TempInfo);

    return bRet;
}

BOOL CMFCApplication::InitInstance()
{
    char szCurFolder[1024] = { 0, };
    GetModuleFileName(GetModuleHandle(NULL), szCurFolder, 1023);

    CString szFullPath = szCurFolder;
    szFullPath = szFullPath.Left(szFullPath.ReverseFind('\\'));

    g_szProgramFolder = szFullPath;

    CCommandLineInfo oCmdLineInfo;
    ParseCommandLine(oCmdLineInfo);

    g_szCmdLine = oCmdLineInfo.m_strFileName;

    if(IsVista()) {
        if(stricmp(g_szCmdLine, "elevation") == 0) {
            char szCmdLine[1024] = { 0, };
            char szCurFileName[1024] = { 0, };
            GetModuleFileName(GetModuleHandle(NULL), szCurFileName, 1023);

            BOOL bRet = 
                RunAsAdministrator( szCurFileName, (LPSTR)(LPCTSTR)g_szProgramFolder );

            if(bRet == TRUE) {
                return FALSE;
            }
        } else if(stricmp(g_szCmdLine, "runasadmin") == 0) {
            //
            // go trough!.
            //
        } else {
            char szCmdLine[1024] = { 0, };
            char szCurFileName[1024] = { 0, };
            GetModuleFileName(GetModuleHandle(NULL), szCurFileName, 1023);

            sprintf(szCmdLine, "\"%s\" elevation", szCurFileName);

            WinExec(szCmdLine, SW_SHOW);

            return FALSE;
        }
    }
    .
    .
    .
}

关注点

RunAsAdministrator 函数在用户选择“取消”时返回 FALSE。因此,你可以重复执行程序,直到用户选择“允许”。

历史

  • 2008-05-16:首次发布
© . All rights reserved.