From 4b57b13e4021f3b257a54a72b93eff6ee9e72f9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Zalewski?= <mikolaj@zalewski.pl>
Date: Sun, 2 Aug 2020 20:03:20 +0200
Subject: [PATCH v2 2/2] comdlg32: Filename should be filled after
 CDN_INITDONE.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=33590
Signed-off-by: Mikołaj Zalewski <mikolaj@zalewski.pl>
---
 dlls/comdlg32/filedlg.c       | 150 +++++++++++++++++++---------------
 dlls/comdlg32/tests/filedlg.c |  63 ++++++++++++++
 2 files changed, 147 insertions(+), 66 deletions(-)

diff --git a/dlls/comdlg32/filedlg.c b/dlls/comdlg32/filedlg.c
index 538358bd5f..4460f187b4 100644
--- a/dlls/comdlg32/filedlg.c
+++ b/dlls/comdlg32/filedlg.c
@@ -165,11 +165,13 @@ static BOOL filedialog_is_readonly_hidden(const FileOpenDlgInfos *info)
 
 /* Internal functions used by the dialog */
 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
-static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
+static LRESULT FILEDLG95_FillFolder(HWND hwnd, WPARAM wParam, LPARAM lParam);
+static void    FILEDLG95_FillFilename(FileOpenDlgInfos *fodInfos);
 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
 static BOOL    FILEDLG95_OnOpen(HWND hwnd);
 static LRESULT FILEDLG95_InitControls(HWND hwnd);
+static void    FILEDLG95_ComputeEffectiveDirAndFilename(HWND hwnd, FileOpenDlgInfos *fodInfos);
 static void    FILEDLG95_Clean(HWND hwnd);
 
 /* Functions used by the shell navigation */
@@ -1347,7 +1349,9 @@ INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
      	   CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
 
          FILEDLG95_ResizeControls(hwnd, wParam, lParam);
-      	 FILEDLG95_FillControls(hwnd, wParam, lParam);
+
+         FILEDLG95_ComputeEffectiveDirAndFilename(hwnd, fodInfos);
+         FILEDLG95_FillFolder(hwnd, wParam, lParam);
 
          if( fodInfos->DlgInfos.hwndCustomDlg)
              ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
@@ -1357,6 +1361,8 @@ INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
              SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
          }
 
+         FILEDLG95_FillFilename(fodInfos);
+
          /* if the app has changed the position of the invisible listbox,
           * change that of the listview (browser) as well */
          GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
@@ -1493,13 +1499,6 @@ static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
  */
 static LRESULT FILEDLG95_InitControls(HWND hwnd)
 {
-  BOOL win2000plus = FALSE;
-  BOOL win98plus   = FALSE;
-  BOOL handledPath = FALSE;
-  OSVERSIONINFOW osVi;
-  static const WCHAR szwSlash[] = { '\\', 0 };
-  static const WCHAR szwStar[] = { '*',0 };
-
   static const TBBUTTON tbb[] =
   {
    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
@@ -1525,18 +1524,6 @@ static LRESULT FILEDLG95_InitControls(HWND hwnd)
 
   TRACE("%p\n", fodInfos);
 
-  /* Get windows version emulating */
-  osVi.dwOSVersionInfoSize = sizeof(osVi);
-  GetVersionExW(&osVi);
-  if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
-    win98plus   = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
-  } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-    win2000plus = (osVi.dwMajorVersion > 4);
-    if (win2000plus) win98plus = TRUE;
-  }
-  TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
-
-
   /* Use either the edit or the comboboxex for the filename control */
   if (filename_is_edit( fodInfos ))
   {
@@ -1651,8 +1638,69 @@ static LRESULT FILEDLG95_InitControls(HWND hwnd)
       SetWindowTextW(hwnd, buf);
   }
 
-  /* Initialise the file name edit control */
-  handledPath = FALSE;
+  /* Must the open as read only check box be checked ?*/
+  if(fodInfos->ofnInfos->Flags & OFN_READONLY)
+  {
+    SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
+  }
+
+  /* Must the open as read only check box be hidden? */
+  if (filedialog_is_readonly_hidden(fodInfos))
+  {
+    ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
+    EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
+  }
+
+  /* Must the help button be hidden? */
+  if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
+  {
+    ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
+    EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
+  }
+
+  /* change Open to Save */
+  if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
+  {
+      WCHAR buf[16];
+      LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, ARRAY_SIZE(buf));
+      SetDlgItemTextW(hwnd, IDOK, buf);
+      LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, ARRAY_SIZE(buf));
+      SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
+  }
+
+  /* Initialize the filter combo box */
+  FILEDLG95_FILETYPE_Init(hwnd);
+
+  return 0;
+}
+
+/***********************************************************************
+ *      FILEDLG95_ComputeEffectiveDirAndFilename
+ *
+ * WM_INITDIALOG message handler - compute init dir and filename box
+ * contents based on caller input and various heuristics.
+ */
+static void FILEDLG95_ComputeEffectiveDirAndFilename(HWND hwnd, FileOpenDlgInfos *fodInfos)
+{
+  OSVERSIONINFOW osVi;
+  static const WCHAR szwSlash[] = { '\\', 0 };
+  static const WCHAR szwStar[] = { '*',0 };
+
+  BOOL win2000plus = FALSE;
+  BOOL win98plus   = FALSE;
+  BOOL handledPath = FALSE;
+
+  /* Get windows version emulating */
+  osVi.dwOSVersionInfoSize = sizeof(osVi);
+  GetVersionExW(&osVi);
+  if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
+    win98plus   = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
+  } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+    win2000plus = (osVi.dwMajorVersion > 4);
+    if (win2000plus) win98plus = TRUE;
+  }
+  TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
+
   TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
 
   if(fodInfos->filename)
@@ -1684,10 +1732,6 @@ static LRESULT FILEDLG95_InitControls(HWND hwnd)
             TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
                     debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
          }
-         SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
-
-      } else {
-         SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
       }
   }
 
@@ -1755,7 +1799,6 @@ static LRESULT FILEDLG95_InitControls(HWND hwnd)
             TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
                  debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
          }
-         SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
       }
 
       /* 4. Win2000+: Recently used */
@@ -1839,43 +1882,7 @@ static LRESULT FILEDLG95_InitControls(HWND hwnd)
           TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
       }
   }
-  SetFocus( fodInfos->DlgInfos.hwndFileName );
   TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
-
-  /* Must the open as read only check box be checked ?*/
-  if(fodInfos->ofnInfos->Flags & OFN_READONLY)
-  {
-    SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
-  }
-
-  /* Must the open as read only check box be hidden? */
-  if (filedialog_is_readonly_hidden(fodInfos))
-  {
-    ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
-    EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
-  }
-
-  /* Must the help button be hidden? */
-  if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
-  {
-    ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
-    EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
-  }
-
-  /* change Open to Save */
-  if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
-  {
-      WCHAR buf[16];
-      LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, ARRAY_SIZE(buf));
-      SetDlgItemTextW(hwnd, IDOK, buf);
-      LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, ARRAY_SIZE(buf));
-      SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
-  }
-
-  /* Initialize the filter combo box */
-  FILEDLG95_FILETYPE_Init(hwnd);
-
-  return 0;
 }
 
 /***********************************************************************
@@ -1934,11 +1941,11 @@ static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
 }
 
 /***********************************************************************
- *      FILEDLG95_FillControls
+ *      FILEDLG95_FillFolder
  *
  * WM_INITDIALOG message handler (after hook notification)
  */
-static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
+static LRESULT FILEDLG95_FillFolder(HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
   LPITEMIDLIST pidlItemId = NULL;
 
@@ -1970,6 +1977,17 @@ static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
 
   return TRUE;
 }
