@@ -21,6 +21,9 @@ static std::mutex lock_str_data;
2121static std::unordered_map<std::wstring,
2222 res_string_loader::res_string_identifier>
2323 str_data;
24+ static std::unordered_map<res_string_loader::res_string_identifier,
25+ std::wstring>
26+ str_data_rev;
2427static std::unordered_map<size_t , std::string> module_name_cache;
2528
2629res_string_loader::string_id res_string_loader::string_to_id (std::wstring str) {
@@ -34,8 +37,10 @@ res_string_loader::string_id res_string_loader::string_to_id(std::wstring str) {
3437
3538std::string get_module_name_from_instance (HINSTANCE hInstance) {
3639 char buffer[MAX_PATH];
37- GetModuleFileNameA (hInstance, buffer, MAX_PATH);
38- return std::filesystem::path (buffer).filename ().string ();
40+ if (GetModuleFileNameA (hInstance, buffer, MAX_PATH)) {
41+ return std::filesystem::path (buffer).filename ().string ();
42+ }
43+ return {};
3944}
4045
4146size_t store_module_name (HINSTANCE hInstance) {
@@ -57,7 +62,7 @@ void res_string_loader::init_hook() {
5762 static auto LoadStringWHook =
5863 kernelbase->exports (" LoadStringW" )->inline_hook ();
5964 LoadStringWHook->install (+[](HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer,
60- int cchBufferMax) -> int {
65+ int cchBufferMax) -> int {
6166 auto res = LoadStringWHook->call_trampoline <int >(hInstance, uID, lpBuffer,
6267 cchBufferMax);
6368 if (res > 0 ) {
@@ -66,6 +71,7 @@ void res_string_loader::init_hook() {
6671 if (str_data.find (str) != str_data.end ())
6772 return res;
6873 str_data[str] = {uID, store_module_name (hInstance)};
74+ str_data_rev[{uID, store_module_name (hInstance)}] = str;
6975 }
7076 return res;
7177 });
@@ -74,7 +80,7 @@ void res_string_loader::init_hook() {
7480 kernelbase->exports (" LoadStringA" )->inline_hook ();
7581
7682 LoadStringAHook->install (+[](HINSTANCE hInstance, UINT uID, LPSTR lpBuffer,
77- int cchBufferMax) -> int {
83+ int cchBufferMax) -> int {
7884 auto res = LoadStringAHook->call_trampoline <int >(hInstance, uID, lpBuffer,
7985 cchBufferMax);
8086 if (res > 0 ) {
@@ -84,6 +90,7 @@ void res_string_loader::init_hook() {
8490 if (str_data.find (s) != str_data.end ())
8591 return res;
8692 str_data[s] = {uID, store_module_name (hInstance)};
93+ str_data_rev[{uID, store_module_name (hInstance)}] = s;
8794 }
8895
8996 return res;
@@ -154,6 +161,58 @@ void EnumerateStringResources(
154161 return TRUE ;
155162 },
156163 reinterpret_cast <LONG_PTR>(&callback));
164+ // RT_MENU
165+ EnumResourceNamesW (
166+ mod, MAKEINTRESOURCEW (4 ),
167+ +[](HMODULE hModule, LPCWSTR /* lpType*/ , LPWSTR lpName,
168+ LONG_PTR lParam) -> BOOL {
169+ auto &cb =
170+ *reinterpret_cast <std::function<void (std::wstring_view, size_t )> *>(
171+ lParam);
172+ if (!IS_INTRESOURCE (lpName))
173+ return TRUE ;
174+
175+ HMENU hMenu = LoadMenuW (hModule, lpName);
176+ if (hMenu) {
177+ for (UINT id = 0 ; id < 0xFFFF ; id++) {
178+ UINT state = GetMenuState (hMenu, id, MF_BYCOMMAND);
179+ if (state != 0xFFFFFFFF ) {
180+ MENUITEMINFOW info = {sizeof (MENUITEMINFO)};
181+ info.fMask = MIIM_STRING;
182+ info.dwTypeData = nullptr ;
183+ info.cch = 0 ;
184+
185+ if (auto res = GetMenuItemInfoW (hMenu, id, FALSE , &info); !res) {
186+ std::println (" Failed to get menu item info for id {}: {}" , id,
187+ GetLastError ());
188+ continue ;
189+ }
190+
191+ std::wstring name;
192+ if (info.cch == 0 ) {
193+ continue ; // 没有名称
194+ } else {
195+ name.resize (info.cch + 1 );
196+ info.dwTypeData = name.data ();
197+ info.cch = static_cast <UINT>(name.size ());
198+ if (!GetMenuItemInfoW (hMenu, id, FALSE , &info)) {
199+ std::println (" Failed to get menu item info for id {}" , id);
200+ continue ;
201+ }
202+ }
203+
204+ if (info.dwTypeData ) {
205+ cb (info.dwTypeData ,
206+ static_cast <size_t >((id << 16 ) + (size_t )lpName));
207+ }
208+ }
209+ }
210+ DestroyMenu (hMenu);
211+ }
212+
213+ return TRUE ;
214+ },
215+ reinterpret_cast <LONG_PTR>(&callback));
157216}
158217
159218void load_all_res_strings (std::string module ) {
@@ -163,7 +222,11 @@ void load_all_res_strings(std::string module) {
163222 return ;
164223 }
165224 if (!hInstance) {
166- return ;
225+ hInstance = LoadLibraryExA (module .data (), nullptr ,
226+ LOAD_LIBRARY_AS_DATAFILE |
227+ LOAD_LIBRARY_AS_IMAGE_RESOURCE);
228+ if (!hInstance)
229+ return ;
167230 }
168231 auto mod_hash = store_module_name (hInstance);
169232
@@ -175,6 +238,7 @@ void load_all_res_strings(std::string module) {
175238 if (str_data.find (s) != str_data.end ())
176239 return ;
177240 str_data[s] = {id, mod_hash};
241+ str_data_rev[{id, mod_hash}] = s;
178242 });
179243}
180244
@@ -193,8 +257,40 @@ void res_string_loader::init_known_strings() {
193257 load_all_res_strings (dll);
194258 }
195259 dbgout (" [perf] init_known_strings took {}ms" ,
196- std::chrono::duration_cast<std::chrono::milliseconds>(
197- std::chrono::high_resolution_clock::now () - now)
198- .count ());
260+ std::chrono::duration_cast<std::chrono::milliseconds>(
261+ std::chrono::high_resolution_clock::now () - now)
262+ .count ());
263+ }
264+ std::string res_string_loader::string_from_id_string (const std::string &str) {
265+ auto pos = str.find (' @' );
266+ if (pos == std::string::npos) {
267+ return str;
268+ }
269+ auto id_str = str.substr (0 , pos);
270+ auto module_name = str.substr (pos + 1 );
271+
272+ size_t id = std::stoull (id_str);
273+ if (module_name == " 0" ) {
274+ return std::to_string (id);
275+ }
276+
277+ res_string_identifier id_obj{id, std::hash<std::string>{}(module_name)};
278+ std::lock_guard lock (lock_str_data);
279+ auto it = str_data_rev.find (id_obj);
280+ if (it != str_data_rev.end ()) {
281+ return wstring_to_utf8 (it->second );
282+ }
283+ return " " ;
284+ }
285+ std::vector<std::string>
286+ res_string_loader::get_all_ids_of_string (const std::wstring &str) {
287+ std::vector<std::string> ids;
288+ std::lock_guard lock (lock_str_data);
289+ for (const auto &[id, s] : str_data_rev) {
290+ if (s == str) {
291+ ids.push_back (std::to_string (id.id ) + " @" + module_name_cache[id.module ]);
292+ }
293+ }
294+ return ids;
199295}
200296} // namespace mb_shell
0 commit comments