简体   繁体   English

为什么我的程序不会终止?

[英]Why won't my program terminate?

I have a .NET Compact Framework app that can runs on three windows machines (Desktop windows and two WinCE machines) and on the WinCE devices, the process never terminates on exit, even if I call Application.Exit(). 我有一个.NET Compact Framework应用程序,它可以在三台Windows机器(台式机窗口和两台WinCE机器)和WinCE设备上运行,即使我调用Application.Exit(),该过程也不会在退出时终止。 Besides .NET, it uses one COM component (which does everything on the UI thread). 除了.NET之外,它还使用一个COM组件(在UI线程上执行所有操作)。 If I break into the debugger after exitting, Visual Studio shows only one thread and a completely blank call stack. 如果退出后进入调试器,则Visual Studio仅显示一个线程和一个完全空白的调用堆栈。

What could possibly cause this? 可能是什么原因造成的?

Update: My process is terminating on the desktop but not the WinCE machines. 更新:我的过程在台式机上终止,但不在WinCE计算机上。 I tried to force the process to terminate with the following code, but it doesn't work: 我试图用以下代码强制终止该过程,但是它不起作用:

[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();
}

There are also supposed to be ExitProcess() and GetCurrentProcess() APIs like the following, but if I try to call them, I get EntryPointNotFoundException. 还应该有如下所示的ExitProcess()和GetCurrentProcess()API,但是如果我尝试调用它们,则会得到EntryPointNotFoundException。 Therefore I am using TerminateProcess(-1, 0) because the documentation for the desktop version of GetCurrentProcess claims that it simply returns -1. 因此,我正在使用TerminateProcess(-1,0),因为GetCurrentProcess的桌面版本的文档声称它只是返回-1。

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

Even throwing an unhandled exception won't do it. 即使抛出未处理的异常也不会这样做。

Update 2: the simplest program that causes the problem merely creates the COM object. 更新2:导致问题的最简单程序仅创建COM对象。

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

C++ programs that use the COM component do not exhibit this behavior, so my C++ COM component must have some bizarre interaction with the .NET framework which I will investigate. 使用COM组件的C ++程序不会表现出这种行为,因此我的C ++ COM组件必须与将要调查的.NET框架有某种怪异的交互。

look like you have some threads still running in your application. 看起来您的应用程序中仍有一些线程在运行。

Make sure you have terminate every child thread before exiting the main one. 在退出主线程之前,请确保已终止每个子线程。

Just a hunch - make sure CoUninitialize() is called before exit? 只是预感-确保在退出之前调用CoUninitialize()吗? Also, instead of breaking into a debugger create a crash dump and debug that. 另外,不要破坏调试器,而是创建崩溃转储并对其进行调试。 Not sure how this works on CE, but that's what'd I'd recommend on Windows. 不确定在CE上如何工作,但是我建议在Windows上使用。

If an app doesn't exit that usually means that there's one handle still open which can't be closed from userspace. 如果应用程序没有退出,通常意味着有一个句柄仍在打开,无法从用户空间关闭。 And that means there's a buggy driver. 这意味着有一个越野车司机。

See this post about details. 有关详细信息,请参见这篇文章

Your COM object is creating a thread in the background and that thread is not terminating. 您的COM对象正在后台创建一个线程,并且该线程没有终止。 It's likely that this is because the COM object is not getting released in your code. 可能是因为未在代码中释放COM对象。

Try calling Marshal.ReleaseComObject before exiting, so your simple test app would look like this: 尝试在退出之前调用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);
} 

I sort-of figured it out. 我有点想通了。

My COM object sets itself up to get WM_TIMER messages through a hidden window. 我的COM对象设置为通过隐藏窗口获取WM_TIMER消息。 Basically: 基本上:

// 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);

(Experts might point out I don't need a timer window to receive timer messages--the last parameter of SetTimer can be set to a callback function. Indeed, if I use a callback instead of a timer window, the problem disappears! However, I had to use a timer window to work around a strange bug in WinCE in which SetTimer(NULL,...) can cause WM_TIMER messages to received by somebody that calls PeekMessage() .) (专家可能会指出,我不需要计时器窗口来接收计时器消息SetTimer的最后一个参数可以设置为回调函数。确实,如果我使用回调而不是计时器窗口,问题就消失了! ,我不得不使用计时器窗口来解决WinCE中的一个奇怪错误,在该错误中SetTimer(NULL,...)可能导致调用PeekMessage()的人收到WM_TIMER消息。

Now, when the last COM object that uses the timer is destroyed, the timer and timer window are also destroyed: 现在,当使用计时器的最后一个COM对象被销毁时,计时器和计时器窗口也被销毁:

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

Unfortunately, DestroyWindow() never returns. 不幸的是, DestroyWindow()永远不会返回。 I assume there is some kind of deadlock in DestroyWindow , though it is not clear why the call stack is blank when I pause in Visual Studio. 我假设DestroyWindow存在某种死锁,尽管不清楚为什么我在Visual Studio中暂停时调用堆栈为空。 Perhaps because the COM object is destroyed automatically instead of by Marshal.ReleaseComObject() , it is destroyed in the finalizer thread, and DestroyWindow cannot be called from the finalizer thread on WinCE. 也许是因为COM对象是自动销毁的,而不是由Marshal.ReleaseComObject()销毁的,所以它在终结器线程中被销毁,并且无法从WinCE的终结器线程中调用DestroyWindow As usual Microsoft doesn't spell out the danger in its documentation, stating only "Do not use DestroyWindow in one thread to destroy a window created by a different thread." 像往常一样,Microsoft并未在其文档中说明危险,仅声明“请勿在一个线程中使用DestroyWindow破坏由另一个线程创建的窗口”。

The solution was simple: don't destroy the timer window at all, as the OS destroys it automatically when the process exits. 解决方案很简单:根本不破坏计时器窗口,因为操作系统在进程退出时会自动破坏计时器窗口。

Fun fact: the problem with DestroyWindow does not occur if I call SetTimer(NULL,...) instead of SetTimer(gTimerWindow,...) , but it does occur if I don't call SetTimer at all. 有趣的事实:如果我调用SetTimer(NULL,...)而不是SetTimer(gTimerWindow,...) ,则不会发生DestroyWindow的问题,但是如果我根本不调用SetTimer ,则确实会发生。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我的程序不能从Program Files目录运行,而不能从其他任何地方运行? - Why won't my program run from the Program Files directory but will from anywhere else? 为什么我的MessageQueue无法正常关闭? - Why won't my MessageQueue close properly? 我的程序无法正确显示数值 - My program won't display numerical values correctly 不知道为什么我的读者不会阅读我的文本文件 - Not sure why my reader won't read my text file 当Task有未处理的异常时,为什么我的进程不会终止? - Why doesn't my process terminate when Task has unhandled exception? 为什么我的WriteLine循环过早终止? - Why does my WriteLine loop terminate prematurely? 在进程中调用 robocopy 的批处理脚本不会终止 - Batch script calling robocopy in Process won't terminate 在“ C:\\ Program Files(x86)”之外运行时,为什么为“ x86”编译的WinForms应用程序不会在“ x64”计算机上退出? - Why won't my WinForms app compiled for “x86” exit on an “x64” machine when running outside “C:\Program Files (x86)”? 为什么我的AJAX控件不起作用? (而.net 4的ajax无法正常工作?) - Why won't my AJAX controls work? (and ajax for .net 4 not working?) 为什么我的 WPF XAML Grid TranslateTransform.X 不能? - Why won't my WPF XAML Grid TranslateTransform.X?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM