65.9K
CodeProject 正在变化。 阅读更多。
Home

获取和设置桌面文件夹名称

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (32投票s)

2003年1月25日

CPOL

2分钟阅读

viewsIcon

100141

downloadIcon

855

提供可复制/粘贴的函数,用于检索本地化的文件夹名称,以及设置/获取桌面文件夹的用户自定义文件夹名称

引言

在开发某个应用程序时,我们需要检索桌面上的某些常用 shell 文件夹的名称,例如“我的电脑”、“回收站”等。我们很快发现,默认情况下,每个操作系统都带有预定义的名称,具体取决于所使用的操作系统语言版本。这些字符串存储在 Shell32.dll 中。但是,用户可以自由地重命名这些文件夹中的任何一个,当他这样做时,新的字符串将存储在注册表中。我不知道有多少人会发现这段代码有用,但如果有人遇到需要这样做的情况,他就不必花费我们花费的漫长时间,才发现这仅仅是读取 Shell32.dll 和注册表的问题。 我编写了一些函数,您可以通过包含单个头文件直接在程序中使用它们。

典型用法

// This will retrieve the localized
// names stored in Shell32.dll
cout << "Localized folder names\r\n";
cout << "------------------------------\r\n";
cout << GetLocalizedName(MyComputer) << "\r\n";
cout << GetLocalizedName(MyDocuments) << "\r\n";
cout << GetLocalizedName(NetworkNeighbourhood) << "\r\n";
cout << GetLocalizedName(RecycleBin) << "\r\n";
cout << GetLocalizedName(InternetExplorer) << "\r\n";

cout << "\r\n";

// Let's change the user defined names
// that are stored in the registry
SetCustomName(MyComputer,"Nish's Computer");
SetCustomName(RecycleBin,"Trash Can");

// This retrieves the user defined names
// from the registry
cout << "User-defined folder names\r\n";
cout << "------------------------------\r\n";
cout << GetCustomName(MyComputer) << "\r\n";
cout << GetCustomName(MyDocuments) << "\r\n";
cout << GetCustomName(NetworkNeighbourhood) << "\r\n";
cout << GetCustomName(RecycleBin) << "\r\n";
cout << GetCustomName(InternetExplorer) << "\r\n"; 

函数

对于所有三个函数,我都在使用自定义 enum 来指定桌面文件夹

enum IconFolder
{
    MyComputer,
    MyDocuments,
    NetworkNeighbourhood,
    RecycleBin,
    InternetExplorer
};

GetLocalizedName

CString GetLocalizedName(IconFolder folder)
{
    HMODULE sh32lib = LoadLibrary("Shell32.dll");
    char buff[256];

    switch(folder)
    {
    case MyComputer:
        LoadString(sh32lib,9216,buff,255);
        break;
    case MyDocuments:
        LoadString(sh32lib,9227,buff,255);
        break;
    case NetworkNeighbourhood:
        LoadString(sh32lib,9217,buff,255);
        break;
    case RecycleBin:
        LoadString(sh32lib,8964,buff,255);
        break;
    case InternetExplorer:
        LoadString(sh32lib,9222,buff,255);
        break;
    default:
        strcpy(buff,"Invalid Folder Request");
        break;
    }

    FreeLibrary(sh32lib);
    return CString(buff);
}

正如您所看到的,我所做的只是从 Shell32.dll 加载字符串,字符串表条目标识符是硬编码的,我已经在 Windows XP 家庭版和专业版上测试过。 我相信它们对于 Windows 2000 版本也是相同的,但我不确定其他操作系统,如 Windows ME。 如果有人可以测试并告诉我,那就太好了。

GetCustomName

CString GetCustomName(IconFolder folder)
{
    HKEY hKey = 0;
    CString keyname = 
        "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\";

    switch(folder)
    {
    case MyComputer:
        keyname += "{20D04FE0-3AEA-1069-A2D8-08002B30309D}";
        break;
    case MyDocuments:
        keyname += "{450D8FBA-AD25-11D0-98A8-0800361B1103}";
        break;
    case NetworkNeighbourhood:
        keyname += "{208D2C60-3AEA-1069-A2D7-08002B30309D}";
        break;
    case RecycleBin:
        keyname += "{645FF040-5081-101B-9F08-00AA002F954E}";
        break;
    case InternetExplorer:
        keyname += "{871C5380-42A0-1069-A2EA-08002B30309D}";
        break;
    default:        
        keyname = "";
        break;
    }

    BYTE buff[256];

    if(keyname.GetLength())
    {
        LONG result = ::RegOpenKeyEx(HKEY_CURRENT_USER,
            (LPCTSTR)keyname,0,KEY_READ,&hKey);

        ZeroMemory(buff,255);
        DWORD sz = sizeof buff;
        DWORD typ = REG_SZ;

        RegQueryValueEx(hKey,"",0,&typ,buff,&sz);

        RegCloseKey(hKey);
    }
    else
    {
        return CString("Invalid Folder Request");
    }

    if(CString(buff).GetLength())
        return CString(buff);
    else
        return CString("No custom definition");
}

嗯,这也很简单; 只是读取一些注册表项的问题。 基本上,操作系统在显示桌面图标时也是这样做的,它首先读取这些注册表值,如果它们为空,那么它将从 Shell32.dll 中提取字符串。

SetCustomName

void SetCustomName(IconFolder folder, CString foldername)
{
    HKEY hKey = 0;
    CString keyname = 
        "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\";

    switch(folder)
    {
    case MyComputer:
        keyname += "{20D04FE0-3AEA-1069-A2D8-08002B30309D}";
        break;
    case MyDocuments:
        keyname += "{450D8FBA-AD25-11D0-98A8-0800361B1103}";
        break;
    case NetworkNeighbourhood:
        keyname += "{208D2C60-3AEA-1069-A2D7-08002B30309D}";
        break;
    case RecycleBin:
        keyname += "{645FF040-5081-101B-9F08-00AA002F954E}";
        break;
    case InternetExplorer:
        keyname += "{871C5380-42A0-1069-A2EA-08002B30309D}";
        break;
    default:        
        keyname = "";
        break;
    }

    if(keyname.GetLength())
    {
        LONG result = ::RegOpenKeyEx(HKEY_CURRENT_USER,
            (LPCTSTR)keyname,0,KEY_WRITE,&hKey);

        RegSetValueEx(hKey,"",0,REG_SZ,
            (const BYTE*)foldername.GetBuffer(0),foldername.GetLength());
        foldername.ReleaseBuffer();

        RegCloseKey(hKey);

        LPITEMIDLIST pidl;
        SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&pidl);
        SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,pidl,0);
    }
}

在这里,我们只是使用新的自定义字符串更新注册表项。 如果您保存 NULL 字符串,那么操作系统将使用 Shell32.dll 中的特定于语言的字符串。 最后有一些有趣的代码,我用它来强制刷新桌面图标名称。 我尝试了各种方法,从使桌面无效、发送 WM_PAINT 消息到发送 F5 键消息,但它们都没有奏效。 这是唯一对我有用的代码。

刷新桌面技巧(保存此技巧)

LPITEMIDLIST pidl;
SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&pidl);
SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,pidl,0);

结论

使用这些类型的注册表读取和 DLL 字符串读取的基本问题是,您永远不知道 Microsoft 何时会在他们的下一个操作系统版本中更改字符串标识符或注册表位置。 但这是你必须承担的风险,并且每当他们做出更改时,你都必须做好准备进行版本检查,并根据检测到的操作系统版本执行所需的操作。 我希望至少有一些人从本文中受益。 欢迎通过本文底部的论坛提交您的反馈。

© . All rights reserved.