2

3台のWindowsマシン(デスクトップウィンドウと2台のWinCEマシン)で実行できる.NET Compact Frameworkアプリがあり、WinCEデバイスでは、Application.Exit()を呼び出しても、プロセスが終了時に終了することはありません。.NETに加えて、1つのCOMコンポーネント(UIスレッドですべてを実行)を使用します。終了後にデバッガーに侵入すると、VisualStudioには1つのスレッドと完全に空白の呼び出しスタックのみが表示されます。

何が原因でしょうか?

更新:私のプロセスはデスクトップで終了していますが、WinCEマシンでは終了していません。次のコードでプロセスを強制的に終了しようとしましたが、機能しません。

[DllImport("coredll.dll")]
static extern int TerminateProcess(IntPtr hProcess, uint uExitCode);

static public void ExitProcess()
{
    if (Platform.IsWindowsCE)
        TerminateProcess(new IntPtr(-1), 0);
    Application.Exit();
}

次のようなExitProcess()およびGetCurrentProcess()APIもあるはずですが、それらを呼び出そうとすると、EntryPointNotFoundExceptionが発生します。したがって、デスクトップバージョンのGetCurrentProcessのドキュメントには、単に-1が返されると記載されているため、TerminateProcess(-1、0)を使用しています。

[DllImport("coredll.dll")]
static extern int ExitProcess(IntPtr hProcess);
[DllImport("coredll.dll")]
static extern IntPtr GetCurrentProcess();

未処理の例外をスローしても、それは行われません。

更新2:問題を引き起こす最も単純なプログラムは、COMオブジェクトを作成するだけです。

static void Main()
{
    new FastNavLib.MapControl();
}

COMコンポーネントを使用するC++プログラムはこの動作を示さないため、私のC ++ COMコンポーネントは、調査する.NETFrameworkとの奇妙な相互作用を持っている必要があります。

4

5 に答える 5

3

アプリケーションでまだいくつかのスレッドが実行されているように見えます。

メインスレッドを終了する前に、すべての子スレッドを終了していることを確認してください。

于 2009-11-02T11:43:29.913 に答える
1

ただの予感-CoUninitialize()終了する前に呼び出されることを確認しますか?また、デバッガーに侵入する代わりに、クラッシュダンプを作成し、それをデバッグします。これがCEでどのように機能するかはわかりませんが、Windowsではそれをお勧めします。

于 2009-10-29T16:47:06.490 に答える
1

アプリが終了しない場合、それは通常、ユーザースペースから閉じることができないハンドルがまだ開いていることを意味します。そして、それはバグのあるドライバーがいることを意味します。

詳細については、この投稿を参照してください。

于 2009-10-29T21:17:48.913 に答える
1

COMオブジェクトはバックグラウンドでスレッドを作成しており、そのスレッドは終了していません。これは、COMオブジェクトがコードでリリースされていないことが原因である可能性があります。

終了する前にMarshal.ReleaseComObjectを呼び出してみてください。そうすると、単純なテストアプリは次のようになります。

static void Main() 
{ 
    // create the COM object
    var obj = new FastNavLib.MapControl(); 

    // simulate doing stuff
    Thread.Sleep(1000);

    // release the COM object
    Marshal.ReleaseComObject(obj);
} 
于 2010-06-07T16:56:12.483 に答える
0

私はそれを理解しました。

WM_TIMER私のCOMオブジェクトは、非表示のウィンドウからメッセージを取得するように設定されています。基本的に:

// Register window class
WNDCLASS wc;
memset(&wc, 0, sizeof(wc));
wc.lpfnWndProc = &WinCeTimerProc;
wc.lpszClassName = _T("FastNavTimerDummyWindow");
// Create window
gTimerWindow = CreateWindow(wc.lpszClassName, wc.lpszClassName, 
    WS_OVERLAPPED, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), NULL);
gTimerID = SetTimer(gTimerWindow, 88, gTimerIntervalMs, NULL);

(専門家は、タイマーメッセージを受信するためにタイマーウィンドウは必要ないと指摘するかもしれません。の最後のパラメーターはSetTimerコールバック関数に設定できます。実際、タイマーウィンドウの代わりにコールバックを使用すると、問題は解消されます!ただし、 WinCEの奇妙なバグを回避するには、タイマーウィンドウを使用する必要がありました。このバグにより、呼び出し元の誰かがメッセージを受信するSetTimer(NULL,...)可能性があります。)WM_TIMERPeekMessage()

これで、タイマーを使用する最後のCOMオブジェクトが破棄されると、タイマーとタイマーウィンドウも破棄されます。

KillTimer(gTimerWindow, gTimerID);
DestroyWindow(gTimerWindow);

残念ながら、DestroyWindow()二度と戻りません。DestroyWindowVisual Studioで一時停止したときに呼び出しスタックが空白になる理由は明らかではありませんが、に何らかのデッドロックがあると思います。おそらく、COMオブジェクトはによってMarshal.ReleaseComObject()ではなく自動的に破棄されるため、ファイナライザスレッドで破棄され、DestroyWindowWinCEのファイナライザスレッドから呼び出すことはできません。いつものように、Microsoftはドキュメントに危険性を明記しておらず、「あるスレッドでDestroyWindowを使用して、別のスレッドで作成されたウィンドウを破棄しないでください」とだけ述べています。

解決策は単純でした。プロセスが終了するとOSが自動的にタイマーウィンドウを破棄するため、タイマーウィンドウをまったく破棄しないでください。

おもしろい事実:の代わりDestroyWindowに電話をかけた場合は問題は発生しませんが、まったく電話をかけなかった場合は問題が発生します。SetTimer(NULL,...)SetTimer(gTimerWindow,...)SetTimer

于 2010-06-07T21:12:10.383 に答える