+
+/***********************************************************************
+ *      FILEDLG95_FillFilename
+ *
+ * WM_INITDIALOG message handler (after hook notification)
+ */
+static void FILEDLG95_FillFilename(FileOpenDlgInfos *fodInfos) {
+  SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
+  SetFocus( fodInfos->DlgInfos.hwndFileName );
+}
+
 /***********************************************************************
  *      FILEDLG95_Clean
  *
diff --git a/dlls/comdlg32/tests/filedlg.c b/dlls/comdlg32/tests/filedlg.c
index 165b5cd8bd..75c93361fb 100644
--- a/dlls/comdlg32/tests/filedlg.c
+++ b/dlls/comdlg32/tests/filedlg.c
@@ -1116,6 +1116,68 @@ static void test_extension(void)
     test_extension_helper(&ofn, "TestFilter (*.*.def)\0*.*.def\0", "deadbeef.xyz");
 }
 
+static UINT_PTR CALLBACK notification_order_hook(HWND hCustomDlg, UINT msg, WPARAM wParam, LPARAM lParam)  {
+    NMHDR *nmh;
+    static BOOL initdone_received = FALSE;
+    static BOOL folderchange_received = FALSE;
+
+    if( msg == WM_NOTIFY)
+    {
+        nmh = (NMHDR*)lParam;
+        if( nmh->code == CDN_INITDONE)
+        {
+            CHAR fn[MAX_PATH];
+            GetWindowTextA(GetDlgItem(nmh->hwndFrom, cmb13), fn, MAX_PATH);
+            /* Needed for bug #33590. */
+            ok(fn[0] == 0, "Filename edit box shouldn't be set yet on CDN_INITDONE\n");
+
+            ok(GetDlgItem(nmh->hwndFrom, cmb13) != NULL, "Dialog should have filename combobox.");
+            ok(GetDlgItem(nmh->hwndFrom, edt1) == NULL, "Dialog should have no filename editbox.");
+
+            initdone_received = TRUE;
+        } else if (nmh->code == CDN_FOLDERCHANGE )
+        {
+            CHAR fn[MAX_PATH];
+            GetWindowTextA(GetDlgItem(nmh->hwndFrom, cmb13), fn, MAX_PATH);
+            ok(fn[0] == 0, "Filename edit box shouldn't be set yet on first CDN_FOLDERCHANGE\n");
+
+            folderchange_received = TRUE;
+            ok(initdone_received, "CDN_INITDONE not received before CDN_FOLDERCHANGE\n");
+
+            /* Make the dialog box send a CDN_TYPECHANGE once initialization completes. */
+            PostMessageA(nmh->hwndFrom, WM_COMMAND, MAKEWPARAM(cmb1, CBN_SELENDOK), (LPARAM)GetDlgItem(nmh->hwndFrom, cmb1));
+        } else if (nmh->code == CDN_TYPECHANGE) {
+            CHAR fn[MAX_PATH];
+            GetWindowTextA(GetDlgItem(nmh->hwndFrom, cmb13), fn, MAX_PATH);
+            ok(strcmp(fn, "this_test_filename.txt") == 0 || strcmp(fn, "this_test_filename") == 0,
+                "File path not filled properly on CDN_TYPECHANGE - got %s\n", fn);
+
+            ok(folderchange_received, "CDN_FOLDERCHANGE not received before CDN_TYPECHANGE\n");
+
+            /* Finish the test. */
+            PostMessageA(nmh->hwndFrom, WM_COMMAND, IDCANCEL, 0);
+        }
+    }
+
+    return 0;
+}
+
+static void test_notification_order(void) {
+    char file[MAX_PATH] = "this_test_filename.txt";
+    OPENFILENAMEA ofn = {0};
+    BOOL ret;
+
+    ofn.lStructSize = sizeof(ofn);
+    ofn.lpstrFile = file;
+    ofn.nMaxFile = MAX_PATH;
+    ofn.lpfnHook = notification_order_hook;
+    ofn.lpstrFilter = "Text File\0*.txt\0AllFiles\0*.*\0";
+    ofn.Flags = OFN_ENABLEHOOK | OFN_EXPLORER;
+    ofn.hInstance = GetModuleHandleA(NULL);
+    ret = GetOpenFileNameA(&ofn);
+    ok(!ret, "GetOpenFileNameA returned %#x\n", ret);
+}
+
 static BOOL WINAPI test_null_enum(HWND hwnd, LPARAM lParam)
 {
     /* Find the textbox and send a filename so IDOK will work.
@@ -1338,6 +1400,7 @@ START_TEST(filedlg)
     test_mru();
     if( resizesupported) test_resizable2();
     test_extension();
+    test_notification_order();
     test_null_filename();
     test_directory_filename();
     test_ole_initialization();
-- 
2.20.1

