سؤال

لدي تطبيق .NET Compact Framework الذي يمكن تشغيله على ثلاثة أجهزة تعمل بنظام Windows (نوافذ سطح المكتب وجهازي WinCE) وعلى أجهزة WinCE، لا تنتهي العملية أبدًا عند الخروج، حتى لو اتصلت بـ Application.Exit().إلى جانب .NET، يستخدم مكون COM واحدًا (الذي يقوم بكل شيء في سلسلة واجهة المستخدم).إذا قمت باقتحام مصحح الأخطاء بعد الخروج، فسيعرض Visual Studio مؤشر ترابط واحد فقط ومكدس استدعاءات فارغًا تمامًا.

ما الذي يمكن أن يسبب هذا؟

تحديث:تنتهي عمليتي على سطح المكتب ولكن ليس على أجهزة 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() مثل ما يلي، ولكن إذا حاولت الاتصال بهم، أحصل على 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();
}

برامج C++ التي تستخدم مكون COM لا تظهر هذا السلوك، لذلك يجب أن يكون لمكون 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.كالعادة، لم توضح Microsoft الخطر في وثائقها، قائلة فقط "لا تستخدم DestroyWindow في موضوع واحد لتدمير نافذة تم إنشاؤها بواسطة موضوع مختلف."

وكان الحل بسيطا:لا تدمر نافذة المؤقت على الإطلاق، حيث يقوم نظام التشغيل بتدميرها تلقائيًا عند انتهاء العملية.

حقيقة ممتعة:المشكلة مع DestroyWindow لا يحدث إذا اتصلت SetTimer(NULL,...) بدلاً من SetTimer(gTimerWindow,...), ، لكنه يفعل يحدث إذا لم أتصل SetTimer على الاطلاق.

نصائح أخرى

وتبدو وكأنها لديك بعض المواضيع يزال قيد التشغيل في التطبيق الخاص بك.

تأكد من حصولك على إنهاء كل موضوع الطفل قبل أن تخرج واحدة رئيسية.

ومجرد حدس - جعل يسمى تأكد CoUninitialize() قبل الخروج؟ أيضا، بدلا من اقتحام مصحح إنشاء تفريغ الأعطال وتصحيح ذلك. لست متأكدا كيف يعمل هذا على CE، ولكن هذا ماذا أراد أنا أنصح على ويندوز.

إذا لم التطبيق الخروج التي عادة ما يعني أن هناك مقبض تزال واحدة مفتوحة والتي لا يمكن أن تكون مغلقة من مساحة المستخدم. وهذا يعني أن هناك سائق عربات التي تجرها الدواب.

هذا المنصب عن مزيد من التفاصيل.

والكائن 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