Browse Source

Update nativefiledialog dependency

Rokas Kupstys 8 years ago
parent
commit
a670b87859

+ 4 - 19
Source/AtomicEditor/Utils/FileUtils.cpp

@@ -96,10 +96,7 @@ String FileUtils::NewProjectFileDialog()
     upath = GetSubsystem<FileSystem>()->GetUserDocumentsDir();
 #endif
 
-    nfdresult_t result = NFD_ChooseDirectory( "Please choose the root folder for your project",
-                                upath.Length() ? GetNativePath(upath).CString() : "",
-                                &outPath);
-
+    nfdresult_t result = NFD_PickFolder(upath.Length() ? GetNativePath(upath).CString() : "", &outPath);
 
     if (outPath && result == NFD_OKAY)
     {
@@ -121,9 +118,7 @@ String FileUtils::GetBuildPath(const String& defaultPath)
 
     nfdchar_t *outPath = NULL;
     
-    nfdresult_t result = NFD_ChooseDirectory( "Please choose the build folder",
-                                defaultPath.Length() ? GetNativePath(defaultPath).CString() : "",
-                                &outPath);
+    nfdresult_t result = NFD_PickFolder(defaultPath.Length() ? GetNativePath(defaultPath).CString() : "", &outPath);
 
     if (outPath && result == NFD_OKAY)
     {
@@ -145,15 +140,7 @@ String FileUtils::GetAntPath(const String& defaultPath)
 
     nfdchar_t *outPath = NULL;
 
-#ifdef ATOMIC_PLATFORM_WINDOWS
-    String msg = "Please select the folder which contains ant.bat";
-#else
-    String msg = "Please select the folder which contains the ant executable";
-#endif
-
-    nfdresult_t result = NFD_ChooseDirectory(msg.CString(),
-                        defaultPath.Length() ? GetNativePath(defaultPath).CString() : "",
-                        &outPath);
+    nfdresult_t result = NFD_PickFolder(defaultPath.Length() ? GetNativePath(defaultPath).CString() : "", &outPath);
 
     if (outPath && result == NFD_OKAY)
     {
@@ -208,9 +195,7 @@ String FileUtils::FindPath(const String& title, const String& defaultPath)
     String resultPath;
     nfdchar_t *outPath = NULL;
 
-    nfdresult_t result = NFD_ChooseDirectory(title.CString(),
-                       defaultPath.Length() ? GetNativePath(defaultPath).CString() : "",
-                       &outPath);
+    nfdresult_t result = NFD_PickFolder(defaultPath.Length() ? GetNativePath(defaultPath).CString() : "", &outPath);
 
     if (outPath && result == NFD_OKAY)
     {

+ 1 - 1
Source/ThirdParty/nativefiledialog/CMakeLists.txt

@@ -2,7 +2,7 @@
 set (SOURCE_FILES nfd_common.c nfd.h)
 
 if (APPLE)
-    set (SOURCE_FILES ${SOURCE_FILES} nfd_cocoa.mm )
+    set (SOURCE_FILES ${SOURCE_FILES} nfd_cocoa.m )
 endif( APPLE)
 
 if (WIN32)

+ 4 - 4
Source/ThirdParty/nativefiledialog/nfd.h

@@ -48,12 +48,12 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
 /* save dialog */
 nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
                             const nfdchar_t *defaultPath,
-                            const nfdchar_t *defaultFilename,
                             nfdchar_t **outPath );
 
-nfdresult_t NFD_ChooseDirectory( const nfdchar_t *prompt,
-                                 const nfdchar_t *defaultPath,
-                                 nfdchar_t **outPath );
+
+/* select folder dialog */
+nfdresult_t NFD_PickFolder( const nfdchar_t *defaultPath,
+                            nfdchar_t **outPath);
 
 /* nfd_common.c */
 

+ 24 - 42
Source/ThirdParty/nativefiledialog/nfd_cocoa.mm → Source/ThirdParty/nativefiledialog/nfd_cocoa.m

@@ -55,22 +55,14 @@ static void AddFilterListToDialog( NSSavePanel *dialog, const char *filterList )
     }
 }
 
-static void SetDefaultPath( NSSavePanel *dialog, const nfdchar_t *defaultPath, const nfdchar_t *defaultFilename )
+static void SetDefaultPath( NSSavePanel *dialog, const nfdchar_t *defaultPath )
 {
-    if ( defaultPath && strlen(defaultPath))
-    {
-        NSString *defaultPathString = [NSString stringWithUTF8String: defaultPath];
-        NSURL *url = [NSURL fileURLWithPath:defaultPathString isDirectory:YES];
-        [dialog setDirectoryURL:url];
-    }
-
-
-    if ( defaultFilename && strlen(defaultFilename))
-    {
-        NSString *defaultFilenameString = [NSString stringWithUTF8String: defaultFilename];
-        [dialog setNameFieldStringValue:defaultFilenameString];
-    }
+    if ( !defaultPath || strlen(defaultPath) == 0 )
+        return;
 
+    NSString *defaultPathString = [NSString stringWithUTF8String: defaultPath];
+    NSURL *url = [NSURL fileURLWithPath:defaultPathString isDirectory:YES];
+    [dialog setDirectoryURL:url];    
 }
 
 
@@ -81,7 +73,7 @@ static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset )
     assert([urls count]);
 
     pathset->count = (size_t)[urls count];
-    pathset->indices = (size_t *) NFDi_Malloc( sizeof(size_t)*pathset->count );
+    pathset->indices = NFDi_Malloc( sizeof(size_t)*pathset->count );
     if ( !pathset->indices ) 
     {
         return NFD_ERROR;
@@ -95,7 +87,7 @@ static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset )
         bufsize += [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1;
     }
 
-    pathset->buf = (nfdchar_t*) NFDi_Malloc( sizeof(nfdchar_t) * bufsize );
+    pathset->buf = NFDi_Malloc( sizeof(nfdchar_t) * bufsize );
     if ( !pathset->buf )
     {
         return NFD_ERROR;
@@ -130,8 +122,8 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
                             nfdchar_t **outPath )
 {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-    
-    NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
+
+    NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];    
     NSOpenPanel *dialog = [NSOpenPanel openPanel];
     [dialog setAllowsMultipleSelection:NO];
 
@@ -139,7 +131,7 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
     AddFilterListToDialog(dialog, filterList);
 
     // Set the starting directory
-    SetDefaultPath(dialog, defaultPath, NULL);
+    SetDefaultPath(dialog, defaultPath);
 
     nfdresult_t nfdResult = NFD_CANCEL;
     if ( [dialog runModal] == NSModalResponseOK )
@@ -150,7 +142,7 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
         // byte count, not char count
         size_t len = strlen(utf8Path);//NFDi_UTF8_Strlen(utf8Path);
 
-        *outPath = (nfdchar_t*) NFDi_Malloc( len+1 );
+        *outPath = NFDi_Malloc( len+1 );
         if ( !*outPath )
         {
             [pool release];
@@ -159,10 +151,9 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
         memcpy( *outPath, utf8Path, len+1 ); /* copy null term */
         nfdResult = NFD_OKAY;
     }
-
-    [keyWindow makeKeyAndOrderFront:nil];
     [pool release];
 
+    [keyWindow makeKeyAndOrderFront:nil];
     return nfdResult;
 }
 
@@ -173,15 +164,14 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
 {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
     
-    NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
     NSOpenPanel *dialog = [NSOpenPanel openPanel];
-    [dialog setAllowsMultipleSelection:YES];    
+    [dialog setAllowsMultipleSelection:YES];
 
     // Build the fiter list.
     AddFilterListToDialog(dialog, filterList);
 
     // Set the starting directory
-    SetDefaultPath(dialog, defaultPath, NULL);
+    SetDefaultPath(dialog, defaultPath);
     
     nfdresult_t nfdResult = NFD_CANCEL;
     if ( [dialog runModal] == NSModalResponseOK )
@@ -202,8 +192,6 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
 
         nfdResult = NFD_OKAY;
     }
