2009-10-29 9 views
2

세 개의 Windows 컴퓨터 (데스크톱 창과 두 대의 WinCE 컴퓨터)에서 실행될 수있는 .NET Compact Framework 응용 프로그램이 있고 WinCE 장치에서 Application.Exit()을 호출하더라도 프로세스가 종료 될 수 없습니다. .NET 외에도 하나의 COM 구성 요소 (UI 스레드의 모든 것을 수행함)를 사용합니다. 나가기 후에 디버거에 침입하면 Visual Studio는 단 하나의 스레드와 완전히 빈 호출 스택을 보여줍니다.왜 내 프로그램이 종료되지 않습니까?

가능한 원인은 무엇입니까?

업데이트 : 내 프로세스가 데스크톱에서는 종료되지만 WinCE 시스템에서는 종료되지 않습니다. 나는 다음과 같은 코드로 종료 프로세스를 강제하려했지만 작동하지 않습니다

또한 내가하려고하면 ExitProcess()와 GetCurrentProcess() 다음과 같은 API를, 그러나 할 수있다 해야하는
[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(); 
} 

그것들을 호출하면 EntryPointNotFoundException이 발생합니다. 따라서 GetCurrentProcess의 데스크톱 버전에 대한 설명서에서 -1을 반환하기 때문에 TerminateProcess (-1, 0)를 사용하고 있습니다.

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

처리되지 않은 예외를 던져도 처리되지 않습니다.

업데이트 2 : 문제를 일으키는 가장 간단한 프로그램은 COM 개체를 만들기 만합니다. COM 구성 요소가 내가 조사 할 .NET 프레임 워크와 기괴한 상호 작용이 있어야합니다 ++

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

C++이 문제가 발생하지 않는 COM 구성 요소를 사용하는 프로그램, 그래서 내 C.

답변

0

내가 정렬의 그것을 알아 냈 : 당신의 간단한 테스트 응용 프로그램은 다음과 같을 것이다 있도록

가 종료하기 전에 Marshal.ReleaseComObject를 호출하십시오.

내 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의 마지막 매개 변수는 콜백 함수로 설정 될 수있다.실제로 타이머 창 대신 콜백을 사용하면 문제가 사라집니다. 그러나, 나는 SetTimer(NULL,...)PeekMessage()를 호출 누군가에 의해 수신에 WM_TIMER 메시지를 일으킬 수있는 주춤에서 이상한 버그를 해결하기 위해 타이머 창을 사용했다.) 이제

를, 타이머를 사용하는 마지막 COM 개체가 소멸 될 때 타이머 및 타이머 창은 파괴됩니다

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

불행하게도, DestroyWindow()는 반환하지 않습니다. DestroyWindow에 교착 상태가 있다고 가정합니다. Visual Studio에서 일시 중지 할 때 호출 스택이 비어있는 이유는 분명하지 않습니다. COM 개체가 Marshal.ReleaseComObject() 대신 자동으로 소멸되기 때문에 finalizer 스레드에서 COM 개체가 삭제되고 WinCE의 finalizer 스레드에서 DestroyWindow을 호출 할 수 없습니다. 평소와 같이 Microsoft는 문서에서 "다른 스레드로 만든 창을 파괴하기 위해 한 스레드에서 DestroyWindow를 사용하지 마십시오"라는 위험을 설명하지 않습니다.

해결 방법은 간단합니다. 타이머 창을 완전히 파괴하지 마십시오. OS가 프로세스를 종료 할 때 자동으로 OS를 파괴하므로.

재미있는 사실 : 내가 대신 SetTimer(gTimerWindow,...)SetTimer(NULL,...)를 호출하는 경우 DestroyWindow의 문제가 발생하지 않습니다,하지만 난 전혀 SetTimer를 호출하지 않는 경우 않습니다가 발생합니다.

1

그냥 직감 - 종료 전에 CoUninitialize()을 호출했는지 확인하십시오. 또한 디버거에 침입하여 크래시 덤프를 만들고 디버깅하는 대신. 이 기능이 CE에서 어떻게 작동하는지 모르지만 Windows에서이 기능을 사용하는 것이 좋습니다.

+0

내 C++ 응용 프로그램이 종료되지 않는 경우가 종종 있습니다.하지만 그럴 필요는 없습니다. – Qwertie

+0

어떻게하면 크래시 덤프를 만들고 디버깅합니까, 왜 VS 디버거를 사용하는 것보다 낫겠습니까? – Qwertie

+0

http://support.microsoft.com/kb/241215 – psychotik

1

앱이 종료되지 않으면 일반적으로 사용자 공간에서 닫을 수없는 핸들이 아직 열려 있음을 의미합니다. 그리고 그 말은 운전수가 불편하다는 뜻입니다.

자세한 내용은 this post을 참조하십시오.

+0

응용 프로그램에서 사용하는 유일한 특수 장치는 COM 포트이며 COM 포트를 열지 않아도 프로세스가 종료되지 않습니다. – Qwertie

+0

오, 나 또한 waveOutOpen 등으로 소리를 재생합니다. 그 원인을 조사 할 수 있다고 생각합니다. – Qwertie

+0

아니, waveOutOpen 호출을 주석 처리하는 것이 도움이되지 않습니다. 그의 게시물을 기반으로 – Qwertie

3

응용 프로그램에서 여전히 실행중인 스레드가있는 것 같습니다.

주 스레드를 종료하기 전에 모든 하위 스레드를 종료했는지 확인하십시오.

+0

앞서 언급 한 것처럼 광산은 단일 스레드 응용 프로그램입니다. COM 구성 요소를 포함하여 응용 프로그램의 모든 코드를 작성 했으므로 알아 두어야합니다. 프로세스가 데스크톱에서 성공적으로 종료되기 때문에 WinXP 및 WinCE의 "프로세스 종료 규칙"간에는 약간의 차이가있을 수 있습니까? – Qwertie

+0

아니요, 다른 규칙은 없습니다. COM 구성 요소가 스레드를 만들고 스레드가 종료되지 않습니다. – ctacke

1

COM 개체가 백그라운드에서 스레드를 만들고 있고 해당 스레드가 종료되지 않습니다. COM 개체가 코드에서 해제되지 않기 때문일 수 있습니다.

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); 
} 
+0

내 COM 개체가 스레드를 만들지 않습니다. ATL 메서드 FinalRelease()의 끝에서 OutputDebugString을 사용하여 COM 개체가 정상적으로 릴리스되었음을 확인했습니다. WM_TIMER 메시지를받을 창을 만들면 문제가 발생한다는 것을 알게되었습니다. 이에 대한 답변을 게시하겠습니다. – Qwertie

관련 문제