如何从提升的进程中调用未提升的进程

How to call an unelevated process from an elevated process

我看过相关社区posts*

在提升的 Excel 中(Excel 必须 运行 提升),VBA 打开 MS Word。 MS Word VBA 重新启动之前禁用的 OneDrive。问题已提升 Excel 导致 Word 被提升,从而导致调用 OneDrive 提升,从而导致 OneDrive 抛出错误。因此,我希望 Excel 以未提升的方式打开 Word。代码如下。

*P.S.

我阅读了所有社区 posts,还有 37 个结果,当我搜索我的问题的变体时出现,但我找不到任何适用的,可能是因为我的情况是 VBA 或者我没有受过足够的教育,无法理解如何将其他答案转化为我需要的答案。我尝试过,但我是 100% 自学的,复制了一些我不完全理解的代码,例如下面 social.msdn 的 Hans Vogelaar 的代码。

这是ExcelVBA

Sub Open_Word_DocM()
'Credit: Hans Vogelaar https://social.msdn.microsoft.com/Forums/en-US/29265e5f-8df9-4cab-8984-1afb9b110d2f/in-excel-use-vba-to-check-if-a-word-document-is-open?forum=isvvba

Dim Wd As Object
Dim InstrDoc As Object
Dim f As Boolean

Const strpath = "C:\Users\ssttr\OneDrive\Documents\Testing\ReStartOneDrive.docm"

On Error Resume Next

9990100:
Set InstrDoc = GetObject(strpath)

If InstrDoc Is Nothing Then
    Set Wd = GetObject(, "Word.Application")
    If Wd Is Nothing Then
        Set Wd = CreateObject("Word.Application")
        If Wd Is Nothing Then
            Call ErrorLog
                If mErr = 4 Then
                    GoTo 9990100
                End If
        End If
        f = True
    End If

9990200:
    Set InstrDoc = Wd.Documents.Open(strpath)

    If InstrDoc Is Nothing Then
        Call ErrorLog
        If mErr = 4 Then
            GoTo 9990200
        End If
        If f Then
            Wd.Quit
        End If
        Exit Sub
    End If
    
    Wd.Visible = True

Else
    With InstrDoc.Parent
        .Visible = True
        .Activate
    End With
End If
End Sub

这是 Word .docm VBA

Sub Restart_OneDrive()
    Dim shell
    Set shell = CreateObject("wscript.shell")
    shell.Run """C:\Users\ssttr\OneDrive\Documents\Investing\Automation\Static Inputs\OneDrive Restart.bat"""
        'batch file contents: start %LOCALAPPDATA%\Microsoft\OneDrive\OneDrive.exe /background
End Sub

这是 OneDrive 错误

OneDrive 无法 运行 使用完全管理员权限
请在没有管理员权限的情况下重新启动 OneDrive。

FWIW 1

SysInternals Process Explorer 显示 Word 的父级为 svchost.exe:

FWIW 2

我一直禁用 UAC。

FWIW 3

我通过以下方式为所有用户调用 Excel 作为管理员:属性 > 兼容性选项卡 > 更改所有用户的设置按钮 > 以管理员身份启用 运行 此程序:

关注论坛?

这个问题的更详细版本是 post2021 年 12 月 How to Restart OneDrive via VBA When Running Excel Elevated. I think it was TLDR bc I received no responses. A couple months ago, an earlier, different approach to this problem was at Start OneDrive Under Full Admin Rights。 post,也是 TLDR,确实收到了一个响应,我尝试过但无法成功实施的响应。如果有一条论坛规则(我找不到)反对 post 不止一次讨论类似的主题,那么请删除过于冗长的规则并请留下这个。谢谢。

简而言之:从资源管理器调用 OneDrive(它有一个在这种情况下很有用的限制;它只调用 exe 作为 non-admin)然后摆脱不需要的文件资源管理器 window.

这有点麻烦,但确实有效。

更改 MS Word VBA(以及相关的批处理文件,如 VBA 评论中所述)如下(我没有再次将其编辑为我最初发布的简化版本):

'The #-prefixed Declarations are used to enable the Windows API Sleep function (since Word does not allow Excel's Application.Wait method)
'VBA 7 replaces the VBA code base in Office 2007 and earlier versions. VBA 7 is available in both the 32-bit and 64-bit versions of Office. It provides two conditional compilation constants:
'VBA7 - Helps ensure the backward compatibility of your code by testing whether your application is using VBA 7 or the previous version of VBA.
'Win64 Tests whether code is running as 32-bit or 64-bit.
'per https://www.myonlinetraininghub.com/pausing-or-delaying-vba-using-wait-sleep-or-a-loop
#If VBA7 And Win64 Then
    ' For 64bit version of Excel
    Public Declare PtrSafe Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As LongPtr)
#Else
    ' For 32bit version of Excel
    Public Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)
#End If

Sub Restart_OneDrive()
'Restarts OneDrive via batch file command.
'Then closes the unwanted Explorer.exe window after a 5000 [ms] sleep.
'NOTE: this method is necessary to solve the problem of invoking OneDrive
    '(which will not run with elevated privileges) from elevated Word
    '(elevated bc called from elevated Excel (elevated bc this is the only way
    'Excel PID functions can control VLIA).
'https://www.myonlinetraininghub.com/pausing-or-delaying-vba-using-wait-sleep-or-a-loop
'https://docs.microsoft.com/en-us/previous-versions/office/developer/office-2010/ee691831(v=office.14)?redirectedfrom=MSDN

Dim shellt
Set shellt = CreateObject("wscript.shell")

shellt.Run """C:\Users\ssttr\OneDrive\Documents\Automation\Static Inputs\OneDrive Restart.bat"""
    'batch file contents: explorer %LOCALAPPDATA%\Microsoft\OneDrive\OneDrive.exe
Dim waitOnReturn As Boolean: waitOnReturn = True 'Waits for shell to finish before returning to VBA
   
Sleep 5000 'in milliseconds (ref Declarations)

'Now kill the unwanted File Explorer window
    'Note that in order to not kill all Explorer.exe windows, TaskKill's syntax requires:
        '(1) each explorer window open in a separate process
            'View > Folder Options > View Tab > enable Display the full path in the titlebar
        '(2) the full path in title bar has been enabled in Folder view
            'View > Folder Options > View Tab > enable Launch folder windows in a separate process
        '^per https://superuser.com/questions/1263315/how-to-close-a-particular-opened-folder-using-cmd-or-batch-file

Call shell("taskkill /fi ""IMAGENAME eq explorer.exe"" /fi ""windowtitle eq OneDrive - Personal""")
waitOnReturn = True 'Waits for shell to finish before returning to VBA

End Sub