如何从 C++ 中的单独程序打开记事本中的系统菜单?

Posted

技术标签:

【中文标题】如何从 C++ 中的单独程序打开记事本中的系统菜单?【英文标题】:How to open system menu in Notepad from separate program in C++? 【发布时间】:2020-05-27 19:01:15 【问题描述】:

我正在尝试在记事本中弹出系统菜单,如下所示:

不一定是帮助菜单;任何菜单都可以。

此代码将窗口置于前台并记录0x204a4 0x2bd041f 0,但不会打开菜单。

#include <iostream>
#include <windows.h>

int main() 
    HWND hWnd = FindWindow(NULL, "Untitled - Notepad");
    SetForegroundWindow(hWnd);
    HMENU hMenu = GetSystemMenu(hWnd, FALSE);
    int flag = TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON, 452, 335, NULL, hWnd, NULL);
    std::cout << hWnd << " " << hMenu << " " << flag << std::endl; // 0x204a4 0x2bd041f 0
    SendMessage(hWnd, WM_SYSCOMMAND, flag, 0);

g++ main.cpp


更新:

这是我更新的代码。它打开了错误的菜单:

#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR pCmdLine, int nCmdShow) 
    const wchar_t CLASS_NAME[] = L"My Window Class";
    WNDCLASS wc = ;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    RegisterClass(&wc);
    HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"My Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
    if (hwnd == NULL) 
        return 0;
    
    ShowWindow(hwnd, nCmdShow);
    //--------------------------------------------------------------
    HWND hWndNotepad = FindWindow(NULL, L"Untitled - Notepad");
    if (!hWndNotepad) 
        MessageBox(hwnd, L"Notepad window handle not found.", L"Error", MB_OK | MB_ICONERROR);
    
    if (!SetForegroundWindow(hWndNotepad)) 
        MessageBox(hwnd, L"Unable to bring Notepad window to front.", L"Error", MB_OK | MB_ICONERROR);
    
    HMENU hMenu = GetSystemMenu(hWndNotepad, FALSE);
    if (!hMenu) 
        MessageBox(hwnd, L"Notepad menu handle not found.", L"Error", MB_OK | MB_ICONERROR);
    
    TrackPopupMenuEx(hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON, 452, 335, hwnd, NULL);
    //--------------------------------------------------------------
    MSG msg = ;
    while (GetMessage(&msg, NULL, 0, 0)) 
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    
    return 0;


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
    switch (uMsg) 
    case WM_CREATE:
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_PAINT: 
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
        EndPaint(hwnd, &ps);
        break;
    
        return 0;
    
    return DefWindowProc(hwnd, uMsg, wParam, lParam);

【问题讨论】:

你能用 AutoHotkey 或类似的代替吗? 您的应用在调用TrackPopupMenu()时需要使用自己的HWND,当该窗口在另一个进程中时,您不能使用菜单的所属窗口。但是您可以将WM_SYSCOMMAND 发布到另一个进程中的窗口。此外,您应该改用TrackPopupMenuEx()。此外,在调用TrackPopupMenu/Ex() 之前,您没有进行任何错误处理以确保FindWindow()SetForegroundWindow()GetSystemMenu() 实际上是成功的 @RemyLebeau 我根据您的建议更新了我的帖子。但这会打开错误的菜单,如您在屏幕截图中所见。 @GirkovArpa 那是因为GetSystemMenu() 没有返回您正在寻找的菜单。它返回与窗口左上角图标和任务栏按钮关联的菜单。您正在寻找 GetMenu() 返回的菜单。 【参考方案1】:

#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR pCmdLine, int nCmdShow) 
    const wchar_t CLASS_NAME[] = L"My Window Class";
    WNDCLASS wc = ;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    RegisterClass(&wc);
    HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"My Window", WS_OVERLAPPEDWINDOW, 683 - 100, 360 - 150, 300, 200, NULL, NULL, hInstance, NULL);
    if (hwnd == NULL) 
        return 0;
    
    ShowWindow(hwnd, nCmdShow);
    //--------------------------------------------------------------
    HWND hWndNotepad = FindWindow(NULL, L"Untitled - Notepad");
    if (!hWndNotepad) 
        MessageBox(hwnd, L"Notepad window handle not found.", L"Error", MB_OK | MB_ICONERROR);
        return 0;
    
    HMENU hMenu = GetMenu(hWndNotepad);
    if (!hMenu) 
        MessageBox(hwnd, L"Notepad menu handle not found.", L"Error", MB_OK | MB_ICONERROR);
        return 0;
    
    tagTPMPARAMS tpm_params;
    tpm_params.cbSize = sizeof(tagTPMPARAMS);
    GetWindowRect(hWndNotepad, &tpm_params.rcExclude);
    TrackPopupMenuEx(GetSubMenu(hMenu, 0), NULL, tpm_params.rcExclude.left, tpm_params.rcExclude.top, hwnd, NULL);
    //--------------------------------------------------------------
    MSG msg = ;
    while (GetMessage(&msg, NULL, 0, 0)) 
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    
    return 0;


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
    switch (uMsg) 
    case WM_CREATE:
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_PAINT: 
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
        EndPaint(hwnd, &ps);
        break;
    
        return 0;
    
    return DefWindowProc(hwnd, uMsg, wParam, lParam);

g++ main.cpp -mwindows

【讨论】:

以上是关于如何从 C++ 中的单独程序打开记事本中的系统菜单?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用windows优化大师进行右键新建word

压缩文件后(它们从 Visual Studio 中的文件路径引用打开),如何让我的应用程序从单独的 Winform 打开? (C#)

如何创建和使用LabVIEW中的LLB文件?

c++文件流fstream中的函数

如何修改eclipse中的默认工作路径

如何使用C ++消除记事本.txt文件中的BOM? [重复]