visual-studio - 如何在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 设备编写用户界面。我想添加两个功能 - 我想创建将出现在屏幕上并使用户能够:
- 通过单击“存储数据”按钮,将打开文件资源管理器,他们将能够选择存储从端点缓冲区读取的数据的文件
- 通过单击“读取数据”按钮,将打开文件资源管理器,他们将能够选择要从中读取数据的文件并将其写入端点。我想让用户选择文件的路径,我不希望用户使用键盘将路径插入终端,我想创建一个按钮来打开文件资源管理器并让用户访问所需的文件\位置。
例如,要将端点缓冲区中的数据存储到文件中,用户将单击“存储数据”并导航到所需的文件\位置。选择位置后,libusb 函数将从端点读取数据并将数据存储在一个临时结构中,我将从该结构中将其写入文件。
我的主要问题是创建这些按钮并让它们显示文件资源管理器。我已经开始使用一些简短的代码来创建一个新窗口,如本指南中所述:
- 按钮创建 - https://docs.microsoft.com/en-us/windows/win32/controls/create-a-button
- 窗口创建 - 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”,我也没有任何链接器错误,所以我想不是这样。可能是什么问题呢?我试过查看其他类似的问题,但找不到任何有用的东西。另外,是否有任何库提供单击按钮后打开文件资源管理器的功能?
我希望我的问题以前没有被问过,并且写得正确。如果有什么问题,请告诉我,以便我编辑它。
非常感谢您的时间和关注。
解决方案
运行程序时窗口立即打开并折叠的原因是您没有创建消息循环。消息循环不仅仅是WindowProc
您提到的功能。您还需要添加消息处理循环功能。
根据MSDN文档:
wWinMain是程序入口点。当程序启动时,它会注册一些有关应用程序窗口行为的信息。最重要的一项是函数的地址,在本例中名为 WindowProc。这个函数定义了窗口的行为——它的外观、它如何与用户交互等等。
接下来,程序创建窗口并接收唯一标识窗口的句柄。
如果窗口创建成功,程序进入一个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);
}
推荐阅读
- r - 使用分隔符从原始向量创建几个新向量
- angular - 从 Angular 7 中的 .net 核心 API 检索 http 响应正文
- mysql - Laravel:hasManyThrough 关系获取多对多表值
- python - 我们如何在 Open CV 中创建一个轨迹栏,以便我可以使用它跳到视频的特定部分?
- php - 引导崩溃:显示一个隐藏另一个
- ssl - 如何通过 SSL/TLS 连接 Thingsboard 和 Thingsboard 物联网网关?
- php - 检查队列返回状态
- jakarta-ee - 如何在生产中禁用 swagger-ui(Thorntail)?
- ssl - Websphere trust.p12 vs cacert 存储
- if-statement - MultiWayIf 和经典守卫有什么区别?