-
-    [keyWindow makeKeyAndOrderFront:nil];
     [pool release];
 
     return nfdResult;
@@ -212,21 +200,18 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
 
 nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
                             const nfdchar_t *defaultPath,
-                            const nfdchar_t *defaultFilename,
                             nfdchar_t **outPath )
 {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
-    NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
     NSSavePanel *dialog = [NSSavePanel savePanel];
     [dialog setExtensionHidden:NO];
-    [dialog setCanCreateDirectories:YES];
     
     // Build the filter list.
     AddFilterListToDialog(dialog, filterList);
 
     // Set the starting directory
-    SetDefaultPath(dialog, defaultPath, defaultFilename);
+    SetDefaultPath(dialog, defaultPath);
 
     nfdresult_t nfdResult = NFD_CANCEL;
     if ( [dialog runModal] == NSModalResponseOK )
@@ -236,7 +221,7 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
 
         size_t byteLen = [url.path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1;
         
-        *outPath = (nfdchar_t*) NFDi_Malloc( byteLen );
+        *outPath = NFDi_Malloc( byteLen );
         if ( !*outPath )
         {
             [pool release];
@@ -246,27 +231,25 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
         nfdResult = NFD_OKAY;
     }
 
-    [keyWindow makeKeyAndOrderFront:nil];
     [pool release];
 
     return nfdResult;
 }
 
-nfdresult_t NFD_ChooseDirectory(const nfdchar_t *prompt, const nfdchar_t *defaultPath,
-                                nfdchar_t **outPath )
+nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath,
+    nfdchar_t **outPath)
 {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
-    NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
+    NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];    
     NSOpenPanel *dialog = [NSOpenPanel openPanel];
     [dialog setAllowsMultipleSelection:NO];
     [dialog setCanChooseDirectories:YES];
     [dialog setCanCreateDirectories:YES];
-    [dialog setTitle:[NSString stringWithUTF8String: prompt]];
-    [dialog setPrompt:@"Ok"];
+    [dialog setCanChooseFiles:NO];
 
     // Set the starting directory
-    SetDefaultPath(dialog, defaultPath, NULL);
+    SetDefaultPath(dialog, defaultPath);
 
     nfdresult_t nfdResult = NFD_CANCEL;
     if ( [dialog runModal] == NSModalResponseOK )
