Skip to content

Commit d4b62a8

Browse files
committed
Add Windows string conversion utilities and update usage
Introduced string_utils_windows.h with functions for converting between std::string and std::wstring, and for handling WCHAR arrays. Updated display, menu, tray icon, window manager, and window implementations to use these utilities for proper UTF-8/UTF-16 conversions, improving Unicode support in Windows API calls.
1 parent 599f1b3 commit d4b62a8

File tree

6 files changed

+78
-24
lines changed

6 files changed

+78
-24
lines changed

src/platform/windows/display_windows.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "../../display.h"
22

33
#include <windows.h>
4+
#include "string_utils_windows.h"
45

56
namespace nativeapi {
67

@@ -65,7 +66,7 @@ std::string Display::GetName() const {
6566
if (!pimpl_->h_monitor_)
6667
return "";
6768
MONITORINFOEX monitorInfo = GetMonitorInfo(pimpl_->h_monitor_);
68-
return monitorInfo.szDevice;
69+
return WCharArrayToString(monitorInfo.szDevice);
6970
}
7071

7172
Point Display::GetPosition() const {

src/platform/windows/menu_windows.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <vector>
66
#include "../../menu.h"
77
#include "../../menu_event.h"
8+
#include "string_utils_windows.h"
89

910
namespace nativeapi {
1011

@@ -151,8 +152,9 @@ void MenuItem::SetLabel(const std::optional<std::string>& label) {
151152
MENUITEMINFO mii = {};
152153
mii.cbSize = sizeof(MENUITEMINFO);
153154
mii.fMask = MIIM_STRING;
154-
const char* labelStr = label.has_value() ? label->c_str() : "";
155-
mii.dwTypeData = const_cast<LPSTR>(labelStr);
155+
std::string labelStr = label.has_value() ? *label : "";
156+
std::wstring wLabelStr = StringToWString(labelStr);
157+
mii.dwTypeData = const_cast<LPWSTR>(wLabelStr.c_str());
156158
SetMenuItemInfo(pimpl_->parent_menu_, pimpl_->menu_item_id_, FALSE, &mii);
157159
}
158160
}
@@ -355,8 +357,9 @@ void Menu::AddItem(std::shared_ptr<MenuItem> item) {
355357
}
356358

357359
auto labelOpt = item->GetLabel();
358-
const char* labelStr = labelOpt.has_value() ? labelOpt->c_str() : "";
359-
AppendMenu(pimpl_->hmenu_, flags, menuId, labelStr);
360+
std::string labelStr = labelOpt.has_value() ? *labelOpt : "";
361+
std::wstring wLabelStr = StringToWString(labelStr);
362+
AppendMenu(pimpl_->hmenu_, flags, menuId, wLabelStr.c_str());
360363

361364
// Update the item's impl with menu info
362365
item->pimpl_->parent_menu_ = pimpl_->hmenu_;
@@ -380,9 +383,10 @@ void Menu::InsertItem(size_t index, std::shared_ptr<MenuItem> item) {
380383
}
381384

382385
auto labelOpt = item->GetLabel();
383-
const char* labelStr = labelOpt.has_value() ? labelOpt->c_str() : "";
386+
std::string labelStr = labelOpt.has_value() ? *labelOpt : "";
387+
std::wstring wLabelStr = StringToWString(labelStr);
384388
InsertMenu(pimpl_->hmenu_, static_cast<UINT>(index), flags, item->id,
385-
labelStr);
389+
wLabelStr.c_str());
386390

387391
item->pimpl_->parent_menu_ = pimpl_->hmenu_;
388392
item->pimpl_->menu_item_id_ = static_cast<UINT>(item->id);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#ifndef NATIVEAPI_PLATFORM_WINDOWS_STRING_UTILS_H_
2+
#define NATIVEAPI_PLATFORM_WINDOWS_STRING_UTILS_H_
3+
4+
#include <windows.h>
5+
#include <string>
6+
7+
namespace nativeapi {
8+
namespace { // 匿名命名空间,仅在包含此头文件的编译单元内可见
9+
10+
// Convert std::string (UTF-8) to std::wstring (UTF-16)
11+
inline std::wstring StringToWString(const std::string& str) {
12+
if (str.empty()) return std::wstring();
13+
14+
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), nullptr, 0);
15+
std::wstring wstr(size_needed, 0);
16+
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), &wstr[0], size_needed);
17+
return wstr;
18+
}
19+
20+
// Convert std::wstring (UTF-16) to std::string (UTF-8)
21+
inline std::string WStringToString(const std::wstring& wstr) {
22+
if (wstr.empty()) return std::string();
23+
24+
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.size(), nullptr, 0, nullptr, nullptr);
25+
std::string str(size_needed, 0);
26+
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.size(), &str[0], size_needed, nullptr, nullptr);
27+
return str;
28+
}
29+
30+
// Convert WCHAR array to std::string
31+
inline std::string WCharArrayToString(const WCHAR* wchar_array) {
32+
if (!wchar_array) return std::string();
33+
return WStringToString(std::wstring(wchar_array));
34+
}
35+
36+
} // anonymous namespace
37+
} // namespace nativeapi
38+
39+
#endif // NATIVEAPI_PLATFORM_WINDOWS_STRING_UTILS_H_
40+

