Pergunta

Eu tenho um aplicativo .NET Compact Framework que podem executado em três máquinas Windows (Windows Desktop e duas máquinas WinCE) e nos dispositivos WinCE, o processo nunca termina na saída, mesmo que eu chamo Application.Exit (). Além NET, que utiliza um componente COM (que faz tudo no thread UI). Se eu invadir o depurador após exitting, programas do Visual Studio apenas uma linha e uma pilha de chamadas completamente em branco.

O que poderia causar isso?

Update: O meu processo está a terminar no ambiente de trabalho, mas não as máquinas WinCE. Tentei forçar o processo a terminar com o seguinte código, mas ele não funciona:

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

Há também é suposto ser ExitProcess () e GetCurrentProcess () APIs como o seguinte, mas se eu tentar chamá-los, recebo EntryPointNotFoundException. Portanto, eu estou usando TerminateProcess (-1, 0), porque a documentação para a versão desktop do reivindicações GetCurrentProcess que ele simplesmente retorna -1.

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

Mesmo jogando uma exceção não tratada não vai fazê-lo.

Update 2:. O programa mais simples que faz com que o problema simplesmente cria o objeto COM

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

C ++ programas que usam o componente COM não apresentam esse comportamento, por isso a minha C ++ COM componente deve ter alguma interação bizarra com o .NET framework que vou investigar.

Foi útil?

Solução 5

Eu meio-de descobri-lo.

Os meus COM objeto se levanta para obter mensagens WM_TIMER através de uma janela oculta. Basicamente:

// 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 pode apontar Eu não preciso de uma janela temporizador para receber mensagens do temporizador -. O último parâmetro de SetTimer pode ser configurado para uma função de retorno Na verdade, se eu usar uma chamada de retorno em vez de uma janela timer, o problema desaparece! no entanto, eu tive que usar uma janela temporizador para o trabalho em torno de um bug estranho no WinCE em que SetTimer(NULL,...) pode causar mensagens WM_TIMER a recebida por alguém que as chamadas PeekMessage().)

Agora, quando o último objeto COM que usa o timer é destruído, a janela do temporizador e temporizador são também destruíram:

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

Infelizmente, DestroyWindow() nunca retorna. Eu supor que há algum tipo de impasse no DestroyWindow, embora não seja claro por que a pilha de chamadas está em branco quando faço uma pausa no Visual Studio. Talvez porque o objeto COM é destruído automaticamente em vez de por Marshal.ReleaseComObject(), ele é destruído no segmento finalizador, e DestroyWindow não pode ser chamado a partir do segmento finalizador no WinCE. Como de costume Microsoft não especifica o perigo em sua documentação, afirmando apenas "Não use DestroyWindow em um segmento para destruir uma janela criada por um segmento diferente."

A solução era simples:. Não destroem a janela temporizador em tudo, como o sistema operacional destrói automaticamente quando o processo é encerrado

Fun fato:. O problema com DestroyWindow não ocorre se eu chamo SetTimer(NULL,...) vez de SetTimer(gTimerWindow,...), mas não ocorrer se eu não chamo SetTimer em tudo

Outras dicas

Parece que você tem alguns segmentos ainda em execução na sua aplicação.

Certifique-se de terminar cada segmento de criança antes de sair o principal.

Apenas um palpite - Certifique-se CoUninitialize() é chamado antes de sair? Além disso, em vez de invadir um depurador criar um despejo de memória e depurar isso. Não sei como isso funciona na CE, mas isso é O que foi que eu recomendo no Windows.

Se um aplicativo não sair Isso normalmente significa que há uma alça ainda em aberto que não pode ser fechado a partir do espaço do usuário. E isso significa que há um motorista de buggy.

este post sobre detalhes.

Seu objeto COM é criar um thread em segundo plano e esse segmento não está sendo encerrado. É provável que isso é porque o objeto COM não está sendo lançado em seu código.

Tente chamar Marshal.ReleaseComObject antes de sair, para que o seu aplicativo de teste simples seria algo como isto:

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);
} 
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top