我遵循WinProg网站上的“简单窗口” tutorial

当本教程中的代码在不使用C运行时库的情况下进行编译时,一切似乎都按预期工作。随即创建了该窗口,并向用户显示了该窗口。

如果我按关闭按钮关闭窗口,则该窗口将被破坏并退出该进程-该进程不再在本地计算机上运行。

但是,当我链接到WTS库并添加对WTSRegisterSessionNotification函数的调用时,该进程在关闭其对应的窗口后将继续在本地计算机上运行。

调用WTSRegisterSessionNotification后,从WinMain返回时,似乎只会出现此行为。

我的猜测是WTSRegisterSessionNotification创建某种永远不会被通知退出的工作线程。从WinMain返回似乎没有导致ExitProcess调用,可能是因为代码是在没有C运行时库的情况下编译的。

通过从WinMain返回之前调用ExitProcess可以避免该问题。但这并不适合处理这种情况。

我的问题是:是否有一个我正在忽略的WTS API函数可以/应该从WinMain返回之前被调用,以确保该过程将退出?

代码示例:

#include <windows.h>
#include <wtsapi32.h>

const char g_szClassName[] = "myWindowClass";

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch (msg)
    {
    case WM_WTSSESSION_CHANGE:
        if (wParam == WTS_SESSION_LOCK)
            OutputDebugString( "current session got locked" );
        else if (wParam == WTS_SESSION_UNLOCK)
            OutputDebugString( "current session got unlocked" );
        break;
    case WM_CLOSE:
        DestroyWindow( hwnd );
        break;
    case WM_DESTROY:
        WTSUnRegisterSessionNotification( hwnd );
        PostQuitMessage( 0 );
        break;
    default:
        return DefWindowProc( hwnd, msg, wParam, lParam );
    }
    return 0;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPSTR lpCmdLine, int nCmdShow )
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    //Step 1: Registering the Window Class
    wc.cbSize = sizeof( WNDCLASSEX );
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
    wc.hCursor = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm = LoadIcon( NULL, IDI_APPLICATION );

    if (!RegisterClassEx( &wc ))
    {
        MessageBox( NULL, "Window Registration Failed!", "Error!",
                    MB_ICONEXCLAMATION | MB_OK );
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "The title of my window",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
        NULL, NULL, hInstance, NULL );

    if (hwnd == NULL)
    {
        MessageBox( NULL, "Window Creation Failed!", "Error!",
                    MB_ICONEXCLAMATION | MB_OK );
        return 0;
    }

    if (!WTSRegisterSessionNotification( hwnd, NOTIFY_FOR_THIS_SESSION ))
    {
        MessageBox( NULL, "Register Session Notification Failed!", "Error!",
                    MB_ICONEXCLAMATION | MB_OK );
        return 0;
    }

    ShowWindow( hwnd, nCmdShow );
    UpdateWindow( hwnd );

    // Step 3: The Message Loop
    while (GetMessage( &Msg, NULL, 0, 0 ) > 0)
    {
        TranslateMessage( &Msg );
        DispatchMessage( &Msg );
    }
    return Msg.wParam;
}


编译器命令行:

/GS- /TC /GL /analyze- /W4 /Gy /Zc:wchar_t /Gm- /O1 /Ob2 /Fd"Release\vc100.pdb" /fp:fast /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /errorReport:prompt /WX- /Zc:forScope /GR- /Gd /Oy /Oi /MD /Fa"Release\" /nologo /Zl /Fo"Release\" /Os


链接器命令行:

/OUT:"C:\Users\treintje\Documents\Visual Studio 2015\Projects\sample\Release\sample.exe" /MANIFEST:NO /LTCG /NXCOMPAT /PDB:"C:\Users\treintje\Documents\Visual Studio 2015\Projects\sample\Release\sample.pdb" /DYNAMICBASE:NO "kernel32.lib" "user32.lib" "wtsapi32.lib" /ALLOWISOLATION /MACHINE:X86 /ENTRY:"WinMain" /OPT:REF /INCREMENTAL:NO /PGD:"C:\Users\treintje\Documents\Visual Studio 2015\Projects\sample\Release\sample.pgd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /ManifestFile:"Release\sample.exe.intermediate.manifest" /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /NODEFAULTLIB /TLBID:1

最佳答案

通过在返回之前调用ExitProcess可以避免此问题
  从WinMain。但这不像是正确的应对方式
  情况。


退出过程必须直接或间接调用ExitProcess。这是绝对正确和强制的。当您使用CRT WinMain并不是应用程序的真正入口点时-它是从WinMainCRTStartup调用的,而ExitProcess则称为。如果您不使用CRT-您必须自行致电ExitProcess

从Win 10开始(完全在1607年构建,但可能在以前的版本上)存在新功能-用于DLL加载的“并行加载程序”。因此,现在,当您的进程中加载​​了任何dll(ntdllkernel32kernelbase除外)时,系统都会创建工作线程以“并行”方式加载dll。因此,即使您只运行非常简单的程序-在WinMain中说单个MessageBox但不调用Exitprocess-您的进程没有退出,但仍然存活30-60秒-dll加载器工作线程(LdrpWorkCallback)具有30秒的空闲超时,并且在退出之后

关于c - WTSRegisterSessionNotification导致进程挂起,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40854000/

10-11 18:25