查找本地化的Windows字符串

ndh0cuux  于 2023-03-13  发布在  Windows
关注(0)|答案(5)|浏览(142)

我需要查找当前版本的Windows正在使用的一些字符串。例如,当我创建新文件夹时,它在英语Vista上的初始名称为“New Folder”。我需要以编程方式查找该文件夹在我可能运行的任何语言和版本的Windows上的名称。
有人知道怎么做吗?
谢谢Morinar --我也是偶然发现这篇文章的。不幸的是,stringID看起来并不是常数--在我的Vista上是30396,这与他们在XP上显示的不一样。所以看起来MS没有保持它的稳定。
编辑:看起来这是不可能的...?这个应用程序运行在德国,荷兰,法国,西班牙,巴西,墨西哥,越南,台湾,中国,日本,韩国,印度,以色列,匈牙利...你的想法。这将需要很长的时间来安装所有不同的语言包,并找出'新文件夹'是在每种语言。
也许最好的选择是默认为“新文件夹”,并让用户更改该值,如果他们想要的话。我只是更喜欢让软件尽可能多地弄清楚,让用户免于配置_yet_another_setting_。

hwamh0ep

hwamh0ep1#

无耻地抄袭http://blogs.msdn.com/oldnewthing/archive/2004/01/30/65013.aspx。这基本上是正确的,但如果有一个资源字符串“New Folder something else”,它将匹配:

LPCWSTR FindStringResourceEx(HINSTANCE hinst,
    UINT uId, UINT langId)
{
    // Convert the string ID into a bundle number
    LPCWSTR pwsz = NULL;
    HRSRC hrsrc = FindResourceEx(hinst, RT_STRING,
        MAKEINTRESOURCE(uId / 16 + 1),
        langId);
    if (hrsrc) {
        HGLOBAL hglob = LoadResource(hinst, hrsrc);
        if (hglob) {
            pwsz = reinterpret_cast<LPCWSTR>
                (LockResource(hglob));
            if (pwsz) {
                // okay now walk the string table
                for (int i = 0; i < (uId & 15); i++) {
                    pwsz += 1 + (UINT)*pwsz;
                }

                pwsz+= 1;
            }
        }
    }
    return pwsz;
}

UINT FindResourceStringId(HMODULE resource_handle, LPCWSTR string, UINT langId)
{
    UINT resource_id= -1;

    for (int i= 0; i<65536; ++i)
    {
        LPCWSTR resource_string= FindStringResourceEx(resource_handle, i, langId);

        if (resource_string && wcsncmp(resource_string, string, wcslen(string))==0)
        {
            resource_id= i;
        }
    }

    return resource_id;
}

int main()
{
    HMODULE shell_handle= LoadLibraryW(L"shell32.dll");
    UINT new_folder_id= FindResourceStringId(shell_handle, L"New Folder", 0x409); // look for US English "New Folder" resource id.
}
nfs0ujit

nfs0ujit2#

这并不容易。这些字符串是Windows资源管理器的私有数据,因此它们可以(而且很可能)在不同版本之间更改。您可以在进行大量版本检查并读取相应的资源字符串的地方进行修改,但这似乎是一场失败的战斗。您试图完成什么?

xpszyzbs

xpszyzbs3#

不确定是否有更优雅的方法(我似乎找不到),但这些字符串存储在%windir%\System32\Shell32.dll中,理论上,您只需读取该文件并提取适当的字符串。
看起来有点古怪,但应该能完成任务。这里有一篇文章的链接,讨论了他们在所说的文件中的位置:http://www.askvg.com/customize-new-folder-and-new-shortcut-text-in-windows-xp/
似乎可以甚至应该有一个接口,他们通过Windows API,但拖过文档,我找不到一个。也许你会有更多的运气。

9gm1akwq

9gm1akwq4#

FindResourceStringEx(resource_handle, new_folder_id, language_id)
返回return pwsz;一般不会起作用,因为pwsz不是以空结尾的,因此需要长度,但我不知道如何返回长度和指针这两个值,所以我分配了一个新的字符串。
我还想优化掉uId / 16uId & 15
在真实的使用中,代码将位于两个脚本中,getNumbers和useNumbers,因此我将它们放在两个脚本中
getLocalizationNumbers.c

#include <Windows.h>
#include <stdio.h>

int main()
{
    WORD langId = 0x409; //0x409=english
    HMODULE hModule = LoadLibrary("shell32.dll");
    LPCWSTR stringToSearch = L"New Folder";
    // HMODULE hModule = LoadLibrary("shell32.dll");
    // LPCWSTR stringToSearch = L"Desktop";

    USHORT length_stringToSearch = wcslen(stringToSearch);
    for (size_t i = 1; i < 4097; ++i) {
        HRSRC hrsrc = FindResourceEx(hModule,RT_STRING,MAKEINTRESOURCE(i),langId);
        if (hrsrc) {
            HGLOBAL hglob = LoadResource(hModule, hrsrc);
            if (hglob) {
                LPCWSTR pwsz = (LPCWSTR)LockResource(hglob);
                if (pwsz) {
                    // okay now walk the string table
                    for (size_t j = 0; j < 16; j++) {
                        USHORT length = *pwsz;
                        ++pwsz;
                        if (length==length_stringToSearch && wcsncmp(pwsz, stringToSearch, length_stringToSearch)==0) {
                            printf("%llu\n", 16*(i-1)+j);
                        }
                        pwsz += length;
                    }
                }
            }
        }
    }
}

getLocalizationSpecifyLangId.c

#include <Windows.h>
#include <stdio.h>

wchar_t * getLocalizationSpecifyLangId(HMODULE hModule, UINT uId, WORD langId) {

    wchar_t *localizedString = 0;

    HRSRC hrsrc = FindResourceEx(hModule,RT_STRING,MAKEINTRESOURCE(uId/16 + 1),langId);
    if (hrsrc) {
        HGLOBAL hglob = LoadResource(hModule, hrsrc);
        if (hglob) {
            LPCWSTR pwsz = (LPCWSTR)LockResource(hglob);
            if (pwsz) {
                size_t end = uId & 15;
                for (size_t j = 0; j < end; j++) {
                    pwsz += 1 + *pwsz;
                }
                USHORT length = *pwsz;
                localizedString=(wchar_t *)malloc(sizeof(wchar_t)*(length+1));
                ++pwsz;
                memcpy(localizedString,pwsz,sizeof(wchar_t)*length);
                localizedString[length] = 0;
            }
        }
    }
    return localizedString;
}

int main()
{
    HMODULE hModule = LoadLibrary("shell32.dll");
    wprintf(L"%ls\n", getLocalizationSpecifyLangId(hModule, 4162, 0x409)); //4162="Desktop",0x409=english
    wprintf(L"%ls\n", getLocalizationSpecifyLangId(hModule, 16859, 0x409)); //16859="New Folder",0x409=english

}
omvjsjqw

omvjsjqw5#

如果你想处理80%的案件,你可以从“新建文件夹”开始。
我猜您是在企业环境中,您可以将文件夹名称放回存储器中,然后在一周后(或任何时间)完成名称;更新您的应用程序;释放这新版本这将请用户.(然后稍后公布这结果在这里)
您可以在您怀疑用户使用的一系列平台上抢先测试您的应用。以获得第一系列文件夹名称。
这将避免处理特定于您正在查看的每个平台的代码的问题。

EDIT好吧,我得到了第二个想法,我猜你可能想警告用户关于“新文件夹”,如果它没有重命名后一段时间(比如一分钟)?然后我猜你会需要添加一个列表和一个计时器...

相关问题