首页 > 解决方案 > 如何在visual studio 2019上使用winapi创建打开文件资源管理器的按钮

问题描述

==================================已解决================ ==================

正如肯怀特在评论中提到的那样。我在这里找到了一个对我有帮助的代码。我在某些地方编辑了代码 a 以将其调整为 Visual Studio 2019:

#include <iostream>
#include <Windows.h>

// FUNCTION PROTOTYPES =========================================================
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

// entry point for a Windows application =======================================
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR szCmdLine, int nWinMode) {
    // define some variables
    const wchar_t     szWinName[] = L"Win32App";
    const wchar_t     szAppTitle[] = L"Win32 API Skeletal Application";
    HWND     hwnd;
    MSG      msg;
    WNDCLASS wc;

    // define a window class
    wc.hInstance = hInstance;                         // handle to this instance
    wc.lpszClassName = szWinName;                         // window class name
    wc.lpfnWndProc = WndProc;                           // pointer to window proc
    wc.style = 0;                                 // default style
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);   // predefined icon
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);       // predefined cursor
    wc.lpszMenuName = NULL;                              // no class menu
    wc.cbClsExtra = 0;                                 // no extra info needed
    wc.cbWndExtra = 0;                                 // no extra info needed
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);       // predefined color brush

    // register the defined window class
    if (RegisterClass(&wc) == 0)
    {
        // an error occurred, abort the program
        MessageBox(NULL, L"Couldn't Register the Window Class!", L"ERROR", MB_OK | MB_ICONERROR);
        return 0;
    }

    // now that a window class has been registered, create the main window
    hwnd = CreateWindow(szWinName,           // name of window class to create
        szAppTitle,          // window title bar caption
        WS_OVERLAPPEDWINDOW, // window style - normal
        CW_USEDEFAULT,       // X coordinate - let Windows decide
        CW_USEDEFAULT,       // Y coordinate - let Windows decide
        CW_USEDEFAULT,       // width - let Windows decide
        CW_USEDEFAULT,       // height - let Windows decide
        NULL,                // no parent window
        NULL,                // no menu
        hInstance,           // handle to this instance
        NULL);               // no additional arguments

    // check to see if window was successfully created
    if (hwnd == NULL)
    {
        // an error occurred, abort
        MessageBox(NULL, L"Couldn't Create the Main Window!", L"ERROR", MB_OK | MB_ICONERROR);
        return 0;
    }

    // display (and update) the newly created window
    ShowWindow(hwnd, nWinMode);
    UpdateWindow(hwnd);

    // create the message loop
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);  // translate keyboard messages
        DispatchMessage(&msg);   // return control to Windows
    }

    return msg.wParam;
}


// processes the messages that Windows sends to the application ================
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    // choose which Windows messages you want to use
    switch (message)
    {
        // the window is being destroyed, so terminate the application
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    // let Windows process any messages not specified in the switch statement
    return DefWindowProc(hwnd, message, wParam, lParam);
}

问题描述:在 C++ 中使用 Visual Studio 2019 创建新窗口

我正在使用 Visual Studio 2019 在 cpp 的控制台应用程序类型的项目中为 USB 设备编写用户界面。我想添加两个功能 - 我想创建将出现在屏幕上并使用户能够:

  1. 通过单击“存储数据”按钮,将打开文件资源管理器,他们将能够选择存储从端点缓冲区读取的数据的文件
  2. 通过单击“读取数据”按钮,将打开文件资源管理器,他们将能够选择要从中读取数据的文件并将其写入端点。我想让用户选择文件的路径,我不希望用户使用键盘将路径插入终端,我想创建一个按钮来打开文件资源管理器并让用户访问所需的文件\位置。

例如,要将端点缓冲区中的数据存储到文件中,用户将单击“存储数据”并导航到所需的文件\位置。选择位置后,libusb 函数将从端点读取数据并将数据存储在一个临时结构中,我将从该结构中将其写入文件。

我的主要问题是创建这些按钮并让它们显示文件资源管理器。我已经开始使用一些简短的代码来创建一个新窗口,如本指南中所述:

  1. 按钮创建 - https://docs.microsoft.com/en-us/windows/win32/controls/create-a-button
  2. 窗口创建 - https://docs.microsoft.com/en-us/windows/win32/learnwin32/your-first-windows-program

问题是,当我运行程序时,窗口会立即打开并折叠。另外,我找不到什么功能可以帮助我按下按钮打开文件资源管理器。

我正在使用 windows.h 标头来创建窗口。这是我的代码:

