0

WPF アプリケーションで c# コードから c++ dll ライブラリにアクセスします。UIスレッドからdllにアクセスする際に問題はありません。しかし、C++ dll のコードの実行中に UI が応答する必要があります。そのため、別のスレッドからアクセスしようとしています。しかし、非 ui スレッドで初めて同じ関数 (ui スレッドから呼び出す) を呼び出そうとすると、関数は戻りますが、戻り値は関数に内部エラーがあることを示します。しかし、UI 以外のスレッドからコードをさらに 1 回か 2 回実行すると、エラー以外の値が正常に返されます。私はdllのソースコードを持っていないので、内部で何が起こっているのかわかりません。

c++ 関数

UINT32 myfunc1()

C# の場合

[DllImport("mydll.dll")]
public static extern uint myfunc1();

UIスレッドでコードに到達する方法

uint errorCode = myfunc1(); // returns 0 means no error occured

非UIスレッドでコードに到達する方法

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, args) => { args.Result = myfunc1(); };
// 1st call args.Result is 10 means internal error ocurred
// 2nd call args.Result is sometimes 0 and sometimes 10
// 3rd or later calls args.Result is 0 means no error occured
worker.RunWorkerCompleted += doSth();
worker.RunWorkerAsync();
4

1 に答える 1

1

スレッドで使用されている Apartment モデルと関係がある可能性があります。

UI スレッドは STA (Single Threaded Apartment) モデルを使用します...同期/シリアル化アクセスのメッセージ ループに依存します。

BackgroundWorkerMTA (Multi-Threaded Apartment) モデルを使用します。

その DLL ライブラリには、おそらくいくつかの COM 呼び出しなど、適切な同期のために UI/STA スレッドで実行されることに依存するコードが含まれている可能性があります。動作する場合と動作しない場合がある理由は、おそらく競合状態にあると考えられます...同期の欠如によるものです。

スレッドが STA であることを指定することは可能ですが、スレッドではありませんBackgroundWorker。なぜなら、それらは によって作成および管理され、ThreadPool常に MTA アパートメント モデルを使用するように設定され、再利用されるなど....およびスレッドであるためです。開始する前にアパートメントの状態を設定する必要があります...その後は変更できません。

代わりに、新しいThreadセットのアパートメントを STA に作成し、メッセージループもポンプします。

于 2013-02-05T17:17:13.560 に答える