0
我有一個用C#實現的COM對象,並從StandardOleMarshalObject
繼承來禁用NTA默認行爲。出於某種原因,當我打電話給一個可重入客戶端的服務器時,回調會在另一個線程上結束。爲什麼我的`StandardOleMarshalObject` COM對象是從多個線程調用的?
如何確保所有調用都在主線程上進行?
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IComChat
{
void WriteLine(string text);
void Subscribe(IComChat callback);
}
public class ComChatServer : StandardOleMarshalObject, IComChat
{
private List<IComChat> Clients = new List<IComChat>();
public void WriteLine(string text)
{
foreach (var client in Clients)
{
// this makes a reentrant callback into the calling client
client.WriteLine(text);
}
}
public void Subscribe(IComChat client) => Clients.Add(client);
}
public class ComChatClient : StandardOleMarshalObject, IComChat
{
private IComChat Server;
private Thread MainThread;
public ComChatClient()
{
this.MainThread = Thread.CurrentThread;
this.Server = /* get server by some means */;
this.Server.Subscribe(this);
}
void IComChat.WriteLine(string text)
{
// this throws as the call ends up on a different thread
Contract.Assert(Thread.CurrentThread == MainThread);
Console.WriteLine(text);
}
void IComChat.Subscribe(IComChat callback) => throw new NotSupportedException();
public void WriteLine(string text) => Server.WriteLine(text);
}
public static class Program
{
public static void Main(string[] args)
{
var client = new ComChatClient();
Application.Run(new ChatWindow(client));
}
}
這正是您應該從未**做過的事情。 [STAThread]是一個* promise *,你發誓你的線程行爲良好並且支持非線程安全的代碼。像你的ComChatClient。但是你立即違反了這個承諾,你不會像STA要求的那樣抽出消息循環。所以最初COM創建了一個線程來給你的對象一個安全的家,一個遵循規則。謊言的後果是僵局。可能是非常醜陋的類型,死鎖的終結器線程很難診斷。 –
@HansPassant,應用程序本身在「主」線程上抽取消息。我在示例代碼中錯過了這一點。我自嘲的白癡是一個缺少'STAThreadAttribute'。 – Mitch
Hmya,使用項目模板開始*確實*避免了許多事故。看起來像上世紀的用戶界面也不是那麼漂亮。 –