@@ -277,7 +260,7 @@ nfdresult_t NFD_ChooseDirectory(const nfdchar_t *prompt, const nfdchar_t *defaul
         // byte count, not char count
         size_t len = strlen(utf8Path);//NFDi_UTF8_Strlen(utf8Path);
 
-        *outPath = (nfdchar_t*) NFDi_Malloc( len+1 );
+        *outPath = NFDi_Malloc( len+1 );
         if ( !*outPath )
         {
             [pool release];
@@ -286,9 +269,8 @@ nfdresult_t NFD_ChooseDirectory(const nfdchar_t *prompt, const nfdchar_t *defaul
         memcpy( *outPath, utf8Path, len+1 ); /* copy null term */
         nfdResult = NFD_OKAY;
     }
-
-    [keyWindow makeKeyAndOrderFront:nil];
     [pool release];
 
+    [keyWindow makeKeyAndOrderFront:nil];
     return nfdResult;
 }

+ 49 - 48
Source/ThirdParty/nativefiledialog/nfd_gtk.c

@@ -13,8 +13,7 @@
 
 
 const char INIT_FAIL_MSG[] = "gtk_init_check failed to initilaize GTK+";
-const char NOPATH_MSG[] = "The selected path is out of memory.";
-const char NOMEM_MSG[] = "Out of memory.";
+
 
 static void AddTypeToFilterName( const char *typebuf, char *filterName, size_t bufsize )
 {
@@ -26,7 +25,7 @@ static void AddTypeToFilterName( const char *typebuf, char *filterName, size_t b
         strncat( filterName, SEP, bufsize - len - 1 );
         len += strlen(SEP);
     }
-
+    
     strncat( filterName, typebuf, bufsize - len - 1 );
 }
 
@@ -37,34 +36,34 @@ static void AddFiltersToDialog( GtkWidget *dialog, const char *filterList )
     const char *p_filterList = filterList;
     char *p_typebuf = typebuf;
     char filterName[NFD_MAX_STRLEN] = {0};
-
+    
     if ( !filterList || strlen(filterList) == 0 )
         return;
 
     filter = gtk_file_filter_new();
     while ( 1 )
     {
-
+        
         if ( NFDi_IsFilterSegmentChar(*p_filterList) )
         {
             char typebufWildcard[NFD_MAX_STRLEN];
             /* add another type to the filter */
             assert( strlen(typebuf) > 0 );
             assert( strlen(typebuf) < NFD_MAX_STRLEN-1 );
-
+            
             snprintf( typebufWildcard, NFD_MAX_STRLEN, "*.%s", typebuf );
             AddTypeToFilterName( typebuf, filterName, NFD_MAX_STRLEN );
-
+            
             gtk_file_filter_add_pattern( filter, typebufWildcard );
-
+            
             p_typebuf = typebuf;
             memset( typebuf, 0, sizeof(char) * NFD_MAX_STRLEN );
         }
-
+        
         if ( *p_filterList == ';' || *p_filterList == '\0' )
         {
             /* end of filter -- add it to the dialog */
-
+            
             gtk_file_filter_set_name( filter, filterName );
             gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(dialog), filter );
 
@@ -73,7 +72,7 @@ static void AddFiltersToDialog( GtkWidget *dialog, const char *filterList )
             if ( *p_filterList == '\0' )
                 break;
 
-            filter = gtk_file_filter_new();
+            filter = gtk_file_filter_new();            
         }
 
         if ( !NFDi_IsFilterSegmentChar( *p_filterList ) )
@@ -84,7 +83,7 @@ static void AddFiltersToDialog( GtkWidget *dialog, const char *filterList )
 
         p_filterList++;
     }
-
+    
     /* always append a wildcard option to the end*/
 
     filter = gtk_file_filter_new();
@@ -112,7 +111,7 @@ static nfdresult_t AllocPathSet( GSList *fileList, nfdpathset_t *pathSet )
     GSList *node;
     nfdchar_t *p_buf;
     size_t count = 0;
-
+    
     assert(fileList);
     assert(pathSet);
 
@@ -122,7 +121,6 @@ static nfdresult_t AllocPathSet( GSList *fileList, nfdpathset_t *pathSet )
     pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count );
     if ( !pathSet->indices )
     {
-        NFDi_SetError(NOMEM_MSG);
         return NFD_ERROR;
     }
 
@@ -142,7 +140,7 @@ static nfdresult_t AllocPathSet( GSList *fileList, nfdpathset_t *pathSet )
         nfdchar_t *path = (nfdchar_t*)(node->data);
         size_t byteLen = strlen(path)+1;
         ptrdiff_t index;
-
+        
         memcpy( p_buf, path, byteLen );
         g_free(node->data);
 
@@ -155,7 +153,7 @@ static nfdresult_t AllocPathSet( GSList *fileList, nfdpathset_t *pathSet )
     }
 
     g_slist_free( fileList );
-
+    
     return NFD_OKAY;
 }
 
@@ -164,13 +162,13 @@ static void WaitForCleanup(void)
     while (gtk_events_pending())
         gtk_main_iteration();
 }
-
+                                 
 /* public */
 
 nfdresult_t NFD_OpenDialog( const char *filterList,
                             const nfdchar_t *defaultPath,
                             nfdchar_t **outPath )
-{
+{    
     GtkWidget *dialog;
     nfdresult_t result;
 
@@ -208,7 +206,6 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
             {
                 g_free( filename );
                 gtk_widget_destroy(dialog);
-                NFDi_SetError(NOPATH_MSG);
                 return NFD_ERROR;
             }
         }
@@ -216,8 +213,8 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
 
         result = NFD_OKAY;
     }
