|
@@ -4,6 +4,10 @@
|
|
|
http://www.frogtoss.com/labs
|
|
|
*/
|
|
|
|
|
|
+#define _CRTDBG_MAP_ALLOC
|
|
|
+#include <stdlib.h>
|
|
|
+#include <crtdbg.h>
|
|
|
+
|
|
|
/* only locally define UNICODE in this compilation unit */
|
|
|
#ifndef UNICODE
|
|
|
#define UNICODE
|
|
@@ -19,7 +23,7 @@
|
|
|
#include <stdio.h>
|
|
|
#include <assert.h>
|
|
|
#include <windows.h>
|
|
|
-#include <ShObjIdl.h>
|
|
|
+#include <shobjidl.h>
|
|
|
#include "nfd_common.h"
|
|
|
|
|
|
|
|
@@ -47,9 +51,9 @@ static void CopyWCharToNFDChar( const wchar_t *inStr, nfdchar_t **outStr )
|
|
|
/* includes NULL terminator byte in return */
|
|
|
static size_t GetUTF8ByteCountForWChar( const wchar_t *str )
|
|
|
{
|
|
|
- int bytesNeeded = WideCharToMultiByte( CP_UTF8, 0,
|
|
|
- str, -1,
|
|
|
- NULL, 0, NULL, NULL );
|
|
|
+ size_t bytesNeeded = WideCharToMultiByte( CP_UTF8, 0,
|
|
|
+ str, -1,
|
|
|
+ NULL, 0, NULL, NULL );
|
|
|
assert( bytesNeeded );
|
|
|
return bytesNeeded+1;
|
|
|
}
|
|
@@ -148,12 +152,12 @@ static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char
|
|
|
}
|
|
|
|
|
|
/* filterCount plus 1 because we hardcode the *.* wildcard after the while loop */
|
|
|
- COMDLG_FILTERSPEC *specList = (COMDLG_FILTERSPEC*)NFDi_Malloc( sizeof(COMDLG_FILTERSPEC) * (filterCount + 1) );
|
|
|
+ COMDLG_FILTERSPEC *specList = (COMDLG_FILTERSPEC*)NFDi_Malloc( sizeof(COMDLG_FILTERSPEC) * ((size_t)filterCount + 1) );
|
|
|
if ( !specList )
|
|
|
{
|
|
|
return NFD_ERROR;
|
|
|
}
|
|
|
- for (size_t i = 0; i < filterCount+1; ++i )
|
|
|
+ for (UINT i = 0; i < filterCount+1; ++i )
|
|
|
{
|
|
|
specList[i].pszName = NULL;
|
|
|
specList[i].pszSpec = NULL;
|
|
@@ -181,9 +185,8 @@ static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char
|
|
|
if ( *p_filterList == ';' || *p_filterList == '\0' )
|
|
|
{
|
|
|
/* end of filter -- add it to specList */
|
|
|
-
|
|
|
- // Empty filter name -- Windows describes them by extension.
|
|
|
- CopyNFDCharToWChar(specbuf, (wchar_t**)&specList[specIdx].pszName);
|
|
|
+
|
|
|
+ CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszName );
|
|
|
CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszSpec );
|
|
|
|
|
|
memset( specbuf, 0, sizeof(char)*NFD_MAX_STRLEN );
|
|
@@ -270,6 +273,8 @@ static nfdresult_t AllocPathSet( IShellItemArray *shellItems, nfdpathset_t *path
|
|
|
|
|
|
// Calculate length of name with UTF-8 encoding
|
|
|
bufSize += GetUTF8ByteCountForWChar( name );
|
|
|
+
|
|
|
+ CoTaskMemFree(name);
|
|
|
}
|
|
|
|
|
|
assert(bufSize);
|
|
@@ -304,6 +309,7 @@ static nfdresult_t AllocPathSet( IShellItemArray *shellItems, nfdpathset_t *path
|
|
|
shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name);
|
|
|
|
|
|
int bytesWritten = CopyWCharToExistingNFDCharBuffer(name, p_buf);
|
|
|
+ CoTaskMemFree(name);
|
|
|
|
|
|
ptrdiff_t index = p_buf - pathSet->buf;
|
|
|
assert( index >= 0 );
|
|
@@ -353,29 +359,30 @@ static nfdresult_t SetDefaultPath( IFileDialog *dialog, const char *defaultPath
|
|
|
/* public */
|
|
|
|
|
|
|
|
|
-nfdresult_t NFD_OpenDialog( const char *filterList,
|
|
|
+nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList,
|
|
|
const nfdchar_t *defaultPath,
|
|
|
nfdchar_t **outPath )
|
|
|
{
|
|
|
nfdresult_t nfdResult = NFD_ERROR;
|
|
|
|
|
|
// Init COM library.
|
|
|
- HRESULT result = ::CoInitializeEx(NULL,
|
|
|
- ::COINIT_APARTMENTTHREADED |
|
|
|
- ::COINIT_DISABLE_OLE1DDE );
|
|
|
+ HRESULT coResult = ::CoInitializeEx(NULL,
|
|
|
+ ::COINIT_APARTMENTTHREADED |
|
|
|
+ ::COINIT_DISABLE_OLE1DDE );
|
|
|
|
|
|
::IFileOpenDialog *fileOpenDialog(NULL);
|
|
|
|
|
|
- if ( !SUCCEEDED(result))
|
|
|
+ if ( !SUCCEEDED(coResult))
|
|
|
{
|
|
|
+ fileOpenDialog = NULL;
|
|
|
NFDi_SetError("Could not initialize COM.");
|
|
|
goto end;
|
|
|
}
|
|
|
|
|
|
// Create dialog
|
|
|
- result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL,
|
|
|
- CLSCTX_ALL, ::IID_IFileOpenDialog,
|
|
|
- reinterpret_cast<void**>(&fileOpenDialog) );
|
|
|
+ HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL,
|
|
|
+ CLSCTX_ALL, ::IID_IFileOpenDialog,
|
|
|
+ reinterpret_cast<void**>(&fileOpenDialog) );
|
|
|
|
|
|
if ( !SUCCEEDED(result) )
|
|
|
{
|
|
@@ -412,6 +419,7 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
|
|
|
if ( !SUCCEEDED(result) )
|
|
|
{
|
|
|
NFDi_SetError("Could not get file path for selected.");
|
|
|
+ shellItem->Release();
|
|
|
goto end;
|
|
|
}
|
|
|
|
|
@@ -420,6 +428,7 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
|
|
|
if ( !*outPath )
|
|
|
{
|
|
|
/* error is malloc-based, error message would be redundant */
|
|
|
+ shellItem->Release();
|
|
|
goto end;
|
|
|
}
|
|
|
|
|
@@ -436,8 +445,12 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
|
|
|
nfdResult = NFD_ERROR;
|
|
|
}
|
|
|
|
|
|
- end:
|
|
|
- ::CoUninitialize();
|
|
|
+end:
|
|
|
+ if (fileOpenDialog)
|
|
|
+ fileOpenDialog->Release();
|
|
|
+
|
|
|
+ if (SUCCEEDED(coResult))
|
|
|
+ ::CoUninitialize();
|
|
|
|
|
|
return nfdResult;
|
|
|
}
|
|
@@ -449,10 +462,10 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
|
|
|
nfdresult_t nfdResult = NFD_ERROR;
|
|
|
|
|
|
// Init COM library.
|
|
|
- HRESULT result = ::CoInitializeEx(NULL,
|
|
|
- ::COINIT_APARTMENTTHREADED |
|
|
|
- ::COINIT_DISABLE_OLE1DDE );
|
|
|
- if ( !SUCCEEDED(result))
|
|
|
+ HRESULT coResult = ::CoInitializeEx(NULL,
|
|
|
+ ::COINIT_APARTMENTTHREADED |
|
|
|
+ ::COINIT_DISABLE_OLE1DDE );
|
|
|
+ if ( !SUCCEEDED(coResult))
|
|
|
{
|
|
|
NFDi_SetError("Could not initialize COM.");
|
|
|
return NFD_ERROR;
|
|
@@ -461,12 +474,13 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
|
|
|
::IFileOpenDialog *fileOpenDialog(NULL);
|
|
|
|
|
|
// Create dialog
|
|
|
- result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL,
|
|
|
- CLSCTX_ALL, ::IID_IFileOpenDialog,
|
|
|
- reinterpret_cast<void**>(&fileOpenDialog) );
|
|
|
+ HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL,
|
|
|
+ CLSCTX_ALL, ::IID_IFileOpenDialog,
|
|
|
+ reinterpret_cast<void**>(&fileOpenDialog) );
|
|
|
|
|
|
if ( !SUCCEEDED(result) )
|
|
|
{
|
|
|
+ fileOpenDialog = NULL;
|
|
|
NFDi_SetError("Could not create dialog.");
|
|
|
goto end;
|
|
|
}
|
|
@@ -512,6 +526,7 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
|
|
|
|
|
|
if ( AllocPathSet( shellItems, outPaths ) == NFD_ERROR )
|
|
|
{
|
|
|
+ shellItems->Release();
|
|
|
goto end;
|
|
|
}
|
|
|
|
|
@@ -528,8 +543,12 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
|
|
|
nfdResult = NFD_ERROR;
|
|
|
}
|
|
|
|
|
|
- end:
|
|
|
- ::CoUninitialize();
|
|
|
+end:
|
|
|
+ if ( fileOpenDialog )
|
|
|
+ fileOpenDialog->Release();
|
|
|
+
|
|
|
+ if (SUCCEEDED(coResult))
|
|
|
+ ::CoUninitialize();
|
|
|
|
|
|
return nfdResult;
|
|
|
}
|
|
@@ -541,10 +560,10 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
|
|
|
nfdresult_t nfdResult = NFD_ERROR;
|
|
|
|
|
|
// Init COM library.
|
|
|
- HRESULT result = ::CoInitializeEx(NULL,
|
|
|
- ::COINIT_APARTMENTTHREADED |
|
|
|
- ::COINIT_DISABLE_OLE1DDE );
|
|
|
- if ( !SUCCEEDED(result))
|
|
|
+ HRESULT coResult = ::CoInitializeEx(NULL,
|
|
|
+ ::COINIT_APARTMENTTHREADED |
|
|
|
+ ::COINIT_DISABLE_OLE1DDE );
|
|
|
+ if ( !SUCCEEDED(coResult))
|
|
|
{
|
|
|
NFDi_SetError("Could not initialize COM.");
|
|
|
return NFD_ERROR;
|
|
@@ -553,12 +572,13 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
|
|
|
::IFileSaveDialog *fileSaveDialog(NULL);
|
|
|
|
|
|
// Create dialog
|
|
|
- result = ::CoCreateInstance(::CLSID_FileSaveDialog, NULL,
|
|
|
- CLSCTX_ALL, ::IID_IFileSaveDialog,
|
|
|
- reinterpret_cast<void**>(&fileSaveDialog) );
|
|
|
+ HRESULT result = ::CoCreateInstance(::CLSID_FileSaveDialog, NULL,
|
|
|
+ CLSCTX_ALL, ::IID_IFileSaveDialog,
|
|
|
+ reinterpret_cast<void**>(&fileSaveDialog) );
|
|
|
|
|
|
if ( !SUCCEEDED(result) )
|
|
|
{
|
|
|
+ fileSaveDialog = NULL;
|
|
|
NFDi_SetError("Could not create dialog.");
|
|
|
goto end;
|
|
|
}
|
|
@@ -591,6 +611,7 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
|
|
|
result = shellItem->GetDisplayName(::SIGDN_FILESYSPATH, &filePath);
|
|
|
if ( !SUCCEEDED(result) )
|
|
|
{
|
|
|
+ shellItem->Release();
|
|
|
NFDi_SetError("Could not get file path for selected.");
|
|
|
goto end;
|
|
|
}
|
|
@@ -600,6 +621,7 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
|
|
|
if ( !*outPath )
|
|
|
{
|
|
|
/* error is malloc-based, error message would be redundant */
|
|
|
+ shellItem->Release();
|
|
|
goto end;
|
|
|
}
|
|
|
|
|
@@ -616,8 +638,12 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
|
|
|
nfdResult = NFD_ERROR;
|
|
|
}
|
|
|
|
|
|
- end:
|
|
|
- ::CoUninitialize();
|
|
|
+end:
|
|
|
+ if ( fileSaveDialog )
|
|
|
+ fileSaveDialog->Release();
|
|
|
+
|
|
|
+ if (SUCCEEDED(coResult))
|
|
|
+ ::CoUninitialize();
|
|
|
|
|
|
return nfdResult;
|
|
|
}
|
|
@@ -729,7 +755,8 @@ nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath,
|
|
|
ComPtr<IShellItem> pShellItem;
|
|
|
if (!SUCCEEDED(pFileDialog->GetResult(&pShellItem)))
|
|
|
{
|
|
|
- return NFD_OKAY;
|
|
|
+ NFDi_SetError("Could not get shell item from dialog.");
|
|
|
+ return NFD_ERROR;
|
|
|
}
|
|
|
|
|
|
// Finally get the path
|