문제

3 개의 Windows 머신 (데스크탑 Wind .NET 외에도 하나의 COM 구성 요소 (UI 스레드의 모든 작업)를 사용합니다. 종료 후 디버거에 침입하면 Visual Studio는 하나의 스레드와 완전히 빈 콜 스택 만 표시됩니다.

이것을 원인 할 수있는 것은 무엇입니까?

업데이트 : 내 프로세스는 데스크탑에서 종료되었지만 Wince Machines는 아닙니다. 프로세스가 다음 코드로 종료하도록 강요하려고했지만 작동하지 않습니다.

[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 구성 요소는 조사 할 .NET 프레임 워크와 기괴한 상호 작용이 있어야합니다.

도움이 되었습니까?

해결책 5

나는 그것을 알아 냈다.

내 COM 객체는 스스로를 설정합니다 WM_TIMER 숨겨진 창을 통한 메시지. 원래:

// 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_TIMER 전화하는 누군가가받는 메시지 PeekMessage().)

이제 타이머를 사용하는 마지막 COM 객체가 파괴되면 타이머와 타이머 창도 파괴됩니다.

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

안타깝게도, DestroyWindow() 결코 돌아 오지 않습니다. 나는 일종의 교착 상태가 있다고 생각합니다 DestroyWindow, Visual Studio에서 일시 중지 할 때 왜 통화 스택이 비어있는지는 확실하지 않습니다. 아마도 com 객체가 Marshal.ReleaseComObject(), 그것은 결승 분기 스레드에서 파괴되고 DestroyWindow Wince의 Finalizer 스레드에서 호출 할 수 없습니다. 평소와 같이 Microsoft는 문서의 위험을 설명하지 않으며, "다른 스레드로 생성 된 창을 파괴하기 위해 한 스레드에서 DestroyWindow를 사용하지 마십시오"라고 말합니다.

솔루션은 간단했습니다. 프로세스가 종료 될 때 OS가 자동으로 파괴되므로 타이머 창을 전혀 파괴하지 마십시오.

재미있는 사실 : 문제 DestroyWindow 내가 전화하면 발생하지 않습니다 SetTimer(NULL,...) 대신에 SetTimer(gTimerWindow,...), 그러나 그러나 그것은 하다 내가 전화하지 않으면 발생합니다 SetTimer 조금도.

다른 팁

애플리케이션에서 여전히 실행중인 스레드가있는 것 같습니다.

메인 스레드를 종료하기 전에 모든 어린이 실을 종료했는지 확인하십시오.

그냥 직감 - 확인하십시오 CoUninitialize() 출구 전에 호출 되나요? 또한 디버거로 나누는 대신 충돌 덤프를 만들고 디버깅하십시오. 이것이 CE에서 어떻게 작동하는지 잘 모르겠지만 그것이 Windows에서 추천 할 것입니다.

앱이 종료되지 않으면 일반적으로 사용자 공간에서 닫을 수없는 핸들이 여전히 열려 있음을 의미합니다. 그리고 그것은 버기 드라이버가 있다는 것을 의미합니다.

보다 이 게시물 세부 사항에 대해.

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);
} 
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top