- 
-   
+
+    WaitForCleanup();
     gtk_widget_destroy(dialog);
     WaitForCleanup();
 
@@ -259,13 +256,13 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
         if ( AllocPathSet( fileList, outPaths ) == NFD_ERROR )
         {
             gtk_widget_destroy(dialog);
-            NFDi_SetError(NOPATH_MSG);
             return NFD_ERROR;
         }
-
+        
         result = NFD_OKAY;
     }
 
+    WaitForCleanup();
     gtk_widget_destroy(dialog);
     WaitForCleanup();
 
@@ -274,7 +271,6 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
 
 nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
                             const nfdchar_t *defaultPath,
-                            const nfdchar_t *defaultFilename,
                             nfdchar_t **outPath )
 {
     GtkWidget *dialog;
@@ -291,19 +287,21 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
                                           GTK_FILE_CHOOSER_ACTION_SAVE,
                                           "_Cancel", GTK_RESPONSE_CANCEL,
                                           "_Save", GTK_RESPONSE_ACCEPT,
-                                          NULL );
+                                          NULL ); 
     gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(dialog), TRUE );
 
-    /* Build the filter list */
+    /* Build the filter list */    
     AddFiltersToDialog(dialog, filterList);
-    SetDefaultPath(dialog, defaultPath);
 
-    result = NFD_CANCEL;
+    /* Set the default path */
+    SetDefaultPath(dialog, defaultPath);
+    
+    result = NFD_CANCEL;    
     if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
     {
         char *filename;
         filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) );
-
+        
         {
             size_t len = strlen(filename);
             *outPath = NFDi_Malloc( len + 1 );
@@ -312,7 +310,6 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
             {
                 g_free( filename );
                 gtk_widget_destroy(dialog);
-                NFDi_SetError(NOPATH_MSG);
                 return NFD_ERROR;
             }
         }
@@ -321,39 +318,43 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
         result = NFD_OKAY;
     }
 
+    WaitForCleanup();
     gtk_widget_destroy(dialog);
-
     WaitForCleanup();
-
+    
     return result;
 }
 
-nfdresult_t NFD_ChooseDirectory( const nfdchar_t *prompt,
-                                 const nfdchar_t *defaultPath,
-                                 nfdchar_t **outPath )
+nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath,
+    nfdchar_t **outPath)
 {
-    GtkWidget *dialog = NULL;
-    nfdresult_t result = NFD_ERROR;
+    GtkWidget *dialog;
+    nfdresult_t result;
 
-    if ( !gtk_init_check( NULL, NULL ) )
+    if (!gtk_init_check(NULL, NULL))
     {
         NFDi_SetError(INIT_FAIL_MSG);
         return NFD_ERROR;
     }
-    dialog = gtk_file_chooser_dialog_new( prompt,
+
+    dialog = gtk_file_chooser_dialog_new( "Select folder",
                                           NULL,
                                           GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
                                           "_Cancel", GTK_RESPONSE_CANCEL,
-                                          "_Open", GTK_RESPONSE_ACCEPT,
-                                          NULL );
+                                          "_Select", GTK_RESPONSE_ACCEPT,
+                                          NULL ); 
+    gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(dialog), TRUE );
 
-    SetDefaultPath(dialog, defaultPath);
 
-    result = NFD_CANCEL;
+    /* Set the default path */
+    SetDefaultPath(dialog, defaultPath);
+    
+    result = NFD_CANCEL;    
     if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
     {
-        char *filename = NULL;
+        char *filename;
         filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) );
+        
         {
             size_t len = strlen(filename);
             *outPath = NFDi_Malloc( len + 1 );
@@ -362,17 +363,17 @@ nfdresult_t NFD_ChooseDirectory( const nfdchar_t *prompt,
             {
                 g_free( filename );
                 gtk_widget_destroy(dialog);
-                NFDi_SetError(NOPATH_MSG);
                 return NFD_ERROR;
             }
         }
         g_free(filename);
+
         result = NFD_OKAY;
     }
 
