如何在Vista(.NET)中不提升运行

如何在Vista(.NET)中不提升运行,.net,windows-vista,uac,elevation,.net,Windows Vista,Uac,Elevation,我有一个应用程序,我必须作为管理员运行 该应用程序的一小部分是用Process.start启动其他应用程序 已启动的应用程序也将作为管理员运行,但我更希望它们作为“普通”用户运行 我如何做到这一点 /约翰/来自: 一个经常被问到的问题是如何 从启动未提升的应用程序 提升的过程,或更多 从根本上说,我如何启动 使用我的未提升令牌的进程 一旦我跑高了。自从 没有直接的方法可以做到这一点 这种情况通常可以通过以下方法避免: 按以下方式启动原始应用程序: 标准用户,仅提升这些 应用程序中 要求行政权利。

我有一个应用程序,我必须作为管理员运行

该应用程序的一小部分是用Process.start启动其他应用程序

已启动的应用程序也将作为管理员运行,但我更希望它们作为“普通”用户运行

我如何做到这一点

/约翰/

来自:

一个经常被问到的问题是如何 从启动未提升的应用程序 提升的过程,或更多 从根本上说,我如何启动 使用我的未提升令牌的进程 一旦我跑高了。自从 没有直接的方法可以做到这一点 这种情况通常可以通过以下方法避免: 按以下方式启动原始应用程序: 标准用户,仅提升这些 应用程序中 要求行政权利。这 路总有一条非高架路 可用于启动的进程 其他应用程序如 当前已登录桌面用户。 然而,有时,一个更高的 进程需要另一个进程 应用程序未提升运行。这 可以通过使用任务来完成 Windows Vista中的调度程序。这个 提升的进程可以注册任务 以当前登录的身份运行 桌面用户

下面是一个如何安排未提升流程的示例(同样来自同一链接)

