【问题标题】:How do I integrate UAC into my VB6 program?如何将 UAC 集成到我的 VB6 程序中?
【发布时间】:2011-06-12 20:24:42
【问题描述】:

我需要一些代码来将管理员权限图标添加到命令按钮并在单击此类按钮时显示提示。我怎样才能在 VB6 中做到这一点?有些操作需要管理员权限,因为它们会替换 Windows Vista/7 不允许程序正常访问文件的文件和内容。

【问题讨论】:

    标签: visual-studio vb6 uac administrator


    【解决方案1】:

    这是一个 ShellExecuteEx 的 VB6 示例,它允许您有选择地执行具有管理员权限的任何进程。您可以将其放入模块或类中。

    Option Explicit
    
    Private Const SEE_MASK_DEFAULT = &H0
    
    Public Enum EShellShowConstants
            essSW_HIDE = 0
            essSW_SHOWNORMAL = 1
            essSW_SHOWMINIMIZED = 2
            essSW_MAXIMIZE = 3
            essSW_SHOWMAXIMIZED = 3
            essSW_SHOWNOACTIVATE = 4
            essSW_SHOW = 5
            essSW_MINIMIZE = 6
            essSW_SHOWMINNOACTIVE = 7
            essSW_SHOWNA = 8
            essSW_RESTORE = 9
            essSW_SHOWDEFAULT = 10
    End Enum
    
    Private Type SHELLEXECUTEINFO
            cbSize        As Long
            fMask         As Long
            hwnd          As Long
            lpVerb        As String
            lpFile        As String
            lpParameters  As String
            lpDirectory   As String
            nShow         As Long
            hInstApp      As Long
            lpIDList      As Long     'Optional
            lpClass       As String   'Optional
            hkeyClass     As Long     'Optional
            dwHotKey      As Long     'Optional
            hIcon         As Long     'Optional
            hProcess      As Long     'Optional
    End Type
    
    Private Declare Function ShellExecuteEx Lib "shell32.dll" Alias "ShellExecuteExA" (lpSEI As SHELLEXECUTEINFO) As Long
    
    Public Function ExecuteProcess(ByVal FilePath As String, ByVal hWndOwner As Long, ShellShowType As EShellShowConstants, Optional EXEParameters As String = "", Optional LaunchElevated As Boolean = False) As Boolean
        Dim SEI As SHELLEXECUTEINFO
    
        On Error GoTo Err
    
        'Fill the SEI structure
        With SEI
            .cbSize = Len(SEI)                  ' Bytes of the structure
            .fMask = SEE_MASK_DEFAULT           ' Check MSDN for more info on Mask
            .lpFile = FilePath                  ' Program Path
            .nShow = ShellShowType              ' How the program will be displayed
            .lpDirectory = PathGetFolder(FilePath)
            .lpParameters = EXEParameters       ' Each parameter must be separated by space. If the lpFile member specifies a document file, lpParameters should be NULL.
            .hwnd = hWndOwner                   ' Owner window handle
    
            ' Determine launch type (would recommend checking for Vista or greater here also)
            If LaunchElevated = True Then ' And m_OpSys.IsVistaOrGreater = True
                .lpVerb = "runas"
            Else
                .lpVerb = "Open"
            End If
        End With
    
         ExecuteProcess = ShellExecuteEx(SEI)   ' Execute the program, return success or failure
    
        Exit Function
    Err:
        ' TODO: Log Error
        ExecuteProcess = False
    End Function
    
    Private Function PathGetFolder(psPath As String) As String
        On Error Resume Next
        Dim lPos As Long
        lPos = InStrRev(psPath, "\")
        PathGetFolder = Left$(psPath, lPos - 1)
    End Function
    

    【讨论】:

    • 如何在按钮上添加盾牌图标?
    • 没关系,我找到了适用于 VB6 的 BCM_SETSHEILD。如何获得执行操作而不是启动程序的提示。就像它说“Windows 需要您的许可才能继续”而不是“一个身份不明的程序想要访问您的计算机”?运行的语法是什么?
    • 错误记录示例:打开 以输出为 FreeFile
    • 要获得不那么可怕的提示,您需要使用代码签名证书对可执行文件进行签名。 KSoftware 是 Comodo 代码签名证书的知名且可靠的经销商:secure.ksoftware.net/code_signing.html
    • @JoeJordan 你有 singtool 实用程序吗?我需要它,但只是 EXE 而不是完整的 SDK。
    【解决方案2】:

    代码示例确实可以运行,但这里有一个显示“我的第二个实例”方法的简单示例。

    该程序有一个启动静态模块,其中包含一些公共功能,包括一个“提升的操作”处理程序,以及一个只有一个命令按钮的表单:

    模块1.bas

    Option Explicit
    
    Private Const BCM_SETSHIELD As Long = &H160C&
    
    Private Declare Sub InitCommonControls Lib "comctl32" ()
    
    Private Declare Function IsUserAnAdmin Lib "shell32" () As Long
    
    Private Declare Function SendMessage Lib "user32" _
        Alias "SendMessageA" ( _
        ByVal hWnd As Long, _
        ByVal wMsg As Long, _
        ByVal wParam As Long, _
        ByRef lParam As Any) As Long
    
    Private Declare Function ShellExecute Lib "shell32" _
        Alias "ShellExecuteA" ( _
        ByVal hWnd As Long, _
        ByVal lpOperation As String, _
        ByVal lpFile As String, _
        ByVal lpParameters As String, _
        ByVal lpDirectory As String, _
        ByVal nShowCmd As VbAppWinStyle) As Long
    
    Private mblnIsElevated As Boolean
    
    Public Function IsElevated() As Boolean
        IsElevated = mblnIsElevated
    End Function
    
    Public Sub OperationRequiringElevation(ByRef Params As Variant)
        MsgBox "Insert logic here for: " & vbNewLine _
             & Join(Params, vbNewLine)
    End Sub
    
    Public Sub RequestOperation( _
        ByVal hWnd As Long, _
        ByVal Focus As VbAppWinStyle, _
        ByRef Params As Variant)
    
        ShellExecute hWnd, "runas", App.EXEName & ".exe", _
                     Join(Params, " "), CurDir$(), Focus
    End Sub
    
    Public Sub SetShield(ByVal hWnd As Long)
        SendMessage hWnd, BCM_SETSHIELD, 0&, 1&
    End Sub
    
    Private Sub Main()
        If Len(Command$()) > 0 Then
            'Assume we've been run elevated to execute an operation
            'specified as a set of space-delimited strings.
            OperationRequiringElevation Split(Command$(), " ")
        Else
            mblnIsElevated = IsUserAnAdmin()
            InitCommonControls
            Form1.Show
        End If
    End Sub
    

    Form1.frm

    Option Explicit
    
    Private Sub Command1_Click()
        Dim Params As Variant
    
        Params = Array("ReplaceFile", "abc", "123")
        If IsElevated() Then
            OperationRequiringElevation Params
        Else
            RequestOperation hWnd, vbHide, Params
        End If
    End Sub
    
    Private Sub Form_Load()
        If Not IsElevated() Then
            SetShield Command1.hWnd
        End If
    End Sub
    

    应用程序有一个简单的“asInvoker”清单,用于选择 Common Controls 6.0 程序集。

    【讨论】:

      【解决方案3】:

      首先,获取当有人单击按钮时运行的代码,并将其放入单独的 exe 中。更改您的按钮单击代码以使用 ShellExecute 启动 exe。其次,为每个新的 exe 构建外部清单并让它指定 requireAdministrator。第三,向您的按钮发送 BCM_SETSHIELD 消息(您可能需要查找消息 ID 的数值)以使盾牌出现在它们上。

      【讨论】:

      • 我只是建议,与其创建单独的 exe,不如使用命令行参数启动应用程序的第二个实例,表明您只想执行此特定任务,然后退出。
      • 你自己的第二个实例的问题是清单。您希望第二个实例被提升而第一个不被提升。相同的应用程序意味着相同的清单,所以这不起作用。
      • 凯特,你可以使用 ShellExecuteEx 并传递一个 SHELLEXECUTEINFO 结构体,其中 .lpFile 作为应用程序路径,.lpVerb = "runas"。这将以管理员权限启动现有应用程序。
      • 我该怎么做呢?示例?
      【解决方案4】:


      1. 将所有需要提升的代码移到外部进程中。
      2. 向您的按钮发送 BCM_SETSHIELD 消息以添加盾牌图标。
      3. 将清单嵌入到这些进程中,告诉 Windows 它们需要提升。见下文。



      为了强制 Vista 和更高版本在 UAC 中以管理员身份运行 VB6 exe,您必须将清单 xml 作为资源嵌入其中。步骤如下;

      1. 创建清单文件。将其命名为“YourProgram.exe.manifest”,它应包含以下内容。重要的一行是“requestedExecutionLevel”。更改属性以匹配您的 exe。

        <?xml version="1.0" encoding="UTF-8" standalone="yes"?>>
        <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
          <assemblyIdentity
            version="1.0.0.0"
            processorArchitecture="X86"
            name="YourProgram"
            type="win32"
          >
          <description>application description</description>
          <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
            <security
              <requestedPrivileges>
                <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
              </requestedPrivileges>
            </security>
          </trustInfo>
        </assembly>
        
      2. 创建一个名为“YourProgram.exe.manifest.rc”的文件。它应该包含以下内容。

        #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
        #define RT_MANIFEST 24 CREATEPROCESS_MANIFEST_RESOURCE_ID
        RT_MANIFEST "YourProgram.exe.manifest"

      3. 使用 rc.exe 编译您的资源。它默认位于 C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98\Bin。这将创建一个名为 YourProgram.exe.manifest.RES 的文件。语法是;

        rc /r YourProgram.exe.manifest.rc

      4. 将 .RES 文件添加到您的项目中。使用 VB6 中的资源编辑器加载项执行此操作。工具栏上的图标看起来像绿色块。如果您没有该图标,请确保它已在插件管理器中启用。如果不在插件管理器中,则需要在 C:\Program Files\Microsoft Visual Studio\VB98\Wizards\Resedit.dll 上 regsvr32。打开资源编辑器后,单击打开并选择您的 .RES 文件。

      5. 编译您的项目。

      6. 要仔细检查清单是否正确嵌入,您可以使用名为 InspectExe 的工具。在资源管理器中,转到 exe 的属性,如果清单已嵌入,您应该有一个清单选项卡(.Net 程序集也将具有此清单选项卡)。

      7. 尝试在 Vista 或更高版本上运行您的程序。如果确实启用了 UAC,它应该会立即出现提示。

      【讨论】:

      • 我使用的是 Visual Basic 6 Portable,所以它只是 IDE。
      • 没有“便携版”——您使用的是盗版软件。
      • 您不需要这些 RC.EXE 旋转来嵌入应用程序清单。只需将清单文件创建为 ANSI 文本(通常足够接近 UTF-8),确保将其填充为 4 个字节的偶数倍,然后使用 IDE 资源编辑器将其添加为自定义资源并将其类型设置为 #24并将 ID 设置为 #1 并保存。
      • @WindozeNT 如果使用 VB6 Portable 是您问题的一部分,那么它应该在问题中。如果 VB6 Portable 是您问题的一部分,那么它不是一个有效的问题(鼓励使用非法软件)。要么接受当前的(非常好的)答案之一,要么关闭问题。
      猜你喜欢
      • 1970-01-01
      • 2012-09-07
      • 2012-02-04
      • 2021-09-17
      • 1970-01-01
      • 1970-01-01
      • 2015-07-23
      • 1970-01-01
      相关资源
      最近更新 更多