CVS: winex/dlls/shell32 shell32_main.c,1.5,1.6

[email protected] 1 Aug 2007 12:22:29 -0000
Newsgroups gmane.comp.emulators.winex.cvs
Message-ID <[email protected]>
Subject: winex/dlls/shell32 shell32_main.c,1.5,1.6Update of /var/lib/cvsd/cvsroot/winex/dlls/shell32
In directory agravaine:/tmp/cvs-serv27155/dlls/shell32

Modified Files:
	shell32_main.c 
Log Message:

- fixed the CommandLineToArgvW() function so that it had the same behaviour as native, dealt with memory a little better, and checked more error conditions.  This includes gav's argc fix patch.  There is still a hack in this function to get around an incorrect return value from GetModuleFileNameW() (#1313)



Index: shell32_main.c
===================================================================
RCS file: /var/lib/cvsd/cvsroot/winex/dlls/shell32/shell32_main.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- shell32_main.c	1 Apr 2004 12:09:27 -0000	1.5
+++ shell32_main.c	1 Aug 2007 12:22:26 -0000	1.6
@@ -68,6 +68,16 @@
  * '"'  == 0x0022
  * '\\' == 0x005c
  */
+#define CLTAW_STRCAT(x, y)  x##y
+#define CLTAW_PASTE(x, y)   CLTAW_STRCAT(x, y)
+#define CLTAW_ALLOCSPACE    Global
+//#define CLTAW_ALLOCSPACE    Local
+#define CLTAW_ALLOC         CLTAW_PASTE(CLTAW_ALLOCSPACE, Alloc)
+#define CLTAW_REALLOC       CLTAW_PASTE(CLTAW_ALLOCSPACE, ReAlloc)
+#define CLTAW_LOCK          CLTAW_PASTE(CLTAW_ALLOCSPACE, Lock)
+#define CLTAW_FREE          CLTAW_PASTE(CLTAW_ALLOCSPACE, Free)
+
+
 LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
 {
     DWORD argc;
@@ -81,17 +91,67 @@
     if (*lpCmdline==0) {
         /* Return the path to the executable */
         DWORD size;
+        DWORD result;
+        DWORD maxChars;
+
+
+        size = 32;
+        /* NOTE: native LocalReAlloc() does not accept NULL as the handle to realloc.
+                 This leads to an infinite loop on windows.
+                 Also, under windows, the GMEM_MOVEABLE flag seems to be required for
+                 the GlobalAlloc() function to succeed in this case.  Passing 0 for
+                 the <flags> parameter results in NULL being returned as the handle. 
+        */
+        hargv = CLTAW_ALLOC(0, size + (2 * sizeof(WCHAR)));
+
+        if (hargv == 0)
+            return NULL;
+
+        argv = CLTAW_LOCK(hargv);
+
+        if (argv == NULL)
+            return NULL;
+
+
+        maxChars = (size - sizeof(LPWSTR)) / sizeof(WCHAR);
+
+        /* try to grab the module filename into the new buffer.  If it's too small, it'll return
+           <maxChars>, or 0 on error. */
+        FIXME("our implementation of GetModuleFileName() is incorrect - it does not have a return value to indicate a too-small buffer.  Using a hack here to get around it... {size = %ld, maxChars = %ld, hargv = 0x%x, argv = %p}\n", size, maxChars, hargv, argv);
+        result = GetModuleFileNameW((HMODULE)0, (LPWSTR)(argv + 1), maxChars);
+
+
+        /* resize the buffer and try again */
+        /* NOTE: the hack in the loop guard is to compensate for the incorrect return value in GetModuleFileNameW().
+                 Remove it when that function is fixed. */
+        while (result == 0 || result == maxChars /* <HACK> */ - 1 /* </HACK> */){
+            size *= 2;
+            hargv = CLTAW_REALLOC(hargv, size + (2 * sizeof(WCHAR)), 0);
+            argv =  CLTAW_LOCK(hargv);
+            maxChars = (size - sizeof(LPWSTR)) / sizeof(WCHAR);
+            FIXME("our implementation of GetModuleFileName() is incorrect - it does not have a return value to indicate a too-small buffer.  Using a hack here to get around it... {size = %ld, maxChars = %ld, hargv = 0x%x, argv = %p}\n", size, maxChars, hargv, argv);
+
+            if (argv == NULL)
+                return NULL;
+
+            result = GetModuleFileNameW((HMODULE)0, (LPWSTR)(argv + 1), maxChars);
+        }
+
+        /* an error occurred while retrieving the module name (ie: could not retrieve name or bad module handle)
+               => fail */
+        if (result == 0)
+            return NULL;
+
+        /* NOTE: native does NOT null terminate this string array itself, but it does null terminate 
+                 the memory after the final string entry (ie: two null wide characters after the null
+                 terminator of the last string).  It also returns 1 as the argument count in this case.
+                 The first string begins immediately after argv[0]. */
+        argv[0] = (LPWSTR)(argv + 1);
+        argv[0][result + 1] = 0;
+        argv[0][result + 2] = 0;
 
-        hargv=0;
-        size=16;
-        do {
-            size*=2;
-            hargv=GlobalReAlloc(hargv, size, 0);
-            argv=GlobalLock(hargv);
-        } while (GetModuleFileNameW((HMODULE)0, (LPWSTR)(argv+1), size-sizeof(LPWSTR)) == 0);
-        argv[0]=(LPWSTR)(argv+1);
         if (numargs)
-            *numargs=2;
+            *numargs = 1;
 
         return argv;
     }
@@ -126,14 +186,24 @@
         }
         cs++;
     }
+
+
     /* Allocate in a single lump, the string array, and the strings that go with it.
-     * This way the caller can make a single GlobalFree call to free both, as per MSDN.
+     * This way the caller can make a single Global/LocalFree call to free both, as per MSDN.
+     * the extra '2' characters are for the two null terminators at the end of the string list.
+     * NOTE: some time between VC7 and VC8 (possibly with winXP), this function changed from 
+     *       using GlobalAlloc() to using LocalAlloc().  They aren't *supposed* to be compatible
+     *       with each other, but they don't seem to complain and both function properly
+     *       and interchangeably under windows.
      */
-    hargv=GlobalAlloc(0, argc*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR));
-    argv=GlobalLock(hargv);
-    if (!argv)
+    hargv = CLTAW_ALLOC(0, argc * sizeof(LPWSTR) + (strlenW(lpCmdline) + 1 + 2) * sizeof(WCHAR));
+    argv =  CLTAW_LOCK(hargv);
+
+    if (argv == NULL)
         return NULL;
-    cmdline=(LPWSTR)(argv+argc);
+
+
+    cmdline = (LPWSTR)(argv + argc);
     strcpyW(cmdline, lpCmdline);
 
     argc=0;
@@ -182,16 +252,29 @@
             bcount=0;
         }
     }
+
+    /* double terminate the final string */
     if (*arg) {
-        *d='\0';
-        argv[argc]=arg;
+        d[0] = '\0';
+        d[1] = '\0';
+        d[2] = '\0';
+        argv[argc++] = arg;
     }
     if (numargs)
-        *numargs=argc;
+        *numargs = argc;
 
     return argv;
 }
 
+#undef CLTAW_STRCAT
+#undef CLTAW_PASTE
+#undef CLTAW_ALLOCSPACE
+#undef CLTAW_ALLOC
+#undef CLTAW_REALLOC
+#undef CLTAW_LOCK
+#undef CLTAW_FREE
+
+
 /*************************************************************************
  * SHGetFileInfoA			[SHELL32.@]
  *