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.@]
*