static nfdresult_t SetDefaultPath( IFileDialog *dialog, const char *defaultPath ) { if ( !defaultPath || strlen(defaultPath) == 0 ) return NFD_OKAY; wchar_t *defaultPathW = {0}; CopyNFDCharToWChar( defaultPath, &defaultPathW ); IShellItem *folder; HRESULT result = SHCreateItemFromParsingName( defaultPathW, NULL, IID_PPV_ARGS(&folder) ); // Valid non results. if ( result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || result == HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE) ) { NFDi_Free( defaultPathW ); return NFD_OKAY; } if ( !SUCCEEDED(result) ) { NFDi_SetError("Error creating ShellItem"); NFDi_Free( defaultPathW ); return NFD_ERROR; } // Could also call SetDefaultFolder(), but this guarantees defaultPath -- more consistency across API. dialog->SetFolder( folder ); NFDi_Free( defaultPathW ); folder->Release(); return NFD_OKAY; }
static nfdresult_t SetDefaultPath( IFileDialog *dialog, const char *defaultPath ) { if ( !defaultPath || strlen(defaultPath) == 0 ) return NFD_OKAY; wchar_t *defaultPathW = {0}; CopyNFDCharToWChar( defaultPath, &defaultPathW ); PIDLIST_ABSOLUTE pidl; HRESULT result = ::SHParseDisplayName( defaultPathW, 0, &pidl, SFGAO_FOLDER, 0 ); // Valid non results. if ( result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || result == HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE) ) { NFDi_Free( defaultPathW ); return NFD_OKAY; } IShellItem *folder; if ( SUCCEEDED(result) ) { result = ::SHCreateShellItem( NULL, NULL, pidl, &folder ); ILFree(pidl); } if ( !SUCCEEDED(result) ) { NFDi_SetError("Error creating ShellItem"); NFDi_Free( defaultPathW ); return NFD_ERROR; } // Could also call SetDefaultFolder(), but this guarantees defaultPath -- more consistency across API. dialog->SetFolder( folder ); NFDi_Free( defaultPathW ); folder->Release(); return NFD_OKAY; }
static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char *filterList ) { const wchar_t EMPTY_WSTR[] = L""; const wchar_t WILDCARD[] = L"*.*"; if ( !filterList || strlen(filterList) == 0 ) return NFD_OKAY; // Count rows to alloc UINT filterCount = 1; /* guaranteed to have one filter on a correct, non-empty parse */ const char *p_filterList; for ( p_filterList = filterList; *p_filterList; ++p_filterList ) { if ( *p_filterList == ';' ) ++filterCount; } assert(filterCount); if ( !filterCount ) { NFDi_SetError("Error parsing filters."); return NFD_ERROR; } /* filterCount plus 1 because we hardcode the *.* wildcard after the while loop */ COMDLG_FILTERSPEC *specList = (COMDLG_FILTERSPEC*)NFDi_Malloc( sizeof(COMDLG_FILTERSPEC) * (filterCount + 1) ); if ( !specList ) { return NFD_ERROR; } for (size_t i = 0; i < filterCount+1; ++i ) { specList[i].pszName = NULL; specList[i].pszSpec = NULL; } size_t specIdx = 0; p_filterList = filterList; char typebuf[NFD_MAX_STRLEN] = {0}; /* one per comma or semicolon */ char *p_typebuf = typebuf; char filterName[NFD_MAX_STRLEN] = {0}; char specbuf[NFD_MAX_STRLEN] = {0}; /* one per semicolon */ while ( 1 ) { if ( NFDi_IsFilterSegmentChar(*p_filterList) ) { /* append a type to the specbuf (pending filter) */ AppendExtensionToSpecBuf( typebuf, specbuf, NFD_MAX_STRLEN ); p_typebuf = typebuf; memset( typebuf, 0, sizeof(char)*NFD_MAX_STRLEN ); } if ( *p_filterList == ';' || *p_filterList == '\0' ) { /* end of filter -- add it to specList */ // Empty filter name -- Windows describes them by extension. specList[specIdx].pszName = EMPTY_WSTR; CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszSpec ); memset( specbuf, 0, sizeof(char)*NFD_MAX_STRLEN ); ++specIdx; if ( specIdx == filterCount ) break; } if ( !NFDi_IsFilterSegmentChar( *p_filterList )) { *p_typebuf = *p_filterList; ++p_typebuf; } ++p_filterList; } /* Add wildcard */ specList[specIdx].pszSpec = WILDCARD; specList[specIdx].pszName = EMPTY_WSTR; fileOpenDialog->SetFileTypes( filterCount+1, specList ); /* free speclist */ for ( size_t i = 0; i < filterCount; ++i ) { NFDi_Free( (void*)specList[i].pszSpec ); } NFDi_Free( specList ); return NFD_OKAY; }
nfdresult_t NFD_ChooseDirectory(const nfdchar_t *prompt, const nfdchar_t *defaultPath, nfdchar_t **outPath ) { nfdresult_t nfdResult = NFD_ERROR; // Init COM library. HRESULT result = ::CoInitializeEx(NULL, ::COINIT_APARTMENTTHREADED | ::COINIT_DISABLE_OLE1DDE ); wchar_t *promptW = {0}; if (prompt && strlen(prompt)) CopyNFDCharToWChar( prompt, &promptW ); if ( !SUCCEEDED(result)) { NFDi_SetError("Could not initialize COM."); goto end; } ::IFileOpenDialog *fileOpenDialog(NULL); // Create dialog result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL, CLSCTX_ALL, ::IID_IFileOpenDialog, reinterpret_cast<void**>(&fileOpenDialog) ); if ( !SUCCEEDED(result) ) { NFDi_SetError("Could not create dialog."); goto end; } DWORD dwOptions; if (SUCCEEDED(fileOpenDialog->GetOptions(&dwOptions))) { fileOpenDialog->SetOptions(dwOptions | FOS_PICKFOLDERS); } // Set the default path if ( !SetDefaultPath( fileOpenDialog, defaultPath ) ) { goto end; } fileOpenDialog->SetTitle(promptW); // Show the dialog. result = fileOpenDialog->Show(NULL); if ( SUCCEEDED(result) ) { // Get the file name ::IShellItem *shellItem(NULL); result = fileOpenDialog->GetResult(&shellItem); if ( !SUCCEEDED(result) ) { NFDi_SetError("Could not get shell item from dialog."); goto end; } wchar_t *filePath(NULL); result = shellItem->GetDisplayName(::SIGDN_FILESYSPATH, &filePath); if ( !SUCCEEDED(result) ) { NFDi_SetError("Could not get file path for selected."); goto end; } CopyWCharToNFDChar( filePath, outPath ); CoTaskMemFree(filePath); if ( !*outPath ) { /* error is malloc-based, error message would be redundant */ goto end; } nfdResult = NFD_OKAY; shellItem->Release(); } else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED) ) { nfdResult = NFD_CANCEL; } else { NFDi_SetError("File dialog box show failed."); nfdResult = NFD_ERROR; } end: if (prompt && strlen(prompt)); NFDi_Free( promptW ); ::CoUninitialize(); return nfdResult; }