''''

 #include <Windows.h>

 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return 
 DefWindowProc(hwnd, uMsg, wParam, lParam); }

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";

WNDCLASS wc = { };

wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;

RegisterClass(&wc);

HWND hwnd = CreateWindowEx(
    0,                              // Optional window styles.
    CLASS_NAME,                     // Window class
    L"Learn to Program Windows",    // Window text
    WS_OVERLAPPEDWINDOW,            // Window style

    // Size and position
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

    NULL,       // Parent window    
    NULL,       // Menu
    hInstance,  // Instance handle
    NULL        // Additional application data
);

if (hwnd == NULL)
{
    return 0;
}

ShowWindow(hwnd, nCmdShow);

return 0;
}

''''

我在链接器的附加依赖项中添加了标志“user32.lib”,我也没有任何链接器错误,所以我想不是这样。可能是什么问题呢?我试过查看其他类似的问题,但找不到任何有用的东西。另外,是否有任何库提供单击按钮后打开文件资源管理器的功能?

我希望我的问题以前没有被问过,并且写得正确。如果有什么问题,请告诉我,以便我编辑它。

非常感谢您的时间和关注。

标签: visual-studiouser-interfacewinapibutton

解决方案


运行程序时窗口立即打开并折叠的原因是您没有创建消息循环。消息循环不仅仅是WindowProc您提到的功能。您还需要添加消息处理循环功能。

根据MSDN文档:

  1. wWinMain是程序入口点。当程序启动时,它会注册一些有关应用程序窗口行为的信息。最重要的一项是函数的地址,在本例中名为 WindowProc。这个函数定义了窗口的行为——它的外观、它如何与用户交互等等。

  2. 接下来,程序创建窗口并接收唯一标识窗口的句柄。

  3. 如果窗口创建成功,程序进入一个while循环。程序一直在这个循环中,直到用户关闭窗口并退出应用程序。

请注意,该程序没有显式调用 WindowProc 函数,尽管我们说过这是定义大多数应用程序逻辑的地方。Windows 通过传递一系列消息与您的程序进行通信。while循环内的代码驱动这个过程。每次程序调用该DispatchMessage函数时,它都会间接导致 Windows 调用 WindowProc 函数,每条消息调用一次。

然后就可以通过CreateWindow创建一个按钮,代码如下(但需要为后续操作设置唯一标识):

#define IDB_BTN 1001
HWND btn = CreateWindow("BUTTON", "OPEN", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 500, 200, 100, 100, hwnd, (HMENU)IDB_BTN, (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), NULL);

您可以通过两种方式打开资源管理器。

您可以直接通过以下方式打开资源管理器ShellExecuteA

ShellExecute(NULL, "open", "explorer.exe", NULL, NULL, SW_NORMAL);

当然,也许最好的方法是使用SHOpenFolderAndSelectItems()函数。

LPCWSTR pszPathToOpen = L"C:\\Windows";
PIDLIST_ABSOLUTE pidl;
if (SUCCEEDED(SHParseDisplayName(pszPathToOpen, 0, &pidl, 0, 0)))
{
    ITEMIDLIST idNull = { 0 };
    LPCITEMIDLIST pidlNull[1] = { &idNull };
    SHOpenFolderAndSelectItems(pidl, 1, pidlNull, 0);
    ILFree(pidl);
}

这是完整的示例:

#include <Windows.h>
#include <shlobj_core.h>
#define IDB_BTN 1001
LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
    // Register the window class.
    TCHAR CLASS_NAME[] = "Sample Window Class";
    MSG msg;
    WNDCLASS wc = { };

    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;

    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        CLASS_NAME,                     // Window class
        "Learn to Program Windows",    // Window text
        WS_OVERLAPPEDWINDOW,            // Window style

        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

        NULL,       // Parent window    
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
    );
    HWND btn = CreateWindow(
        "BUTTON",
        "OPEN",
        WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
        500,
        200,
        100,
        100,
        hwnd,
        (HMENU)IDB_BTN,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE),
        NULL);
    if (hwnd == NULL)
    {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);

    while (GetMessageW(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
    return msg.wParam;
}


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDB_BTN:
        {
            //ShellExecute(NULL, "open", "explorer.exe", NULL, NULL, SW_NORMAL);
            LPCWSTR pszPathToOpen = L"C:\\Windows";
            PIDLIST_ABSOLUTE pidl;
            if (SUCCEEDED(SHParseDisplayName(pszPathToOpen, 0, &pidl, 0, 0)))
            {
                ITEMIDLIST idNull = { 0 };
                LPCITEMIDLIST pidlNull[1] = { &idNull };
                SHOpenFolderAndSelectItems(pidl, 1, pidlNull, 0);
                ILFree(pidl);
            }
            return 0;
        }
        default:
            break;
        };
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

推荐阅读