.net 为什么赢了';我的程序不会终止吗?

.net 为什么赢了';我的程序不会终止吗?,.net,compact-framework,process,windows-ce,termination,.net,Compact Framework,Process,Windows Ce,Termination,我有一个.NET Compact Framework应用程序,可以在三台windows机器(桌面windows和两台WinCE机器)上运行,在WinCE设备上,即使调用Application.exit(),进程也不会在退出时终止。除了.NET之外,它还使用一个COM组件(在UI线程上执行所有操作)。如果我在退出后进入调试器,VisualStudio只显示一个线程和一个完全空白的调用堆栈 这可能是什么原因造成的 更新:我的进程在桌面上终止,而不是在WinCE机器上终止。我尝试使用以下代码强制进程终

我有一个.NET Compact Framework应用程序,可以在三台windows机器(桌面windows和两台WinCE机器)上运行,在WinCE设备上,即使调用Application.exit(),进程也不会在退出时终止。除了.NET之外,它还使用一个COM组件(在UI线程上执行所有操作)。如果我在退出后进入调试器,VisualStudio只显示一个线程和一个完全空白的调用堆栈

这可能是什么原因造成的

更新:我的进程在桌面上终止,而不是在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。因此,我使用TerminateProcess(-1,0),因为GetCurrentProcess桌面版本的文档声明它只返回-1

[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有一些奇怪的交互。

< P>只是一个预感-请确保在退出之前调用<代码> CudiialAlgIsId()//Cux>
另外,不要打断调试器,而是创建一个崩溃转储并调试它。不确定这在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);
} 

我有点明白了

我的COM对象将自身设置为通过隐藏窗口获取
WM\u 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,…)
会导致调用
peek message()
的人接收到
WM\u TIMER
消息

现在,当使用计时器的最后一个COM对象被销毁时,计时器和计时器窗口也被销毁:

KillTimer(gTimerWindow, gTimerID);
DestroyWindow(gTimerWindow);
不幸的是,
DestroyWindow()
从未返回。我假设
销毁窗口
中存在某种死锁,但不清楚在Visual Studio中暂停时调用堆栈为何为空。可能是因为COM对象是自动销毁的,而不是由
Marshal.ReleaseComObject()
,所以它在终结器线程中销毁,并且不能从WinCE上的终结器线程调用
DestroyWindow
。像往常一样,微软没有在文档中详细说明这种危险,只是声明“不要在一个线程中使用DestroyWindow来破坏由另一个线程创建的窗口。”

解决方案很简单:根本不要破坏计时器窗口,因为当进程退出时,操作系统会自动破坏它


有趣的事实:如果我调用<代码> SETIMER(null,…)<代码>,而不是<代码> SETIMER(GTimeLeWindows,…)>代码>,则不会发生<代码>销毁窗口< /代码>,但是如果我不调用<代码> StimeT/<代码>,则<>强> >

。这可能是当我的C++应用程序不终止(经常发生恼人的事情)时要尝试的东西。但是.NET应用程序不应该调用它。如何进行崩溃转储并对其进行调试,为什么这比使用VS调试器更好?正如我提到的,我的是单线程应用程序。我写了应用程序中的所有代码,包括COM组件,所以我应该知道。由于进程在桌面上成功终止,WinXP和WinCE上的“进程终止规则”可能有些不同?不,没有不同的规则。COM组件正在创建一个线程,而该线程没有被终止。应用程序使用的唯一特殊设备是COM端口,即使我没有打开COM端口,进程也不会终止。哦,等等,我还使用waveOutOpen等播放声音。我想我可以将其作为一个原因。不,对waveOutOpen电话的评论没有帮助。根据他的帖子,这不太可能是司机的问题。这是一个线程问题,在CF中并不少见。我的COM对象不创建任何线程。我还使用ATL方法FinalRelease()末尾的OutputDebugString确认COM对象已正常释放。我现在了解到这个问题是由于创建了一个窗口来接收WM_定时器消息引起的,所以我将发布一个关于这个问题的答案。