C++ 项目相关知识命名空间

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 项目相关知识命名空间相关的知识,希望对你有一定的参考价值。

参考技术A

命名空间一般是对全局变量,函数,类做处理的,以防多个重名变量引起的重定义错误。命名空间主要分为三种

你指定了一个名字为A的命名空间。这种命名空间具有外部链接属性,也就是说这个空间里的变量和函数会和其他文件同一名字的命名空间一起链接。
在同一个项目里,test1.cpp的内容为

把main.cpp内容为

编译链接的时候就会报错

重定义错误,因为在同一个命名空间里有多个同名变量分配了不同空间地址,a在test1.cpp里分配了空间,也在main.cpp里分配了空间。链接器不知道哪个空间才是该变量的正确地址。
所以不能在多个文件的同一个命名空间里定义同名变量,只能在其中一个文件定义,而别的文件里声明引用,对这两个文件进行如下修改
test1.cpp内容改成

main.cpp内容改成

结果是

使用另外一个cpp里命名空间里的变量的方法
test1.cpp里内容如下

main.cpp里内容如下

输出结果为

另一个"main.cpp"

运行结果如下

输出结果

你可以省略命名空间的名字,则该空间的所有变量只能被当前文件所引用,而不能被同一个项目里别的文件使用。这些变量具有internal链接属性,这和声明为static的全局名称的链接属性是相同的,即名称的作用域被限制在当前文件中,无法通过在另外的文件中使用extern声明来进行链接。命名空间都是具有external 连接属性的,只是匿名的命名空间产生的 UNIQUE_NAME 在别的文件中无法得到,这个唯一的名字是不可见的。

无法获取 Windows 7 C++ 上虚拟文件夹的路径(shell 命名空间扩展相关)

【中文标题】无法获取 Windows 7 C++ 上虚拟文件夹的路径(shell 命名空间扩展相关)【英文标题】:cannot get the path for the virtual folder on windows 7 C++(shell namespace extension related) 【发布时间】:2017-11-07 23:05:19 【问题描述】:

通过使用 Microsoft windows SDK 7.0 explorerDataProvider,我在 windows 7 上安装了一个虚拟文件夹。

当我从应用程序打开文件浏览对话框时,

CFileDialog dlg(TRUE, NULL, 0, OFN_ENABLESIZING | OFN_ALLOWMULTISELECT, L"all(*.*)|*.*||", this);

INT_PTR result = dlg.DoModal();

if (result == IDOK)

   .
   . 
   .
   //some actions

它还可以显示虚拟文件夹:

但是当我选择文件的时候,像“零”然后可以点击“打开”,

我尝试添加断点

INT_PTR result = dlg.DoModal();

但似乎这个错误发生在DoModal()内部。

我正在研究并修改虚拟文件夹的代码:

HRESULT CFolderViewImplFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, ULONG *rgfInOut)

// If SFGAO_FILESYSTEM is returned, GetDisplayNameOf(SHGDN_FORPARSING) on that item MUST
// return a filesystem path.
HRESULT hr = E_INVALIDARG;

DWORD dwAttribs = 0;
dwAttribs |= SFGAO_BROWSABLE;
if (1 == cidl)

    int nLevel = 0;
    hr = _GetLevel(apidl[0], &nLevel);
    if (SUCCEEDED(hr))
    
        BOOL fIsFolder = FALSE;
        hr = _GetFolderness(apidl[0], &fIsFolder);
        if (SUCCEEDED(hr))
        

            if (fIsFolder)
            
                dwAttribs |= SFGAO_FOLDER;

                dwAttribs |= SFGAO_FILESYSANCESTOR;
            
            else
            
                dwAttribs |= SFGAO_SYSTEM;

                dwAttribs |= SFGAO_FILESYSTEM;
            

            if (nLevel < g_nMaxLevel)
            
                dwAttribs |= SFGAO_HASSUBFOLDER;
            
        
    


*rgfInOut &= dwAttribs;

return hr;

并返回GetDisplayNameOf()中的路径

HRESULT CFolderViewImplFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF shgdnFlags, STRRET *pName)

HRESULT hr = S_OK;
if (shgdnFlags & SHGDN_FORPARSING)

    WCHAR szDisplayName[MAX_PATH];
    if (shgdnFlags & SHGDN_INFOLDER)
    
        // This form of the display name needs to be handled by ParseDisplayName.
        hr = _GetName(pidl, szDisplayName, ARRAYSIZE(szDisplayName));
    
    else
    
        PWSTR pszThisFolder = L"Computer\\Jerry";

            StringCchCopy(szDisplayName, ARRAYSIZE(szDisplayName), pszThisFolder);
            StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), L"\\");

            WCHAR szName[MAX_PATH];
            hr = _GetName(pidl, szName, ARRAYSIZE(szName));
            if (SUCCEEDED(hr))
            
                StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), szName);
            
    
    if (SUCCEEDED(hr))
    
        hr = StringToStrRet(szDisplayName, pName);
    

