How to use Folder API with Rust

Victor Quiroz Castro 1 Reputation point
2022-11-03T23:22:21.277+00:00

Hello

I need some help to execute the code explained in this example:

https://learn.microsoft.com/en-us/windows/win32/shell/folder-getdetailsof?redirectedfrom=MSDN

Using Rust, I found this in the documentation, but no idea how to use it:

https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/UI/Shell/struct.Folder.html

My main objective is to get the "Media Created" field from a file, as per this thread

https://stackoverflow.com/questions/8351713/how-can-i-extract-the-date-from-the-media-created-column-of-a-video-file

Windows development Windows API - Win32
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. benki 11 Reputation points
    2022-11-12T23:35:57.537+00:00

    The following code may be helpful for you.

       [package]  
       name = "folder_api_sample"  
       version = "0.1.0"  
       authors = ["benki"]  
       edition = "2021"  
         
       [dependencies.windows]  
       version = "0.43"  
       features = [  
           "Win32_Foundation",  
           "Win32_System_Com",  
           "Win32_System_Ole",  
           "Win32_UI_Shell",  
       ]  
    
    
       use std::mem::ManuallyDrop;  
       use windows::{  
           core::{Interface, Result, BSTR, GUID},  
           w,  
           Win32::{  
               System::Com::{  
                   CoCreateInstance, CoInitialize, CoUninitialize, CLSCTX_SERVER, VARIANT, VT_BSTR,  
                   VT_DISPATCH,  
               },  
               UI::Shell::IShellDispatch,  
           },  
       };  
         
       // shldisp.h  
       const CLSID_SHELL: GUID = GUID {  
           data1: 0x13709620,  
           data2: 0xC279,  
           data3: 0x11CE,  
           data4: [0xA4, 0x9E, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00],  
       };  
         
       struct Com;  
       impl Drop for Com {  
           fn drop(&mut self) {  
               unsafe { CoUninitialize() };  
           }  
       }  
         
       struct Variant(VARIANT);  
       impl Drop for Variant {  
           fn drop(&mut self) {  
               unsafe {  
                   match self.0.Anonymous.Anonymous.vt {  
                       VT_BSTR => {  
                           ManuallyDrop::drop(&mut ((*self.0.Anonymous.Anonymous).Anonymous.bstrVal))  
                       }  
                       VT_DISPATCH => {  
                           ManuallyDrop::drop(&mut ((*self.0.Anonymous.Anonymous).Anonymous.pdispVal))  
                       }  
                       _ => (),  
                   }  
                   ManuallyDrop::drop(&mut self.0.Anonymous.Anonymous);  
               }  
           }  
       }  
         
       fn main() -> Result<()> {  
           unsafe {  
               CoInitialize(None)?;  
               let _com = Com;  
         
               let shell: IShellDispatch = CoCreateInstance(&CLSID_SHELL, None, CLSCTX_SERVER)?;  
         
               let mut dir = VARIANT::default();  
               (*dir.Anonymous.Anonymous).vt = VT_BSTR;  
               (*dir.Anonymous.Anonymous).Anonymous.bstrVal = ManuallyDrop::new(r"C:\path\to\dir".into());  
               let dir = Variant(dir);  
         
               let folder = shell.NameSpace(&dir.0)?;  
               let name = BSTR::from_wide(w!("file_name.mov").as_wide());  
               let folder_item = folder.ParseName(&name)?;  
         
               let mut item = VARIANT::default();  
               (*item.Anonymous.Anonymous).vt = VT_DISPATCH;  
               (*item.Anonymous.Anonymous).Anonymous.pdispVal =  
                   ManuallyDrop::new(Some(folder_item.cast()?));  
               let item = Variant(item);  
         
               let details = folder.GetDetailsOf(&item.0, 208)?;  
               println!("{details}");  
           }  
           Ok(())  
       }  
    
    2 people found this answer helpful.
    0 comments No comments

  2. Xiaopo Yang - MSFT 12,731 Reputation points Microsoft External Staff
    2022-11-04T05:51:41.603+00:00

    As IShellFolder2::GetDetailsOf said, This method accepts only single-level PIDLs. So, we need Determining an Object's Parent Folder. For more information, see Using the IShellFolder Interface. But for Rust APIs which encapsulate Win32 APIs, you need to consult to Rust community.
    The following code is adapted from Determining an Object's Parent Folder.

    #include <shlobj.h>  
    #include <shlwapi.h>  
    #include <iostream>  
    #pragma comment(lib, "Shlwapi.lib")  
    int main2()  
    {  
        LPITEMIDLIST pidlProgFiles = NULL;  
        LPITEMIDLIST pidlItems = NULL;  
        IShellFolder* psfFirstFolder = NULL;  
        IShellFolder* psfDeskTop = NULL;  
        IShellFolder* psfProgFiles = NULL;  
        LPENUMIDLIST ppenum = NULL;  
        ULONG celtFetched;  
        HRESULT hr;  
        STRRET strDispName;  
        TCHAR pszDisplayName[MAX_PATH];  
        ULONG uAttr;  
      
       CoInitialize(NULL);  
      
       hr = SHGetFolderLocation(NULL, CSIDL_PROGRAM_FILES, NULL, 0, &pidlProgFiles);  
      
       hr = SHGetDesktopFolder(&psfDeskTop);  
    
       hr = psfDeskTop->BindToObject(pidlProgFiles, NULL, IID_IShellFolder, (LPVOID*)&psfProgFiles);  
        psfDeskTop->Release();  
    
       hr = psfProgFiles->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &ppenum);  
      
       IShellFolder2* tmp = (IShellFolder2*)psfProgFiles;  
        SHELLDETAILS psd{};  
        while (hr = ppenum->Next(1, &pidlItems, &celtFetched) == S_OK && (celtFetched) == 1)  
        {  
            psfProgFiles->GetDisplayNameOf(pidlItems, SHGDN_INFOLDER, &strDispName);  
            StrRetToBuf(&strDispName, pidlItems, pszDisplayName, MAX_PATH);  
            std::cout << pszDisplayName << '\n';  
    
      
           //hr = tmp->GetDetailsOf(pidlItems, 190, &psd);  
            //hr = tmp->GetDetailsOf(pidlItems, 191, &psd);  
            //hr = tmp->GetDetailsOf(pidlItems, 3, &psd);  
            hr = tmp->GetDetailsOf(NULL, 208, &psd);  
            hr = tmp->GetDetailsOf(pidlItems, 208, &psd);  
    
      
           if (!psfFirstFolder)  
            {  
                uAttr = SFGAO_FOLDER;  
                psfProgFiles->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlItems, &uAttr);  
                if (uAttr & SFGAO_FOLDER)  
                {  
                    hr = psfProgFiles->BindToObject(pidlItems, NULL, IID_IShellFolder, (LPVOID*)&psfFirstFolder);  
                }  
            }  
            CoTaskMemFree(pidlItems);  
        }  
    
       std::cout << "\n\n";  
    
       ppenum->Release();  
    
       if (psfFirstFolder)  
        {  
            hr = psfFirstFolder->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &ppenum);  
     
           while (hr = ppenum->Next(1, &pidlItems, &celtFetched) == S_OK && (celtFetched) == 1)  
            {  
                psfFirstFolder->GetDisplayNameOf(pidlItems, SHGDN_INFOLDER, &strDispName);  
                StrRetToBuf(&strDispName, pidlItems, pszDisplayName, MAX_PATH);  
                std::cout << pszDisplayName << '\n';  
                CoTaskMemFree(pidlItems);  
            }  
        }  
      
       ppenum->Release();  
        CoTaskMemFree(pidlProgFiles);  
        psfProgFiles->Release();  
        psfFirstFolder->Release();  
     
       CoUninitialize();  
        return 0;  
    }  
      
      
      
    int main()  
    {  
        IShellFolder2* psfParent = NULL;  
        LPITEMIDLIST pidlSystem = NULL;  
        LPCITEMIDLIST pidlRelative = NULL;  
        STRRET strDispName{};  
        TCHAR szDisplayName[MAX_PATH];  
        HRESULT hr;  
      
       CoInitialize(NULL);  
        hr = SHGetFolderLocation(NULL, CSIDL_ADMINTOOLS, NULL, NULL, &pidlSystem);  
      
       hr = SHBindToParent(pidlSystem, IID_IShellFolder, (void**)&psfParent, &pidlRelative);  
      
       if (SUCCEEDED(hr))  
        {  
            hr = psfParent->GetDisplayNameOf(pidlRelative, SHGDN_NORMAL, &strDispName);  
            hr = StrRetToBuf(&strDispName, pidlSystem, szDisplayName, sizeof(szDisplayName));  
            std::cout << "SHGDN_NORMAL - " << szDisplayName << '\n';  
      
           SHELLDETAILS psd{};  
            //hr = psfParent->GetDetailsOf(NULL, 0, &psd);  
            //hr = psfParent->GetDetailsOf(NULL, 1, &psd);  
            //hr = psfParent->GetDetailsOf(NULL, 2, &psd);  
            //hr = psfParent->GetDetailsOf(NULL, 3, &psd);  
            //hr = psfParent->GetDetailsOf(NULL, 4, &psd);  
            //hr = psfParent->GetDetailsOf(NULL, 5, &psd);  
            //hr = psfParent->GetDetailsOf(NULL, 6, &psd);  
            //hr = psfParent->GetDetailsOf(NULL, 7, &psd);  
            //hr = psfParent->GetDetailsOf(NULL, 8, &psd);  
            //hr = psfParent->GetDetailsOf(NULL, 191, &psd);  
            //hr = psfParent->GetDetailsOf(NULL, 177, &psd);  
            hr = psfParent->GetDetailsOf(NULL, 208, &psd);  
            hr = psfParent->GetDetailsOf(pidlRelative, 3, &psd);  
            hr = psfParent->GetDetailsOf(pidlRelative, 208, &psd);  
            //hr = psfParent->GetDetailsOf(pidlRelative, 4, &psd);  
        }  
      
       psfParent->Release();  
        CoTaskMemFree(pidlSystem);  
       return 0;  
    }  
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.