我知道标题有点令人困惑。 所以我的主要问题是:
我有一个应用程序更新另一个应用程序。更新功能结束后,它使用process.start方法启动另一个应用程序
Process.Start(@"C:\Program Files (x86)\XMLMailService\XMLMailWF.exe");
并且第二个更新的程序发送一个简单的outlook interlop
的邮件Microsoft.Office.Interop.Outlook.Application OutlookObject = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.MailItem MailObject = (Microsoft.Office.Interop.Outlook.MailItem)(OutlookObject.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem));
MailObject.To = txtkime.Text;
MailObject.Subject = psubj;
MailObject.Importance = Microsoft.Office.Interop.Outlook.OlImportance.olImportanceNormal;
MailObject.HTMLBody = pbody;
MailObject.Attachments.Add(pdfyolu);
MailObject.Send();
实际上问题与代码无关。但是当我通过双击启动应用程序时,Outlook代码就像一个魅力。但是给了我错误。
因此,当应用程序以process.start开始时,为什么outlook interlop会出错。
编辑:错误翻译=>
检索具有CLSID {0006F03A-0000-0000-C000-000000000046}的组件的COM类工厂由于以下错误而失败:80080005服务器执行失败(HRESULT异常:0x80080005(CO_E_SERVER_EXEC_FAILURE))。
答案 0 :(得分:1)
这与管理员权限或Outlook无关。 COM拒绝封送在不同安全上下文中运行的进程之间的任何调用 - 这可能导致特权升级攻击。由于Outlook是单例,因此不会创建新的COM对象 - 该调用只是转发到已在运行的实例,该实例在不同的安全上下文中运行。
答案 1 :(得分:1)
在这种情况下,我的解决方案是使用cmd和UACHelper库。我的wpf应用程序必须具有管理员权限。我希望用户可以选择通过Outlook发送电子邮件(大多数情况是通过用户UAC启动的)。为了避免UAC冲突,我必须在不使用传递参数的管理员特权的情况下启动cmd。代码如下:
ProcessStartInfo outlookStartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"/c start outlook.exe /c ipm.note /m youremail@microsoft.com",
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true
};
UACHelper.UACHelper.StartLimited(outlookStartInfo);
答案 2 :(得分:0)
对于任何人都有相同的情况我找到了解决方案。
第一个应用程序正在下载zip文件并解压缩它们。解压缩并进行调整后,应用程序会使用process.start(“...”)方法启动下载的应用程序。
所以这里的问题 1)第一个应用程序需要管理员权限才能实现其目的。当它使用Process.Start时,它也会启动具有管理员权限的第二个应用程序。 2)第二个应用程序正在从Outlook客户端发送邮件作为辅助功能。 Outlook不喜欢自动化应用程序。当您尝试使用Outlook interlop作为管理员时,它会给您COM错误。因为outlook需要与app相同的特权级别。规则用户使用outlook而没有管理员权限,因为outlook的搜索功能在管理员模式下无效(上帝知道原因)
有两种解决方案。
1)您可以在没有管理员权限的情况下启动第一个应用。并尝试使用管理员权限启动应用程序的另一个实例,该实例返回某种数据以告知第一个实例它完成了它的工作。然后第一个实例可以使用没有管理员权限的process.start。 但这不适合我,因为第一个应用程序安装在很多计算机上,我是一个懒惰的人。所以ı选择艰难的方式。 2)您无需管理员权限即可重新启动第二个应用。 (这很棘手)
因此,我使用此代码检查管理员权限,如here中所述并重新启动应用
static class Program
{
public static bool IsAdministrator()
{
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
if (IsAdministrator())
{
UserRights.RunAsDesktopUser(@"C:\Program Files (x86)\XMLMailService\XMLMailWF.exe");
Form1.benciktim = true;
Application.Exit();
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
并使用here
中描述的这段精彩代码 public static class UserRights
{
public static void RunAsDesktopUser(string fileName)
{
if (string.IsNullOrWhiteSpace(fileName))
throw new ArgumentException("Value cannot be null or whitespace.", nameof(fileName));
// To start process as shell user you will need to carry out these steps:
// 1. Enable the SeIncreaseQuotaPrivilege in your current token
// 2. Get an HWND representing the desktop shell (GetShellWindow)
// 3. Get the Process ID(PID) of the process associated with that window(GetWindowThreadProcessId)
// 4. Open that process(OpenProcess)
// 5. Get the access token from that process (OpenProcessToken)
// 6. Make a primary token with that token(DuplicateTokenEx)
// 7. Start the new process with that primary token(CreateProcessWithTokenW)
var hProcessToken = IntPtr.Zero;
// Enable SeIncreaseQuotaPrivilege in this process. (This won't work if current process is not elevated.)
try
{
var process = GetCurrentProcess();
if (!OpenProcessToken(process, 0x0020, ref hProcessToken))
return;
var tkp = new TOKEN_PRIVILEGES
{
PrivilegeCount = 1,
Privileges = new LUID_AND_ATTRIBUTES[1]
};
if (!LookupPrivilegeValue(null, "SeIncreaseQuotaPrivilege", ref tkp.Privileges[0].Luid))
return;
tkp.Privileges[0].Attributes = 0x00000002;
if (!AdjustTokenPrivileges(hProcessToken, false, ref tkp, 0, IntPtr.Zero, IntPtr.Zero))
return;
}
finally
{
CloseHandle(hProcessToken);
}
// Get an HWND representing the desktop shell.
// CAVEATS: This will fail if the shell is not running (crashed or terminated), or the default shell has been
// replaced with a custom shell. This also won't return what you probably want if Explorer has been terminated and
// restarted elevated.
var hwnd = GetShellWindow();
if (hwnd == IntPtr.Zero)
return;
var hShellProcess = IntPtr.Zero;
var hShellProcessToken = IntPtr.Zero;
var hPrimaryToken = IntPtr.Zero;
try
{
// Get the PID of the desktop shell process.
uint dwPID;
if (GetWindowThreadProcessId(hwnd, out dwPID) == 0)
return;
// Open the desktop shell process in order to query it (get the token)
hShellProcess = OpenProcess(ProcessAccessFlags.QueryInformation, false, dwPID);
if (hShellProcess == IntPtr.Zero)
return;
// Get the process token of the desktop shell.
if (!OpenProcessToken(hShellProcess, 0x0002, ref hShellProcessToken))
return;
var dwTokenRights = 395U;
// Duplicate the shell's process token to get a primary token.
// Based on experimentation, this is the minimal set of rights required for CreateProcessWithTokenW (contrary to current documentation).
if (!DuplicateTokenEx(hShellProcessToken, dwTokenRights, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out hPrimaryToken))
return;
// Start the target process with the new token.
var si = new STARTUPINFO();
var pi = new PROCESS_INFORMATION();
if (!CreateProcessWithTokenW(hPrimaryToken, 0, fileName, "", 0, IntPtr.Zero, Path.GetDirectoryName(fileName), ref si, out pi))
return;
}
finally
{
CloseHandle(hShellProcessToken);
CloseHandle(hPrimaryToken);
CloseHandle(hShellProcess);
}
}
#region Interop
private struct TOKEN_PRIVILEGES
{
public UInt32 PrivilegeCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public LUID_AND_ATTRIBUTES[] Privileges;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
private struct LUID_AND_ATTRIBUTES
{
public LUID Luid;
public UInt32 Attributes;
}
[StructLayout(LayoutKind.Sequential)]
private struct LUID
{
public uint LowPart;
public int HighPart;
}
[Flags]
private enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}
private enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
private enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
private static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LookupPrivilegeValue(string host, string name, ref LUID pluid);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
private static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TOKEN_PRIVILEGES newst, int len, IntPtr prev, IntPtr relen);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
[DllImport("user32.dll")]
private static extern IntPtr GetShellWindow();
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, uint processId);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool DuplicateTokenEx(IntPtr hExistingToken, uint dwDesiredAccess, IntPtr lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL impersonationLevel, TOKEN_TYPE tokenType, out IntPtr phNewToken);
[DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool CreateProcessWithTokenW(IntPtr hToken, int dwLogonFlags, string lpApplicationName, string lpCommandLine, int dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
#endregion
}