//---------------------------------------------------------------------
//此文件是Microsoft.NET Framework SDK代码示例的一部分。
// 
//版权所有(C)微软公司。版权所有。
// 
//此源代码仅作为Microsoft的补充
//开发工具和/或在线文档。看到这些了吗
//有关Microsoft代码示例的详细信息的资料。
// 
//本规范和信息按原样提供,不提供任何担保
//明示或暗示的种类,包括但不限于
//对产品适销性和/或适用性的默示保证
//特殊目的。
//---------------------------------------------------------------------
/****************************************************************************
*Main.cpp-Task Scheduler V2 COMAPI*组件的示例应用程序:Task Scheduler
*版权所有(c)2002-2003,微软公司
*此示例创建一个要作为当前登录的deskup用户启动的任务。任务注册后立即启动*
****************************************************************************/
#包括“stdafx.h”
#包括
#包括
#包括
#包括
#包括
//包含任务头文件-包含在MSDN的Windows Vista Beta-2 SDK中
#包括
#包括
#包括
#包括
使用名称空间std;
#定义清理\
pRootFolder->Release()\
pTask->Release()\
coninitialize();
HRESULT CreateMyTask(LPCWSTR,wstring);
无效cdecl wmain(内部argc,wchar\u t**argv)
{
wstring wstrExecutablePath;
WCHAR任务名称[20];
HRESULT结果;
如果(argc<2)
{
printf(“\n用法:LaunchApp yourapp.exe”);
返回;
}
//选择随机数作为任务名称
srand((无符号整数)时间(NULL));
wsprintf((LPWSTR)任务名,L“启动%d”,rand();
wstrExecutablePath=argv[1];
结果=CreateMyTask(taskName,wstrExecutablePath);
printf(“\n返回状态:%d\n”,结果);
}
HRESULT CreateMyTask(LPCWSTR wszTaskName,wstring wstrExecutablePath)
{
//  ------------------------------------------------------
//初始化COM。
任务状态任务状态;
int i;
HRESULT hr=coinitializex(NULL,COINIT\u多线程);
如果(失败(小时))
{
printf(“\n初始化失败:%x”,hr);
返回1;
}
//设置通用COM安全级别。
hr=共同初始化安全性(
无效的
-1,
无效的
无效的
RPC_C_认证级别_PKT_隐私,
RPC_C_IMP_LEVEL_模拟,
无效的
0,
无效);
如果(失败(小时))
{
printf(“\n初始化安全失败:%x”,hr);
coninitialize();
返回1;
}
//  ------------------------------------------------------
//创建任务服务的实例。
ITaskService*pService=NULL;
hr=CoCreateInstance(CLSID_任务调度器,
无效的
CLSCTX_INPROC_服务器,
IID_ITaskService,
(无效**)和P服务);
如果(失败(小时))
{
printf(“未能共同创建TaskService类的实例:%x”,hr);
coninitialize();
返回1;
}
//连接到任务服务。
hr=p服务->连接(\u variant\u t(),\u variant\u t(),\u variant\u t(),\u variant\u t());
如果(失败(小时))
{
printf(“ITaskService::连接失败:%x”,hr);
pService->Release();
coninitialize();
返回1;
}
//  ------------------------------------------------------
//获取指向根任务文件夹的指针。此文件夹将保存
//已注册的新任务。
ITaskFolder*pRootFolder=NULL;
hr=pService->GetFolder(\bstr\t(L“\\”),&pRootFolder);
如果(失败(小时))
{
printf(“无法获取根文件夹指针:%x”,hr);
pService->Release();
coninitialize();
返回1;
}
//检查是否已存在相同的任务。如果存在相同的任务,请将其删除。
hr=pRootFolder->DeleteTask(\u bstr\u t(wszTaskName),0);
//创建任务生成器对象以创建任务。
ITaskDefinition*pTask=NULL;
hr=pService->NewTask(0和pTask);
pService->Release();//COM清理。指针不再使用。
如果(失败(小时))
{
printf(“未能共同创建TaskService类的实例:%x”,hr);
pRootFolder->Release();
coninitialize();
返回1;
}
//  ------------------------------------------------------
//扣动扳机
//---------------------------------------------------------------------
//  This file is part of the Microsoft .NET Framework SDK Code Samples.
// 
//  Copyright (C) Microsoft Corporation.  All rights reserved.
// 
//This source code is intended only as a supplement to Microsoft
//Development Tools and/or on-line documentation.  See these other
//materials for detailed information regarding Microsoft code samples.
// 
//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//PARTICULAR PURPOSE.
//---------------------------------------------------------------------

/****************************************************************************
* Main.cpp - Sample application for Task Scheduler V2 COMAPI                * Component: Task Scheduler                          
* Copyright (c) 2002 - 2003, Microsoft Corporation 
* This sample creates a task to that launches as the currently logged on deskup user. The task launches as soon as it is registered.                                                             *
****************************************************************************/
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <comdef.h>
#include <comutil.h>
//Include Task header files - Included in Windows Vista Beta-2 SDK from MSDN
#include <taskschd.h>
#include <conio.h>
#include <iostream>
#include <time.h>

using namespace std;

#define CLEANUP \
pRootFolder->Release();\
        pTask->Release();\
        CoUninitialize();

HRESULT CreateMyTask(LPCWSTR, wstring);

void __cdecl wmain(int argc, wchar_t** argv)
{
wstring wstrExecutablePath;
WCHAR taskName[20];
HRESULT result;

if( argc < 2 )
{
printf("\nUsage: LaunchApp yourapp.exe" );
return;
}

// Pick random number for task name
srand((unsigned int) time(NULL));
wsprintf((LPWSTR)taskName, L"Launch %d", rand());

wstrExecutablePath = argv[1];

result = CreateMyTask(taskName, wstrExecutablePath);
printf("\nReturn status:%d\n", result);

}
HRESULT CreateMyTask(LPCWSTR wszTaskName, wstring wstrExecutablePath)
{
    //  ------------------------------------------------------
    //  Initialize COM.
TASK_STATE taskState;
int i;
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeEx failed: %x", hr );
        return 1;
    }

    //  Set general COM security levels.
    hr = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        0,
        NULL);

    if( FAILED(hr) )
    {
        printf("\nCoInitializeSecurity failed: %x", hr );
        CoUninitialize();
        return 1;
    }

    //  ------------------------------------------------------
    //  Create an instance of the Task Service. 
    ITaskService *pService = NULL;
    hr = CoCreateInstance( CLSID_TaskScheduler,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_ITaskService,
                           (void**)&pService );  
    if (FAILED(hr))
    {
        printf("Failed to CoCreate an instance of the TaskService class: %x", hr);
        CoUninitialize();
        return 1;
    }

    //  Connect to the task service.
    hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
    if( FAILED(hr) )
    {
        printf("ITaskService::Connect failed: %x", hr );
        pService->Release();
        CoUninitialize();
        return 1;
    }

    //  ------------------------------------------------------
    //  Get the pointer to the root task folder.  This folder will hold the
    //  new task that is registered.
    ITaskFolder *pRootFolder = NULL;
    hr = pService->GetFolder( _bstr_t( L"\\") , &pRootFolder );
    if( FAILED(hr) )
    {
        printf("Cannot get Root Folder pointer: %x", hr );
        pService->Release();
        CoUninitialize();
        return 1;
    }

    //  Check if the same task already exists. If the same task exists, remove it.
    hr = pRootFolder->DeleteTask( _bstr_t( wszTaskName), 0  );

    //  Create the task builder object to create the task.
    ITaskDefinition *pTask = NULL;
    hr = pService->NewTask( 0, &pTask );

    pService->Release();  // COM clean up.  Pointer is no longer used.
    if (FAILED(hr))
    {
        printf("Failed to CoCreate an instance of the TaskService class: %x", hr);
        pRootFolder->Release();
        CoUninitialize();
        return 1;
    }


    //  ------------------------------------------------------
    //  Get the trigger collection to insert the registration trigger.
    ITriggerCollection *pTriggerCollection = NULL;
    hr = pTask->get_Triggers( &pTriggerCollection );
    if( FAILED(hr) )
    {
        printf("\nCannot get trigger collection: %x", hr );
  CLEANUP
        return 1;
    }

    //  Add the registration trigger to the task.
    ITrigger *pTrigger = NULL;

    hr = pTriggerCollection->Create( TASK_TRIGGER_REGISTRATION, &pTrigger );     
    pTriggerCollection->Release();  // COM clean up.  Pointer is no longer used.
    if( FAILED(hr) )
    {
        printf("\nCannot add registration trigger to the Task %x", hr );
        CLEANUP
        return 1;
    }
    pTrigger->Release();

    //  ------------------------------------------------------
    //  Add an Action to the task.     
    IExecAction *pExecAction = NULL;
    IActionCollection *pActionCollection = NULL;

    //  Get the task action collection pointer.
    hr = pTask->get_Actions( &pActionCollection );
    if( FAILED(hr) )
    {
        printf("\nCannot get Task collection pointer: %x", hr );
        CLEANUP
        return 1;
    }

    //  Create the action, specifying that it is an executable action.
    IAction *pAction = NULL;
    hr = pActionCollection->Create( TASK_ACTION_EXEC, &pAction );
    pActionCollection->Release();  // COM clean up.  Pointer is no longer used.
    if( FAILED(hr) )
    {
        printf("\npActionCollection->Create failed: %x", hr );
        CLEANUP
        return 1;
    }

    hr = pAction->QueryInterface( IID_IExecAction, (void**) &pExecAction );
    pAction->Release();
    if( FAILED(hr) )
    {
        printf("\npAction->QueryInterface failed: %x", hr );
        CLEANUP
        return 1;
    }

    //  Set the path of the executable to the user supplied executable.
   hr = pExecAction->put_Path( _bstr_t( wstrExecutablePath.c_str() ) );  

    if( FAILED(hr) )
    {
        printf("\nCannot set path of executable: %x", hr );
        pExecAction->Release();
        CLEANUP
        return 1;
    }
    hr = pExecAction->put_Arguments( _bstr_t( L"" ) );  

   if( FAILED(hr) )
    {
        printf("\nCannot set arguments of executable: %x", hr );
        pExecAction->Release();
        CLEANUP
        return 1;
    }

    //  ------------------------------------------------------
    //  Save the task in the root folder.
    IRegisteredTask *pRegisteredTask = NULL;
    hr = pRootFolder->RegisterTaskDefinition(
            _bstr_t( wszTaskName ),
            pTask,
      TASK_CREATE, 
_variant_t(_bstr_t( L"S-1-5-32-545")),//Well Known SID for \\Builtin\Users group
_variant_t(), 
TASK_LOGON_GROUP,
            _variant_t(L""),
            &pRegisteredTask);
    if( FAILED(hr) )
    {
        printf("\nError saving the Task : %x", hr );
        CLEANUP
        return 1;
    }
    printf("\n Success! Task successfully registered. " );
    for (i=0; i<100; i++)//give 10 seconds for the task to start
{
pRegisteredTask->get_State(&taskState);
if (taskState == TASK_STATE_RUNNING)
{
printf("\nTask is running\n");
break;
}
Sleep(100);
}
if (i>= 100) printf("Task didn't start\n");

    //Delete the task when done
    hr = pRootFolder->DeleteTask(
            _bstr_t( wszTaskName ),
            NULL);
    if( FAILED(hr) )
    {
        printf("\nError deleting the Task : %x", hr );
        CLEANUP
        return 1;
    }

    printf("\n Success! Task successfully deleted. " );

//  Clean up.
    CLEANUP
    CoUninitialize();
    return 0;
}
CreateSaferProcess(@"calc.exe", "", SaferLevel.NormalUser);
//http://odetocode.com/Blogs/scott/archive/2004/10/28/602.aspx
public static void CreateSaferProcess(String fileName, String arguments, SaferLevel saferLevel)
{
   IntPtr saferLevelHandle = IntPtr.Zero;

   //Create a SaferLevel handle to match what was requested
   if (!WinSafer.SaferCreateLevel(
         SaferLevelScope.User, 
         saferLevel, 
         SaferOpen.Open, 
         out saferLevelHandle, 
         IntPtr.Zero))
   {
      throw new Win32Exception(Marshal.GetLastWin32Error());
   }
   try
   {
      //Generate the access token to use, based on the safer level handle.
      IntPtr hToken = IntPtr.Zero;

      if (!WinSafer.SaferComputeTokenFromLevel(
            saferLevelHandle,  // SAFER Level handle
            IntPtr.Zero,       // NULL is current thread token.
            out hToken,        // Target token
            SaferTokenBehaviour.Default,      // No flags
            IntPtr.Zero))      // Reserved
      {
         throw new Win32Exception(Marshal.GetLastWin32Error());
      }
      try
      {
         //Now that we have a security token, we can lauch the process
         //using the standard CreateProcessAsUser API
         STARTUPINFO si = new STARTUPINFO();
         si.cb = Marshal.SizeOf(si);
         si.lpDesktop = String.Empty;

         PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

         // Spin up the new process
         Boolean bResult = Windows.CreateProcessAsUser(
               hToken,
               fileName,
               arguments,
               IntPtr.Zero, //process attributes
               IntPtr.Zero, //thread attributes
               false, //inherit handles
               0, //CREATE_NEW_CONSOLE
               IntPtr.Zero, //environment
               null, //current directory
               ref si, //startup info
               out pi); //process info

         if (!bResult)
            throw new Win32Exception(Marshal.GetLastWin32Error());

         if (pi.hProcess != IntPtr.Zero)
            Windows.CloseHandle(pi.hProcess);

         if (pi.hThread != IntPtr.Zero)
            Windows.CloseHandle(pi.hThread);
      }
      finally
      {
         if (hToken != IntPtr.Zero)
            Windows.CloseHandle(hToken);
      }
   }
   finally
   {
      WinSafer.SaferCloseLevel(saferLevelHandle);
   }
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace PInvoke
{
   public class WinSafer
   {
      /// <summary>
      /// The SaferCreateLevel function opens a SAFER_LEVEL_HANDLE.
      /// </summary>
      /// <param name="scopeId">The scope of the level to be created.</param>
      /// <param name="levelId">The level of the handle to be opened.</param>
      /// <param name="openFlags">Must be SaferOpenFlags.Open</param>
      /// <param name="levelHandle">The returned SAFER_LEVEL_HANDLE. When you have finished using the handle, release it by calling the SaferCloseLevel function.</param>
      /// <param name="reserved">This parameter is reserved for future use. IntPtr.Zero</param>
      /// <returns></returns>
      [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
      public static extern bool SaferCreateLevel(SaferLevelScope scopeId, SaferLevel levelId, SaferOpen openFlags,
            out IntPtr levelHandle, IntPtr reserved);

      /// <summary>
      /// The SaferComputeTokenFromLevel function restricts a token using restrictions specified by a SAFER_LEVEL_HANDLE.
      /// </summary>
      /// <param name="levelHandle">SAFER_LEVEL_HANDLE that contains the restrictions to place on the input token. Do not pass handles with a LevelId of SAFER_LEVELID_FULLYTRUSTED or SAFER_LEVELID_DISALLOWED to this function. This is because SAFER_LEVELID_FULLYTRUSTED is unrestricted and SAFER_LEVELID_DISALLOWED does not contain a token.</param>
      /// <param name="inAccessToken">Token to be restricted. If this parameter is NULL, the token of the current thread will be used. If the current thread does not contain a token, the token of the current process is used.</param>
      /// <param name="outAccessToken">The resulting restricted token.</param>
      /// <param name="flags">Specifies the behavior of the method.</param>
      /// <param name="lpReserved">Reserved for future use. This parameter should be set to IntPtr.EmptyParam.</param>
      /// <returns></returns>
      [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
      public static extern bool SaferComputeTokenFromLevel(IntPtr levelHandle, IntPtr inAccessToken,
            out IntPtr outAccessToken, SaferTokenBehaviour flags, IntPtr lpReserved);

      /// <summary>
      /// The SaferCloseLevel function closes a SAFER_LEVEL_HANDLE that was opened by using the SaferIdentifyLevel function or the SaferCreateLevel function.</summary>
      /// <param name="levelHandle">The SAFER_LEVEL_HANDLE to be closed.</param>
      /// <returns>TRUE if the function succeeds; otherwise, FALSE. For extended error information, call GetLastWin32Error.</returns>
      [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
      public static extern bool SaferCloseLevel(IntPtr levelHandle);
   } //class WinSafer

   /// <summary>
   /// Specifies the behaviour of the SaferComputeTokenFromLevel method
   /// </summary>
   public enum SaferTokenBehaviour : uint
   {
      /// <summary></summary>
      Default = 0x0,
      /// <summary>If the OutAccessToken parameter is not more restrictive than the InAccessToken parameter, the OutAccessToken parameter returns NULL.</summary>
      NullIfEqual = 0x1,
      /// <summary></summary>
      CompareOnly = 0x2,
      /// <summary></summary>
      MakeInert = 0x4,
      /// <summary></summary>
      WantFlags = 0x8
   }

   /// <summary>
   /// The level of the handle to be opened.
   /// </summary>
   public enum SaferLevel : uint
   {
      /// <summary>Software will not run, regardless of the user rights of the user.</summary>
      Disallowed = 0,
      /// <summary>Allows programs to execute with access only to resources granted to open well-known groups, blocking access to Administrator and Power User privileges and personally granted rights.</summary>
      Untrusted = 0x1000,
      /// <summary>Software cannot access certain resources, such as cryptographic keys and credentials, regardless of the user rights of the user.</summary>
      Constrained = 0x10000,
      /// <summary>Allows programs to execute as a user that does not have Administrator or Power User user rights. Software can access resources accessible by normal users.</summary>
      NormalUser = 0x20000,
      /// <summary>Software user rights are determined by the user rights of the user.</summary>
      FullyTrusted = 0x40000
   }

   /// <summary>
   /// The scope of the level to be created.
   /// </summary>
   public enum SaferLevelScope : uint
   {
      /// <summary>The created level is scoped by computer.</summary>
      Machine = 1,
      /// <summary>The created level is scoped by user.</summary>
      User = 2
   }

   public enum SaferOpen : uint
   {
      Open = 1
   }
} //namespace PInvoke
// Get the service on the local machine
using (var ts = new TaskService())
{
     const string taskName = "foo";

     // Create a new task definition and assign properties
     var td = ts.NewTask();
     td.RegistrationInfo.Description = "start foo.exe as limited user";

     // Create an action that will launch foo.exe, with argument bar in workingdir C:\\
     td.Actions.Add(new ExecAction("C:\\foo.exe", "bar", "C:\\"));

     td.Settings.Priority = ProcessPriorityClass.Normal;

     // run with limited token
     td.Principal.RunLevel = TaskRunLevel.LUA;

     td.Settings.AllowDemandStart = true;

     td.Settings.DisallowStartIfOnBatteries = false;

     td.Settings.StopIfGoingOnBatteries = false;

     // Register the task in the root folder
     var ret = ts.RootFolder.RegisterTaskDefinition(taskName, td);

     var fooTask = ts.FindTask(taskName, true);
     if (null != fooTask )
     {
         if (fooTask.Enabled)
         {
             fooTask.Run();

             Thread.Sleep(TimeSpan.FromSeconds(1));

             // find process and wait for Exit
             var processlist = Process.GetProcesses();

             foreach(var theprocess in processlist)
             {
                 if (theprocess.ProcessName != "foo")
                    continue;

                 theprocess.WaitForExit();
                 break;
             }
         }
    }

    // Remove the task we just created
    ts.RootFolder.DeleteTask(taskName);
}
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Runtime.InteropServices;

namespace Microsoft.NodejsTools.SharedProject
{
    /// <summary>
    /// Utility for accessing window IShell* interfaces in order to use them to launch a process unelevated
    /// </summary>
    internal class SystemUtility
    {
        /// <summary>
        /// We are elevated and should launch the process unelevated. We can't create the
        /// process directly without it becoming elevated. So to workaround this, we have
        /// explorer do the process creation (explorer is typically running unelevated).
        /// </summary>
        internal static void ExecuteProcessUnElevated(string process, string args, string currentDirectory = "")
        {
            var shellWindows = (IShellWindows)new CShellWindows();

            // Get the desktop window
            object loc = CSIDL_Desktop;
            object unused = new object();
            int hwnd;
            var serviceProvider = (IServiceProvider)shellWindows.FindWindowSW(ref loc, ref unused, SWC_DESKTOP, out hwnd, SWFO_NEEDDISPATCH);

            // Get the shell browser
            var serviceGuid = SID_STopLevelBrowser;
            var interfaceGuid = typeof(IShellBrowser).GUID;
            var shellBrowser = (IShellBrowser)serviceProvider.QueryService(ref serviceGuid, ref interfaceGuid);

            // Get the shell dispatch
            var dispatch = typeof(IDispatch).GUID;
            var folderView = (IShellFolderViewDual)shellBrowser.QueryActiveShellView().GetItemObject(SVGIO_BACKGROUND, ref dispatch);
            var shellDispatch = (IShellDispatch2)folderView.Application;

            // Use the dispatch (which is unelevated) to launch the process for us
            shellDispatch.ShellExecute(process, args, currentDirectory, string.Empty, SW_SHOWNORMAL);
        }

        /// <summary>
        /// Interop definitions
        /// </summary>
        private const int CSIDL_Desktop = 0;
        private const int SWC_DESKTOP = 8;
        private const int SWFO_NEEDDISPATCH = 1;
        private const int SW_SHOWNORMAL = 1;
        private const int SVGIO_BACKGROUND = 0;
        private readonly static Guid SID_STopLevelBrowser = new Guid("4C96BE40-915C-11CF-99D3-00AA004AE837");

        [ComImport]
        [Guid("9BA05972-F6A8-11CF-A442-00A0C90A8F39")]
        [ClassInterfaceAttribute(ClassInterfaceType.None)]
        private class CShellWindows
        {
        }

        [ComImport]
        [Guid("85CB6900-4D95-11CF-960C-0080C7F4EE85")]
        [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
        private interface IShellWindows
        {
            [return: MarshalAs(UnmanagedType.IDispatch)]
            object FindWindowSW([MarshalAs(UnmanagedType.Struct)] ref object pvarloc, [MarshalAs(UnmanagedType.Struct)] ref object pvarlocRoot, int swClass, out int pHWND, int swfwOptions);
        }

        [ComImport]
        [Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IServiceProvider
        {
            [return: MarshalAs(UnmanagedType.Interface)]
            object QueryService(ref Guid guidService, ref Guid riid);
        }

        [ComImport]
        [Guid("000214E2-0000-0000-C000-000000000046")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IShellBrowser
        {
            void VTableGap01(); // GetWindow
            void VTableGap02(); // ContextSensitiveHelp
            void VTableGap03(); // InsertMenusSB
            void VTableGap04(); // SetMenuSB
            void VTableGap05(); // RemoveMenusSB
            void VTableGap06(); // SetStatusTextSB
            void VTableGap07(); // EnableModelessSB
            void VTableGap08(); // TranslateAcceleratorSB
            void VTableGap09(); // BrowseObject
            void VTableGap10(); // GetViewStateStream
            void VTableGap11(); // GetControlWindow
            void VTableGap12(); // SendControlMsg
            IShellView QueryActiveShellView();
        }

        [ComImport]
        [Guid("000214E3-0000-0000-C000-000000000046")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IShellView
        {
            void VTableGap01(); // GetWindow
            void VTableGap02(); // ContextSensitiveHelp
            void VTableGap03(); // TranslateAcceleratorA
            void VTableGap04(); // EnableModeless
            void VTableGap05(); // UIActivate
            void VTableGap06(); // Refresh
            void VTableGap07(); // CreateViewWindow
            void VTableGap08(); // DestroyViewWindow
            void VTableGap09(); // GetCurrentInfo
            void VTableGap10(); // AddPropertySheetPages
            void VTableGap11(); // SaveViewState
            void VTableGap12(); // SelectItem

            [return: MarshalAs(UnmanagedType.Interface)]
            object GetItemObject(UInt32 aspectOfView, ref Guid riid);
        }

        [ComImport]
        [Guid("00020400-0000-0000-C000-000000000046")]
        [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
        private interface IDispatch
        {
        }

        [ComImport]
        [Guid("E7A1AF80-4D96-11CF-960C-0080C7F4EE85")]
        [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
        private interface IShellFolderViewDual
        {
            object Application { [return: MarshalAs(UnmanagedType.IDispatch)] get; }
        }

        [ComImport]
        [Guid("A4C6892C-3BA9-11D2-9DEA-00C04FB16162")]
        [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
        public interface IShellDispatch2
        {
            void ShellExecute([MarshalAs(UnmanagedType.BStr)] string File, [MarshalAs(UnmanagedType.Struct)] object vArgs, [MarshalAs(UnmanagedType.Struct)] object vDir, [MarshalAs(UnmanagedType.Struct)] object vOperation, [MarshalAs(UnmanagedType.Struct)] object vShow);
        }
    }
}