+    WaitForCleanup();
     gtk_widget_destroy(dialog);
-
     WaitForCleanup();
-
-    return result;        
+    
+    return result;
 }

+ 109 - 76
Source/ThirdParty/nativefiledialog/nfd_win.cpp

@@ -9,15 +9,17 @@
 #define UNICODE
 #endif
 
+#ifdef __MINGW32__
+// Explicitly setting NTDDI version, this is necessary for the MinGW compiler
+#define NTDDI_VERSION NTDDI_VISTA
+#define _WIN32_WINNT _WIN32_WINNT_VISTA
+#endif
 
 #include <wchar.h>
 #include <stdio.h>
 #include <assert.h>
-//ATOMIC: Removed reference to ATL
-//#include <atlbase.h>
 #include <windows.h>
 #include <ShObjIdl.h>
-
 #include "nfd_common.h"
 
 
@@ -130,7 +132,7 @@ static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char
         return NFD_OKAY;
 
     // Count rows to alloc
-    size_t filterCount = 1; /* guaranteed to have one filter on a correct, non-empty parse */
+    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 )
     {
@@ -203,7 +205,7 @@ static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char
     specList[specIdx].pszSpec = WILDCARD;
     specList[specIdx].pszName = EMPTY_WSTR;
     
-    fileOpenDialog->SetFileTypes( static_cast<UINT>(filterCount+1), specList );
+    fileOpenDialog->SetFileTypes( filterCount+1, specList );
 
     /* free speclist */
     for ( size_t i = 0; i < filterCount; ++i )
@@ -361,14 +363,15 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
     HRESULT result = ::CoInitializeEx(NULL,
                                       ::COINIT_APARTMENTTHREADED |
                                       ::COINIT_DISABLE_OLE1DDE );
+
+    ::IFileOpenDialog *fileOpenDialog(NULL);
+
     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,
@@ -619,102 +622,132 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
     return nfdResult;
 }
 
-nfdresult_t NFD_ChooseDirectory(const nfdchar_t *prompt, const nfdchar_t *defaultPath,
-                                nfdchar_t **outPath )
+class AutoCoInit
 {
-    nfdresult_t nfdResult = NFD_ERROR;
-
-    // Init COM library.
-    HRESULT result = ::CoInitializeEx(NULL,
-                                      ::COINIT_APARTMENTTHREADED |
-                                      ::COINIT_DISABLE_OLE1DDE );
+public:
+    AutoCoInit()
+    {
+        mResult = ::CoInitializeEx(NULL,
+            ::COINIT_APARTMENTTHREADED |
+            ::COINIT_DISABLE_OLE1DDE);
+    }
 
-    wchar_t *promptW = {0};
-    if (prompt && strlen(prompt))
-        CopyNFDCharToWChar( prompt, &promptW );
+    ~AutoCoInit()
+    {
+        if (SUCCEEDED(mResult))
+        {
+            ::CoUninitialize();
+        }
+    }
 
+    HRESULT Result() const { return mResult; }
+private:
+    HRESULT mResult;
+};
 
-    if ( !SUCCEEDED(result))
+// VS2010 hasn't got a copy of CComPtr - this was first added in the 2003 SDK, so we make our own small CComPtr instead
+template<class T>
+class ComPtr
+{
+public:
+    ComPtr() : mPtr(NULL) { }
+    ~ComPtr()
     {
-        NFDi_SetError("Could not initialize COM.");
-        goto end;
+        if (mPtr)
+        {
+            mPtr->Release();
+        }
     }
 
-    ::IFileOpenDialog *fileOpenDialog(NULL);
-
-    // Create dialog
-    result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL,
-                                CLSCTX_ALL, ::IID_IFileOpenDialog,
-                                reinterpret_cast<void**>(&fileOpenDialog) );
+    T* Ptr() const { return mPtr; }
+    T** operator&() { return &mPtr; }
+    T* operator->() const { return mPtr; }
+private:
+    // Don't allow copy or assignment
+    ComPtr(const ComPtr&);
+    ComPtr& operator = (const ComPtr&) const;
+    T* mPtr;
+};
 
