好的,我有一个方法可以简单地将Windows事件日志备份为* .evt文件。 在Windows XP x86和x64上的.net2.0中,这很好用,没问题。
我们最近升级到.net4.0(特别是4.0.3),现在这段代码以非常具体的方式失败了。 (在XP x86和x64上失败,Win7工作正常)
如果方法是由事件处理程序中的主GUI线程执行的,那么它可以正常工作。 但是,如果此方法在新的Thread或ThreadPool中执行,则它会因Access Denied错误而失败。
此应用程序以管理员身份运行并访问本地计算机wmi提供程序。
我猜想.net4中有一些新的线程安全性,我不满意或类似的东西。
以下是一些说明问题的示例代码。 这是一个带有3个按钮的表单,处理程序位于最后,说明它何时工作以及何时失败。 它将所有Windows事件日志的副本保存到.. \ Log文件夹。
使用.Net2.0的目标框架编译下面的内容,所有三种调用方法都可以正常工作。 使用.Net4.0.3的目标框架进行编译,最后2个调用方法因Access Denied而失败。
我在这里缺少什么?
public void ExportWindowsEventLogs(object ignored)
{
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_NTEventlogFile");
searcher.Scope.Options.EnablePrivileges = true; // Defaults to False which gives AccessDenied errors so
foreach (ManagementObject oEventLogFile in searcher.Get())
{
string LogName = oEventLogFile["LogfileName"] as string;
if (!String.IsNullOrEmpty(LogName))
{
// Obtain in-parameters for the method
ManagementBaseObject inParams =
oEventLogFile.GetMethodParameters("BackupEventlog");
// Add the input parameters.
string strPath = Application.StartupPath + @"\..\Log\" + LogName + "-Exported.Evt";
inParams["ArchiveFileName"] = strPath;
//Delete the old backup if it exists, as the WMI BackupEventLog method does not overwrite old files.
FileInfo backupFile = new FileInfo(strPath);
if (!backupFile.Directory.Exists)
backupFile.Directory.Create();
else if (backupFile.Exists)
backupFile.Delete();
InvokeMethodOptions options = new InvokeMethodOptions();
// Execute the method and obtain the return values.
//FAILS ON NEXT LINE WITH ACCESS DENIED ERROR,
//but oEventLogFile.ToString() works fine.
ManagementBaseObject outParams =
oEventLogFile.InvokeMethod("BackupEventlog", inParams, null);
object returnValue = oEventLogFile.InvokeMethod("BackupEventlog", new object[] { strPath });
}
}
}
catch(Exception err)
{
MessageBox.Show("An error occurred while trying to execute the WMI method: " + err.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
//WORKS
ExportWindowsEventLogs(null);
}
private void button2_Click(object sender, EventArgs e)
{
//Access Denied error
Thread workerThread = new Thread(new ParameterizedThreadStart(ExportWindowsEventLogs));
workerThread.Priority = ThreadPriority.Lowest;
workerThread.Start(true);
}
private void button3_Click(object sender, EventArgs e)
{
//Access Denied error
System.Threading.ThreadPool.QueueUserWorkItem(ExportWindowsEventLogs, null);
}
更新 这似乎与执行线程的Thread.ApartmentState设置直接相关。 默认情况下,线程是使用ApartmentState.MTA创建的,而主GUI线程是STA线程。 在.Net 4.0中,我的WMI代码在STA线程中运行时有效,但在MTA线程上不起作用。在.Net 2.0中,它适用于两者。
如何让它在.Net 4.0上的MTA线程中运行?我想使用线程池来运行它。