A previoius article extends CFileDialog MFC class, in order to make a File Open or a File Save dialog that automatically filters files, according to available WIC (Windows Imaging Component) codecs. This article presents how to show a similar File Open dialog using IFileOpenDialog interface. This way, it can be used not only in an aplication that uses MFC, but also in an ATL one, even in a raw Win32 or console application that uses basic ATL stuff.

Let’s see an example.

Using IFileOpenDialog to show a WIC File Open Dialog

HRESULT ShowWICFileOpenDialog(HWND hWndOwner, CStringW& strFile) { // create IFileOpenDialog instance. CComPtr<IFileOpenDialog> pIFileOpenDialog; HRESULT hr = pIFileOpenDialog.CoCreateInstance(CLSID_FileOpenDialog); // get an array of WIC decoders friendly names and extensions COMDLG_FILTERSPEC* pFilterSpecArray = NULL; UINT cbFilterSpecCount = 0; if(SUCCEEDED(hr)) { hr = GetWICFileOpenDialogFilterSpecs(pFilterSpecArray, cbFilterSpecCount); } // set the filter if(SUCCEEDED(hr)) { hr = pIFileOpenDialog->SetFileTypes(cbFilterSpecCount, pFilterSpecArray); } // show the file open dialog, and get the chosen file if(SUCCEEDED(hr)) { hr = pIFileOpenDialog->Show(hWndOwner); } // get the choosen full path and file name if(SUCCEEDED(hr)) { CComPtr<IShellItem> pIShellItem; hr = pIFileOpenDialog->GetResult(&pIShellItem); if(SUCCEEDED(hr)) { LPWSTR pszName = NULL; hr = pIShellItem->GetDisplayName(SIGDN_FILESYSPATH, &pszName); strFile = pszName; CoTaskMemFree(pszName); } } // do cleanup for(UINT nIndex = 0; nIndex < cbFilterSpecCount; nIndex++) { delete []pFilterSpecArray[nIndex].pszName; delete []pFilterSpecArray[nIndex].pszSpec; } delete []pFilterSpecArray; return hr; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 HRESULT ShowWICFileOpenDialog ( HWND hWndOwner , CStringW & strFile ) { // create IFileOpenDialog instance. CComPtr < IFileOpenDialog > pIFileOpenDialog ; HRESULT hr = pIFileOpenDialog . CoCreateInstance ( CLSID_FileOpenDialog ) ; // get an array of WIC decoders friendly names and extensions COMDLG_FILTERSPEC * pFilterSpecArray = NULL ; UINT cbFilterSpecCount = 0 ; if ( SUCCEEDED ( hr ) ) { hr = GetWICFileOpenDialogFilterSpecs ( pFilterSpecArray , cbFilterSpecCount ) ; } // set the filter if ( SUCCEEDED ( hr ) ) { hr = pIFileOpenDialog -> SetFileTypes ( cbFilterSpecCount , pFilterSpecArray ) ; } // show the file open dialog, and get the chosen file if ( SUCCEEDED ( hr ) ) { hr = pIFileOpenDialog -> Show ( hWndOwner ) ; } // get the choosen full path and file name if ( SUCCEEDED ( hr ) ) { CComPtr < IShellItem > pIShellItem ; hr = pIFileOpenDialog -> GetResult ( &pIShellItem ) ; if ( SUCCEEDED ( hr ) ) { LPWSTR pszName = NULL ; hr = pIShellItem -> GetDisplayName ( SIGDN_FILESYSPATH , &pszName ) ; strFile = pszName ; CoTaskMemFree ( pszName ) ; } } // do cleanup for ( UINT nIndex = 0 ; nIndex < cbFilterSpecCount ; nIndex ++ ) { delete [ ] pFilterSpecArray [ nIndex ] . pszName ; delete [ ] pFilterSpecArray [ nIndex ] . pszSpec ; } delete [ ] pFilterSpecArray ; return hr ; }

Enumerating the WIC decoders

HRESULT GetWICFileOpenDialogFilterSpecs(COMDLG_FILTERSPEC*& pFilterSpecArray, UINT& cbFilterSpecCount) { ATLASSERT(NULL == pFilterSpecArray); cbFilterSpecCount = 1; // we'll use the last one for "All WIC files" CStringW strAllSpecs; // create IWICImagingFactory instance CComPtr<IWICImagingFactory> pIWICImagingFactory; HRESULT hr = pIWICImagingFactory.CoCreateInstance(CLSID_WICImagingFactory); // create WIC decoders enumerator CComPtr<IEnumUnknown> pIEnum; if(SUCCEEDED(hr)) { DWORD dwOptions = WICComponentEnumerateDefault; hr = pIWICImagingFactory->CreateComponentEnumerator(WICDecoder, dwOptions, &pIEnum); } if(SUCCEEDED(hr)) { CComPtr<IUnknown> pElement; ULONG cbActual = 0; // count enumerator elements while(S_OK == pIEnum->Next(1, &pElement, &cbActual)) { ++cbFilterSpecCount; pElement = NULL; } // alloc COMDLG_FILTERSPEC array pFilterSpecArray = new COMDLG_FILTERSPEC[cbFilterSpecCount]; // reset enumaration an loop again to fill filter specs array pIEnum->Reset(); COMDLG_FILTERSPEC* pFilterSpec = pFilterSpecArray; while(S_OK == pIEnum->Next(1, &pElement, &cbActual)) { CComQIPtr<IWICBitmapDecoderInfo> pIWICBitmapDecoderInfo = pElement; // get necessary buffer size for friendly name and extensions UINT cbName = 0, cbFileExt = 0; pIWICBitmapDecoderInfo->GetFriendlyName(0, NULL, &cbName); pIWICBitmapDecoderInfo->GetFileExtensions(0, NULL, &cbFileExt); // get decoder friendly name (*pFilterSpec).pszName = new WCHAR[cbName]; pIWICBitmapDecoderInfo->GetFriendlyName(cbName, (WCHAR*)(*pFilterSpec).pszName, &cbName); // get extensions; wee need to replace some characters according to the specs CStringW strSpec; pIWICBitmapDecoderInfo->GetFileExtensions(cbFileExt, CStrBuf(strSpec, cbFileExt), &cbFileExt); strSpec.Replace(L',', L';'); strSpec.Replace(L".", L"*."); size_t size = strSpec.GetLength() + 1; (*pFilterSpec).pszSpec = new WCHAR[size]; wcscpy_s((wchar_t*)(*pFilterSpec).pszSpec, size, strSpec.GetString()); // append to "All WIC files" specs strSpec += L";"; strAllSpecs += strSpec; ++pFilterSpec; pElement = NULL; } // set "All WIC files" specs strAllSpecs.TrimRight(_T(';')); (*pFilterSpec).pszName = new WCHAR[wcslen(L"All WIC files") + 1]; wcscpy_s((wchar_t*)(*pFilterSpec).pszName, wcslen(L"All WIC files") + 1, L"All WIC files"); (*pFilterSpec).pszSpec = new WCHAR[strAllSpecs.GetLength() + 1]; wcscpy_s((wchar_t*)(*pFilterSpec).pszSpec, strAllSpecs.GetLength() + 1, strAllSpecs.GetString()); } return S_OK; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 HRESULT GetWICFileOpenDialogFilterSpecs ( COMDLG_FILTERSPEC * & pFilterSpecArray , UINT & cbFilterSpecCount ) { ATLASSERT ( NULL == pFilterSpecArray ) ; cbFilterSpecCount = 1 ; // we'll use the last one for "All WIC files" CStringW strAllSpecs ; // create IWICImagingFactory instance CComPtr < IWICImagingFactory > pIWICImagingFactory ; HRESULT hr = pIWICImagingFactory . CoCreateInstance ( CLSID_WICImagingFactory ) ; // create WIC decoders enumerator CComPtr < IEnumUnknown > pIEnum ; if ( SUCCEEDED ( hr ) ) { DWORD dwOptions = WICComponentEnumerateDefault ; hr = pIWICImagingFactory -> CreateComponentEnumerator ( WICDecoder , dwOptions , &pIEnum ) ; } if ( SUCCEEDED ( hr ) ) { CComPtr < IUnknown > pElement ; ULONG cbActual = 0 ; // count enumerator elements while ( S_OK == pIEnum -> Next ( 1 , &pElement , &cbActual ) ) { ++ cbFilterSpecCount ; pElement = NULL ; } // alloc COMDLG_FILTERSPEC array pFilterSpecArray = new COMDLG_FILTERSPEC [ cbFilterSpecCount ] ; // reset enumaration an loop again to fill filter specs array pIEnum -> Reset ( ) ; COMDLG_FILTERSPEC * pFilterSpec = pFilterSpecArray ; while ( S_OK == pIEnum -> Next ( 1 , &pElement , &cbActual ) ) { CComQIPtr < IWICBitmapDecoderInfo > pIWICBitmapDecoderInfo = pElement ; // get necessary buffer size for friendly name and extensions UINT cbName = 0 , cbFileExt = 0 ; pIWICBitmapDecoderInfo -> GetFriendlyName ( 0 , NULL , &cbName ) ; pIWICBitmapDecoderInfo -> GetFileExtensions ( 0 , NULL , &cbFileExt ) ; // get decoder friendly name ( * pFilterSpec ) . pszName = new WCHAR [ cbName ] ; pIWICBitmapDecoderInfo -> GetFriendlyName ( cbName , ( WCHAR * ) ( * pFilterSpec ) . pszName , &cbName ) ; // get extensions; wee need to replace some characters according to the specs CStringW strSpec ; pIWICBitmapDecoderInfo -> GetFileExtensions ( cbFileExt , CStrBuf ( strSpec , cbFileExt ) , &cbFileExt ) ; strSpec . Replace ( L ',' , L ';' ) ; strSpec . Replace ( L "." , L "*." ) ; size_t size = strSpec . GetLength ( ) + 1 ; ( * pFilterSpec ) . pszSpec = new WCHAR [ size ] ; wcscpy_s ( ( wchar_t * ) ( * pFilterSpec ) . pszSpec , size , strSpec . GetString ( ) ) ; // append to "All WIC files" specs strSpec += L ";" ; strAllSpecs += strSpec ; ++ pFilterSpec ; pElement = NULL ; } // set "All WIC files" specs strAllSpecs . TrimRight ( _T ( ';' ) ) ; ( * pFilterSpec ) . pszName = new WCHAR [ wcslen ( L "All WIC files" ) + 1 ] ; wcscpy_s ( ( wchar_t * ) ( * pFilterSpec ) . pszName , wcslen ( L "All WIC files" ) + 1 , L "All WIC files" ) ; ( * pFilterSpec ) . pszSpec = new WCHAR [ strAllSpecs . GetLength ( ) + 1 ] ; wcscpy_s ( ( wchar_t * ) ( * pFilterSpec ) . pszSpec , strAllSpecs . GetLength ( ) + 1 , strAllSpecs . GetString ( ) ) ; } return S_OK ; }

Demo project

The demo project is a simple Win32 console application that uses the above functions.

Download: WIC_File_Open_Dialog_Win32_Demo.zip (1204)

// stdafx.h // ... // ATL #include <atlbase.h> #include <atlstr.h> // Shell #include <Shobjidl.h> // WIC #include <wincodec.h> #pragma comment(lib, "Windowscodecs.lib") 1 2 3 4 5 6 7 8 9 10 11 12 13 // stdafx.h // ... // ATL #include <atlbase.h> #include <atlstr.h> // Shell #include <Shobjidl.h> // WIC #include <wincodec.h> #pragma comment(lib, "Windowscodecs.lib")

// Demo.cpp // ... int main() { // initialize COM HRESULT hr = ::CoInitialize(NULL); if(SUCCEEDED(hr)) { CStringW strFile; hr = ShowWICFileOpenDialog(NULL, strFile); if(SUCCEEDED(hr)) { ::MessageBoxW(NULL, strFile, L"Demo WIC Open File Dialog", MB_OK); } // release COM ::CoUninitialize(); } return hr; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // Demo.cpp // ... int main ( ) { // initialize COM HRESULT hr = :: CoInitialize ( NULL ) ; if ( SUCCEEDED ( hr ) ) { CStringW strFile ; hr = ShowWICFileOpenDialog ( NULL , strFile ) ; if ( SUCCEEDED ( hr ) ) { :: MessageBoxW ( NULL , strFile , L "Demo WIC Open File Dialog" , MB_OK ) ; } // release COM :: CoUninitialize ( ) ; } return hr ; }

Notes

In a similar way, we can make a File Save dialog using IFileSaveDialog interface.

dialog using interface. This article presents just proof of concepts. IFileOpenDialog offers much more methods to customize the dialog according to specific needs. And of course, a more elegant job can be done by writing some C++ wrapper class(es).

offers much more methods to customize the dialog according to specific needs. And of course, a more elegant job can be done by writing some C++ wrapper class(es). For the future, I intend to integrate WIC File Dialogs in WIC Wrapper Library also presented in this blog.

in also presented in this blog. The built-in WIC decoders deal with the following image file formats: BMP, GIF, ICO, JPEG, PNG, TIFF and WMPhoto. However there are many other decoders that can befound over the internet. Just to mention two free ones: Microsoft Camera Codec Pack and Adobe DNG Codec for Windows.

Resources

Free WIC codecs download

See also

Share this: Twitter

LinkedIn

StumbleUpon

Facebook

Reddit

More

Google

Email



Print

