1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
24 #pragma warning(disable:4740)
25 #endif
26
27 #include "macros.h"
28
29 #ifdef __cplusplus
30 #define local inline
31 #else
32 #define local static
33 #endif
34
SkipBlanks(LPCWSTR lpScan)35 local LPCWSTR SkipBlanks( LPCWSTR lpScan )
36 {
37 while ( ' ' == *lpScan || '\t' == *lpScan )
38 lpScan++;
39
40 return lpScan;
41 }
42
43
SkipArgument(LPCWSTR lpScan)44 local LPCWSTR SkipArgument( LPCWSTR lpScan )
45 {
46 BOOL fQuoted = FALSE;
47 LPCWSTR lpArgEnd = NULL;
48
49 do
50 {
51 switch ( *lpScan )
52 {
53 case ' ':
54 case '\t':
55 if ( fQuoted )
56 lpScan++;
57 else
58 lpArgEnd = lpScan;
59 break;
60 case '\"':
61 lpScan++;
62 fQuoted = !fQuoted;
63 break;
64 case '\0':
65 lpArgEnd = lpScan;
66 break;
67 default:
68 lpScan++;
69 break;
70 }
71 } while( *lpScan && !lpArgEnd );
72
73 return lpScan;
74 }
75
76
77 IMPLEMENT_THUNK( shell32, WINDOWS, LPWSTR *, WINAPI, CommandLineToArgvW, ( LPCWSTR lpCmdLineW, int *pNumArgs ) )
78 {
79 LPWSTR *lpArgvW = NULL;
80
81 if ( !lpCmdLineW || !*lpCmdLineW )
82 {
83 CHAR szFileName[MAX_PATH];
84
85 DWORD dwResult = GetModuleFileNameA( NULL, szFileName, MAX_PATH );
86
87 if ( dwResult && dwResult < MAX_PATH )
88 {
89 int cchNeeded = MultiByteToWideChar( CP_ACP, 0, szFileName, -1, NULL, 0 );
90
91 lpArgvW = (LPWSTR *)GlobalAlloc( 0, cchNeeded * sizeof(WCHAR) + sizeof(LPWSTR) );
92
93 if ( lpArgvW )
94 {
95 lpArgvW[0] = (LPWSTR)(lpArgvW + 1);
96
97 MultiByteToWideChar( CP_ACP, 0, szFileName, -1, lpArgvW[0], cchNeeded );
98 *pNumArgs = 1;
99 }
100 else
101 SetLastError( ERROR_OUTOFMEMORY );
102 }
103 }
104 else
105 {
106 LPCWSTR lpScan = lpCmdLineW;
107 int nTokens = 0;
108 int cchNeeded = 0;
109
110 // Count arguments and required size
111
112 while ( *lpScan )
113 {
114 lpScan = SkipBlanks( lpScan );
115 if ( *lpScan )
116 {
117 LPCWSTR lpArgEnd = SkipArgument( lpScan );
118
119 nTokens++;
120 cchNeeded += lpArgEnd - lpScan + 1;
121 lpScan = lpArgEnd;
122 }
123 }
124
125 // Allocate space for one additional NULL pointer to terminate list
126
127 lpArgvW = (LPWSTR *)GlobalAlloc( 0, sizeof(LPWSTR) * (nTokens + 1) + sizeof(WCHAR) * cchNeeded );
128
129 if ( lpArgvW )
130 {
131 // Collect arguments
132
133 LPWSTR lpDestination = (LPWSTR)&lpArgvW[nTokens + 1];
134
135 lpScan = lpCmdLineW;
136 nTokens = 0;
137
138 while ( *lpScan )
139 {
140 lpScan = SkipBlanks( lpScan );
141 if ( *lpScan )
142 {
143 LPCWSTR lpArgEnd = SkipArgument( lpScan );
144
145 lpArgvW[nTokens++] = lpDestination;
146
147 while ( lpScan < lpArgEnd )
148 {
149 if ( '\"' != *lpScan )
150 *lpDestination++ = *lpScan;
151
152 lpScan++;
153 }
154 *lpDestination++ = 0;
155 }
156 }
157
158 lpArgvW[nTokens] = NULL;
159
160 *pNumArgs = nTokens;
161 }
162 else
163 SetLastError( ERROR_OUTOFMEMORY );
164
165 }
166
167 return lpArgvW;
168 }