【发布时间】:2011-08-04 14:44:51
【问题描述】:
我有一个应用程序通过自动化插件执行一些 excel 自动化。 这个加载项是多线程的,所有线程都设法调用 excel COM 对象。因为 excel 在进行多次调用时有时会返回“正忙”异常,所以我将所有调用都包含在“重试”函数中。但是我觉得这是无用的。 我现在尝试在同一个线程上对 excel 对象进行所有调用,以便所有调用都由我“序列化”,从而降低 excel 返回“正忙”异常的风险。 但是,当此线程尝试访问 excel 对象时,应用程序会挂起。我尝试将线程设置为 STA 或 MTA 无济于事。
我用来从单个线程启动所有内容的代码如下: “违规”部分应该在“DoPass”中,也许我调用代表的方式有点错误。
public static class ExcelConnector
{
public static Thread _thread;
private static int ticket;
public static Dictionary<Delegate, int> actionsToRun = new Dictionary<Delegate, int>();
public static Dictionary<int, object> results = new Dictionary<int, object>();
static ExcelConnector()
{
LaunchProcess();
}
public static int AddMethodToRun(Delegate method)
{
lock (actionsToRun)
{
ticket++;
actionsToRun.Add(method, ticket);
}
return ticket;
}
public static bool GetTicketResult(int ticket, out object result)
{
result = null;
if (!results.ContainsKey(ticket))
return false;
else
{
result = results[ticket];
lock (results)
{
results.Remove(ticket);
}
return true;
}
}
public static void LaunchProcess()
{
_thread = new Thread(new ThreadStart(delegate
{
while (true)
{
DoPass();
}
}));
// _thread.SetApartmentState(ApartmentState.STA);
// _thread.IsBackground = true;
_thread.Start();
}
public static void DoPass()
{
try
{
Logger.WriteLine("DoPass enter");
Dictionary<Delegate, int> copy;
lock (actionsToRun)
{
copy = new Dictionary<Delegate, int>(actionsToRun);
}
//run
foreach (var pair in copy)
{
object res = pair.Key.Method.Invoke(
pair.Key.Target, null);
lock (results)
{
results[pair.Value] = res;
}
lock (actionsToRun)
{
actionsToRun.Remove(pair.Key);
}
Thread.Sleep(100);
}
}
catch (Exception e)
{
Logger.WriteError(e);
//mute
}
}
}
编辑:错误可以在一个简单的测试中重现(readline 只是为了给 ExcelConnector 线程工作时间):
var excelApp = new Application();
excelApp = new Application();
excelApp.Visible = true;
excelApp.DisplayAlerts = false;
System.Action act = delegate
{
string s = excelApp.Caption;
Console.WriteLine(s);
};
ExcelConnector.AddMethodToRun(act);
Console.ReadLine();
【问题讨论】:
标签: c# multithreading excel com interop