else

    PWSTR pszName;
    hr = _GetName(pidl, &pszName);
    if (SUCCEEDED(hr))
    
        hr = StringToStrRet(pszName, pName);
        CoTaskMemFree(pszName);
    

return hr;

但它仍然在应用程序中显示“路径不存在”的错误消息。 我在GetDisplayNameOf 中添加了断点,但是当应用程序打开文件浏览对话框时它永远不会触发。但是如果我只是双击“计算机”打开一个普通文件夹,它就会被触发。

“路径不存在”的错误消息似乎不能被弃用或覆盖。有什么方法可以修改虚拟文件夹以返回正确的路径?


更新:我试过IFileDialog,我复制了MSDN示例中的代码,代码,加断点看看会发生什么。然而,

// Show the dialog
hr = pfd->Show(NULL);//the breakpoint is added here
if (SUCCEEDED(hr))

  // Obtain the result once the user clicks 
 // the 'Open' button.
 // The result is an IShellItem object.
 IShellItem *psiResult;
 hr = pfd->GetResult(&psiResult);
 if (SUCCEEDED(hr))
 
   //do something
 

当我点击“打开”按钮时,仍然出现“路径不存在,请检查路径并重试”的错误消息框。在我点击“打开”按钮后,它永远不会从pfd-&gt;Show(NULL) 中出来。

根据示例代码中的 cmets,它应该来自 hr = pfd-&gt;Show(NULL); 并到达下一行。但错误消息发生在 hr = pfd-&gt;Show(NULL); 内。

更新

IFileDialog,我试过了

hr = pfd->GetOptions(&dwFlags);
            if (SUCCEEDED(hr))
            

                hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS);
                if (SUCCEEDED(hr))
                
                    // Show the dialog
                    hr = pfd->Show(NULL);
                    if (SUCCEEDED(hr))
                    
                        // Obtain the result once the user clicks 
                        // the 'Open' button.
                        // The result is an IShellItem object.
                        IShellItem *psiResult;
                        hr = pfd->GetResult(&psiResult);
                        if (SUCCEEDED(hr))
                        
                            // We are just going to print out the 
                            // name of the file for sample sake.
                            PWSTR pszFilePath = NULL;
                            hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH,
                                &pszFilePath);
                            if (SUCCEEDED(hr))
                            
                                TaskDialog(NULL,
                                    NULL,
                                    L"CommonFileDialogApp",
                                    pszFilePath,
                                    NULL,
                                    TDCBF_OK_BUTTON,
                                    TD_INFORMATION_ICON,
                                    NULL);
                                CoTaskMemFree(pszFilePath);
                            
                            psiResult->Release();
                        
                    

                

我也试过了

hr = pfd->SetOptions(dwFlags);//delete FOS_FORCEFILESYSTEM         

试过了

DWORD dwFlags = 0;
if (SUCCEEDED(hr))

    // overwrite options completely
    hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS);

我还尝试在命名空间扩展代码中返回全名:

WCHAR szDisplayName[MAX_PATH];
    if (shgdnFlags & SHGDN_INFOLDER)
    
        // This form of the display name needs to be handled by ParseDisplayName.
        hr = _GetName(pidl, szDisplayName, ARRAYSIZE(szDisplayName));
    
    else
    
        PWSTR pszThisFolder;// = L"Computer\\Jerry";
        hr = SHGetNameFromIDList(m_pidl, (shgdnFlags & SHGDN_FORADDRESSBAR) ? SIGDN_DESKTOPABSOLUTEEDITING : SIGDN_DESKTOPABSOLUTEPARSING, &pszThisFolder);
        if (SUCCEEDED(hr))
        
            StringCchCopy(szDisplayName, ARRAYSIZE(szDisplayName), pszThisFolder);
            StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), L"\\");

            WCHAR szName[MAX_PATH];
            hr = _GetName(pidl, szName, ARRAYSIZE(szName));
            if (SUCCEEDED(hr))
            
                StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), szName);
            
            CoTaskMemFree(pszThisFolder);
        
    
    if (SUCCEEDED(hr))
    
        hr = StringToStrRet(szDisplayName, pName);
    

但结果是:

更新

hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);

这对我有用!!

【问题讨论】:

您的 SNE 是根计算机命名空间的子节点,而不是任何文件系统驱动器的子节点。你可以随心所欲地谎报你的物品属性,你的 SNE 仍然不是文件系统的一部分,所以没有文件系统路径可供对话框检索。很明显,您正在调用一个只知道如何处理文件系统的旧对话框,而不是一个支持虚拟项目的新对话框 @RemyLebeau 你能告诉我哪个较新的对话框可以支持虚拟物品吗? IFile(Open|Save)Dialog,在 Vista 中引入。 CFileDialog 原包装Get(Open|Save)FileName(),只支持文件系统。在 VS2008+ 中,CFileDialog 在其构造函数中有一个bVistaStyle 参数,当您为 Vista+ 编译时,应该默认使用较新的 API。我建议放弃CFileDialog,直接使用IFileOpenDialog @RemyLebeau 你能检查我的更新吗?好像不行。 在显示之前您将哪些选项传递给IFileDialog?请显示minimal reproducible example。您是否偶然启用了FOS_FORCEFILESYSTEM 选项? “确保返回的项目是文件系统项目 (SFGAO_FILESYSTEM)”,而你的不是。您是否尝试过FOS_ALLNONSTORAGEITEM 选项? "使用户能够选择 Shell 命名空间中的任何项目,而不仅仅是那些具有 SFGAO_STREAMSFAGO_FILESYSTEM 属性的项目。" 【参考方案1】:

在@RemyLebeau 的帮助下,我在我的代码中做了一些测试。最后,我找到了适合我的工作解决方案: 我从 MSDN 复制了 IFileDialog 的代码:https://msdn.microsoft.com/en-us/library/windows/desktop/bb776913.aspx#file_types 然后稍微修改一下:

HRESULT BasicFileOpen()

// CoCreate the File Open Dialog object.
IFileDialog *pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog,
    NULL,
    CLSCTX_INPROC_SERVER,
    IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))

    // Create an event handling object, and hook it up to the dialog.
    IFileDialogEvents *pfde = NULL;
    hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
    if (SUCCEEDED(hr))
    
        // Hook up the event handler.
        DWORD dwCookie;
        hr = pfd->Advise(pfde, &dwCookie);
        if (SUCCEEDED(hr))
        
            // Set the options on the dialog.
            DWORD dwFlags = 0;
            if (SUCCEEDED(hr))
            
                // the default flag is FOS_PATHMUSTEXIST and FOS_FILEMUSTEXIST, so I set overwrite it with these two flags.
                hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);
                if (SUCCEEDED(hr))
                
                    // Show the dialog
                    hr = pfd->Show(NULL);
                    if (SUCCEEDED(hr))
                    
                        // Obtain the result once the user clicks 
                        // the 'Open' button.
                        // The result is an IShellItem object.
                        IShellItem *psiResult;
                        hr = pfd->GetResult(&psiResult);
                        if (SUCCEEDED(hr))
                        
                            // We are just going to print out the 
                            // name of the file for sample sake.
                            PWSTR pszFilePath = NULL;
                            hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH,
                                &pszFilePath);
                            if (SUCCEEDED(hr))
                            
                                TaskDialog(NULL,
                                    NULL,
                                    L"CommonFileDialogApp",
                                    pszFilePath,
                                    NULL,
                                    TDCBF_OK_BUTTON,
                                    TD_INFORMATION_ICON,
                                    NULL);
                                CoTaskMemFree(pszFilePath);
                            
                            psiResult->Release();
                        
                    

                
            
            // Unhook the event handler.
            pfd->Unadvise(dwCookie);
        
        pfde->Release();
    
    pfd->Release();

return hr;

关键是用SetOptions覆盖选项。基于MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx,

FOS_PATHMUSTEXIST
The item returned must be in an existing folder. This is a default value.
FOS_FILEMUSTEXIST
The item returned must exist. This is a default value for the Open dialog.

这些标志是阻止它返回的默认值。 所以我把它设置为:

hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);

这些标志意味着:

FOS_NOVALIDATE
Do not check for situations that would prevent an application from opening the selected file, such as sharing violations or access denied errors.

FOS_ALLNONSTORAGEITEMS
Enables the user to choose any item in the Shell namespace, not just those with SFGAO_STREAM or SFAGO_FILESYSTEM attributes. This flag cannot be combined with FOS_FORCEFILESYSTEM.

然后它终于起作用了!

【讨论】:

以上是关于C++ 项目相关知识命名空间的主要内容,如果未能解决你的问题,请参考以下文章

C++入门基础预备知识

C++基础一C++基础入门(20000字掌握C++基础知识)

C++基础一C++基础入门(20000字掌握C++基础知识)

C++基础一C++基础入门(20000字掌握C++基础知识)

java底层知识GC相关

C++ 相关知识总结