-    if ( !SUCCEEDED(result) )
+nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath,
+    nfdchar_t **outPath)
+{
+    // Init COM
+    AutoCoInit autoCoInit;
+    if (!SUCCEEDED(autoCoInit.Result()))
     {
-        NFDi_SetError("Could not create dialog.");
-        goto end;
+        NFDi_SetError("CoInitializeEx failed.");
+        return NFD_ERROR;
     }
 
-    DWORD dwOptions;
-    if (SUCCEEDED(fileOpenDialog->GetOptions(&dwOptions)))
+    // Create the file dialog COM object
+    ComPtr<IFileDialog> pFileDialog;
+    if (!SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog,
+                                    NULL,
+                                    CLSCTX_ALL,
+                                    IID_PPV_ARGS(&pFileDialog))))
     {
-        fileOpenDialog->SetOptions(dwOptions | FOS_PICKFOLDERS);
+        NFDi_SetError("CoCreateInstance for CLSID_FileOpenDialog failed.");
+        return NFD_ERROR;
     }
 
     // Set the default path
-    if ( !SetDefaultPath( fileOpenDialog, defaultPath ) )
+    if (SetDefaultPath(pFileDialog.Ptr(), defaultPath) != NFD_OKAY)
     {
-        goto end;
+        NFDi_SetError("SetDefaultPath failed.");
+        return NFD_ERROR;
     }
 
-    fileOpenDialog->SetTitle(promptW);
-
-
-    // Show the dialog.
-    result = fileOpenDialog->Show(NULL);
-    if ( SUCCEEDED(result) )
+    // Get the dialogs options
+    DWORD dwOptions = 0;
+    if (!SUCCEEDED(pFileDialog->GetOptions(&dwOptions)))
     {
-        // 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;
-        }
+        NFDi_SetError("GetOptions for IFileDialog failed.");
+        return NFD_ERROR;
+    }
 
-        nfdResult = NFD_OKAY;
-        shellItem->Release();
+    // Add in FOS_PICKFOLDERS which hides files and only allows selection of folders
+    if (!SUCCEEDED(pFileDialog->SetOptions(dwOptions | FOS_PICKFOLDERS)))
+    {
+        NFDi_SetError("SetOptions for IFileDialog failed.");
+        return NFD_ERROR;
     }
-    else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED) )
+
+    // Show the dialog to the user
+    const HRESULT result = pFileDialog->Show(NULL);
+    if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED))
     {
-        nfdResult = NFD_CANCEL;
+        return NFD_CANCEL;
     }
-    else
+    else if (!SUCCEEDED(result))
     {
-        NFDi_SetError("File dialog box show failed.");
-        nfdResult = NFD_ERROR;
+        NFDi_SetError("Show for IFileDialog failed.");
+        return NFD_ERROR;
     }
 
- end:
+    // Get the shell item result
+    ComPtr<IShellItem> pShellItem;
+    if (!SUCCEEDED(pFileDialog->GetResult(&pShellItem)))
+    {
+        return NFD_OKAY;
+    }
 
-    if (prompt && strlen(prompt));
-        NFDi_Free( promptW );
+    // Finally get the path
+    wchar_t *path = NULL;
+    if (!SUCCEEDED(pShellItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &path)))
+    {
+        NFDi_SetError("GetDisplayName for IShellItem failed.");
+        return NFD_ERROR;
+    }
 
-    ::CoUninitialize();
+    // Convert string
+    CopyWCharToNFDChar(path, outPath);
+    CoTaskMemFree(path);
+    if (!*outPath)
+    {
+        // error is malloc-based, error message would be redundant
+        return NFD_ERROR;
+    }
 
-    return nfdResult;
+    return NFD_OKAY;
 }