src/platform/windows/tray_icon_windows.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "../../menu.h"
88
#include "../../tray_icon.h"
99
#include "../../tray_icon_event.h"
10+
#include "string_utils_windows.h"
1011

1112
namespace nativeapi {
1213

@@ -102,16 +103,18 @@ TrayIcon::TrayIcon() : id(-1), pimpl_(std::make_unique<Impl>()) {
102103
static UINT next_class_id = 1;
103104
std::string class_name =
104105
"NativeAPITrayIcon_" + std::to_string(next_class_id++);
106+
std::wstring wclass_name = StringToWString(class_name);
105107

106108
WNDCLASS wc = {};
107109
wc.lpfnWndProc = DefWindowProc;
108110
wc.hInstance = hInstance;
109-
wc.lpszClassName = class_name.c_str();
111+
wc.lpszClassName = wclass_name.c_str();
110112

111113
if (RegisterClass(&wc)) {
112114
// Create hidden message-only window
115+
std::wstring wtitle = StringToWString("NativeAPI Tray Icon");
113116
HWND hwnd =
114-
CreateWindow(class_name.c_str(), "NativeAPI Tray Icon", 0, 0, 0, 0, 0,
117+
CreateWindow(wclass_name.c_str(), wtitle.c_str(), 0, 0, 0, 0, 0,
115118
HWND_MESSAGE, // Message-only window
116119
nullptr, hInstance, nullptr);
117120

@@ -148,12 +151,13 @@ void TrayIcon::SetIcon(std::string icon) {
148151
hIcon = LoadIcon(nullptr, IDI_APPLICATION);
149152
} else if (!icon.empty()) {
150153
// Try to load as file path first
151-
hIcon = (HICON)LoadImage(nullptr, icon.c_str(), IMAGE_ICON, 16, 16,
154+
std::wstring wicon = StringToWString(icon);
155+
hIcon = (HICON)LoadImage(nullptr, wicon.c_str(), IMAGE_ICON, 16, 16,
152156
LR_LOADFROMFILE);
153157

154158
// If file path failed, try as resource
155159
if (!hIcon) {
156-
hIcon = LoadIcon(GetModuleHandle(nullptr), icon.c_str());
160+
hIcon = LoadIcon(GetModuleHandle(nullptr), wicon.c_str());
157161
}
158162

159163
// If still failed, use default application icon
@@ -193,10 +197,10 @@ std::optional<std::string> TrayIcon::GetTitle() {
193197

194198
void TrayIcon::SetTooltip(std::optional<std::string> tooltip) {
195199
if (pimpl_->hwnd_) {
196-
const char* tooltip_str = tooltip.has_value() ? tooltip->c_str() : "";
197-
strncpy_s(pimpl_->nid_.szTip, tooltip_str,
198-
sizeof(pimpl_->nid_.szTip) - 1);
199-
pimpl_->nid_.szTip[sizeof(pimpl_->nid_.szTip) - 1] = '\0';
200+
std::string tooltip_str = tooltip.has_value() ? *tooltip : "";
201+
std::wstring wtooltip = StringToWString(tooltip_str);
202+
wcsncpy_s(pimpl_->nid_.szTip, sizeof(pimpl_->nid_.szTip) / sizeof(WCHAR),
203+
wtooltip.c_str(), _TRUNCATE);
200204

201205
// Update if icon is visible (check if hIcon is set as indicator)
202206
if (pimpl_->nid_.hIcon) {
@@ -206,8 +210,8 @@ void TrayIcon::SetTooltip(std::optional<std::string> tooltip) {
206210
}
207211

208212
std::optional<std::string> TrayIcon::GetTooltip() {
209-
if (pimpl_->hwnd_ && pimpl_->nid_.szTip[0] != '\0') {
210-
return std::string(pimpl_->nid_.szTip);
213+
if (pimpl_->hwnd_ && pimpl_->nid_.szTip[0] != L'\0') {
214+
return WCharArrayToString(pimpl_->nid_.szTip);
211215
}
212216
return std::nullopt;
213217
}

src/platform/windows/window_manager_windows.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "../../window.h"
66
#include "../../window_event.h"
77
#include "../../window_manager.h"
8+
#include "string_utils_windows.h"
89

910
namespace nativeapi {
1011

@@ -114,13 +115,13 @@ std::shared_ptr<Window> WindowManager::Create(const WindowOptions& options) {
114115

115116
// Register window class if not already registered
116117
static bool class_registered = false;
117-
const char* class_name = "NativeAPIWindow";
118+
static std::wstring wclass_name = StringToWString("NativeAPIWindow");
118119

119120
if (!class_registered) {
120121
WNDCLASS wc = {};
121122
wc.lpfnWndProc = WindowProc;
122123
wc.hInstance = hInstance;
123-
wc.lpszClassName = class_name;
124+
wc.lpszClassName = wclass_name.c_str();
124125
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
125126
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
126127

@@ -140,8 +141,9 @@ std::shared_ptr<Window> WindowManager::Create(const WindowOptions& options) {
140141
// Create the window
141142
DWORD style = WS_OVERLAPPEDWINDOW;
142143
DWORD exStyle = 0;
144+
std::wstring wtitle = StringToWString(options.title);
143145

144-
HWND hwnd = CreateWindowEx(exStyle, class_name, options.title.c_str(), style,
146+
HWND hwnd = CreateWindowEx(exStyle, wclass_name.c_str(), wtitle.c_str(), style,
145147
CW_USEDEFAULT, CW_USEDEFAULT,
146148
static_cast<int>(options.size.width),
147149
static_cast<int>(options.size.height), nullptr,

src/platform/windows/window_windows.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <iostream>
33
#include "../../window.h"
44
#include "../../window_manager.h"
5+
#include "string_utils_windows.h"
56

67
namespace nativeapi {
78

@@ -393,7 +394,8 @@ Point Window::GetPosition() const {
393394

394395
void Window::SetTitle(std::string title) {
395396
if (pimpl_->hwnd_) {
396-
SetWindowText(pimpl_->hwnd_, title.c_str());
397+
std::wstring wtitle = StringToWString(title);
398+
SetWindowText(pimpl_->hwnd_, wtitle.c_str());
397399
}
398400
}
399401

@@ -405,9 +407,10 @@ std::string Window::GetTitle() const {
405407
if (length == 0)
406408
return "";
407409

408-
std::string title(length, '\0');
409-
GetWindowText(pimpl_->hwnd_, &title[0], length + 1);
410-
return title;
410+
std::wstring wtitle(length + 1, L'\0');
411+
GetWindowText(pimpl_->hwnd_, &wtitle[0], length + 1);
412+
wtitle.resize(length);
413+
return WStringToString(wtitle);
411414
}
412415

413416
void Window::SetHasShadow(bool has_shadow) {

0 commit comments

Comments
 (0)