Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
urllaunch.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19
20#include "Common/URLLaunch.h"
21
22#define FILE_PREFIX L"file://"
23
24
26HRESULT MakeEscapedURL( LPWSTR pszInURL, LPWSTR *ppszOutURL )
27{
28 if( ( NULL == pszInURL ) || ( NULL == ppszOutURL ) )
29 {
30 return( E_INVALIDARG );
31 }
32
33 //
34 // Do we need to pre-pend file://?
35 //
36 BOOL fNeedFilePrefix = ( 0 == wcsstr( pszInURL, L"://" ) );
37
38 //
39 // Count how many characters need to be escaped
40 //
41 LPWSTR pszTemp = pszInURL;
42 DWORD cEscapees = 0;
43
44 while( TRUE )
45 {
46 LPWSTR pchToEscape = wcspbrk( pszTemp, L" #$%&\\+,;=@[]^{}" );
47
48 if( NULL == pchToEscape )
49 {
50 break;
51 }
52
53 cEscapees++;
54
55 pszTemp = pchToEscape + 1;
56 }
57
58 //
59 // Allocate sufficient outgoing buffer space
60 //
61 int cchNeeded = wcslen( pszInURL ) + ( 2 * cEscapees ) + 1;
62
63 if( fNeedFilePrefix )
64 {
65 cchNeeded += wcslen( FILE_PREFIX );
66 }
67
68 *ppszOutURL = new WCHAR[ cchNeeded ];
69
70 if( NULL == *ppszOutURL )
71 {
72 return( E_OUTOFMEMORY );
73 }
74
75 //
76 // Fill in the outgoing escaped buffer
77 //
78 pszTemp = pszInURL;
79
80 LPWSTR pchNext = *ppszOutURL;
81
82 if( fNeedFilePrefix )
83 {
84 wcscpy( *ppszOutURL, FILE_PREFIX );
85 pchNext += wcslen( FILE_PREFIX );
86 }
87
88 while( TRUE )
89 {
90 LPWSTR pchToEscape = wcspbrk( pszTemp, L" #$%&\\+,;=@[]^{}" );
91
92 if( NULL == pchToEscape )
93 {
94 //
95 // Copy the rest of the input string and get out
96 //
97 wcscpy( pchNext, pszTemp );
98 break;
99 }
100
101 //
102 // Copy all characters since the previous escapee
103 //
104 int cchToCopy = pchToEscape - pszTemp;
105
106 if( cchToCopy > 0 )
107 {
108 wcsncpy( pchNext, pszTemp, cchToCopy );
109
110 pchNext += cchToCopy;
111 }
112
113 //
114 // Expand this character into an escape code and move on
115 //
116 pchNext += swprintf( pchNext, L"%%%02x", *pchToEscape );
117
118 pszTemp = pchToEscape + 1;
119 }
120
121 return( S_OK );
122}
123
124
126HRESULT GetShellOpenCommand( LPTSTR ptszShellOpenCommand, DWORD cbShellOpenCommand )
127{
128 LONG lResult;
129
130 HKEY hKey = NULL;
131 HKEY hFileKey = NULL;
132
133 BOOL fFoundExtensionCommand = FALSE;
134
135 do
136 {
137 //
138 // Look for the file type associated with .html files
139 //
140 TCHAR szFileType[ MAX_PATH ];
141
142 lResult = RegOpenKeyEx( HKEY_CLASSES_ROOT, _T( ".html" ), 0, KEY_READ, &hKey );
143
144 if( ERROR_SUCCESS != lResult )
145 {
146 break;
147 }
148
149 DWORD dwLength = sizeof( szFileType );
150
151 lResult = RegQueryValueEx( hKey, NULL, 0, NULL, (BYTE *)szFileType, &dwLength );
152
153 if( ERROR_SUCCESS != lResult )
154 {
155 break;
156 }
157
158 //
159 // Find the command for the shell's open verb associated with this file type
160 //
161 TCHAR szKeyName[ MAX_PATH + 20 ];
162
163 wsprintf( szKeyName, _T( "%s\\shell\\open\\command" ), szFileType );
164
165 lResult = RegOpenKeyEx( HKEY_CLASSES_ROOT, szKeyName, 0, KEY_READ, &hFileKey );
166
167 if( ERROR_SUCCESS != lResult )
168 {
169 break;
170 }
171
172 dwLength = cbShellOpenCommand;
173
174 lResult = RegQueryValueEx( hFileKey, NULL, 0, NULL, (BYTE *)ptszShellOpenCommand, &dwLength );
175
176 if( 0 == lResult )
177 {
178 fFoundExtensionCommand = TRUE;
179 }
180 }
181 while( FALSE );
182
183 //
184 // If there was no application associated with .html files by extension, look for
185 // an application associated with the http protocol
186 //
187 if( !fFoundExtensionCommand )
188 {
189 if( NULL != hKey )
190 {
191 RegCloseKey( hKey );
192 }
193
194 do
195 {
196 //
197 // Find the command for the shell's open verb associated with the http protocol
198 //
199 lResult = RegOpenKeyEx( HKEY_CLASSES_ROOT, _T( "http\\shell\\open\\command" ), 0, KEY_READ, &hKey );
200
201 if( ERROR_SUCCESS != lResult )
202 {
203 break;
204 }
205
206 DWORD dwLength = cbShellOpenCommand;
207
208 lResult = RegQueryValueEx( hKey, NULL, 0, NULL, (BYTE *)ptszShellOpenCommand, &dwLength );
209 }
210 while( FALSE );
211 }
212
213 if( NULL != hKey )
214 {
215 RegCloseKey( hKey );
216 }
217
218 if( NULL != hFileKey )
219 {
220 RegCloseKey( hFileKey );
221 }
222
223 return( HRESULT_FROM_WIN32( lResult ) );
224}
225
226
228HRESULT LaunchURL( LPCWSTR pszURL )
229{
230 HRESULT hr;
231
232 //
233 // Find the appropriate command to launch URLs with
234 //
235 TCHAR szShellOpenCommand[ MAX_PATH * 2 ];
236
237 hr = GetShellOpenCommand( szShellOpenCommand, sizeof( szShellOpenCommand ) );
238
239 if( FAILED( hr ) )
240 {
241 return( hr );
242 }
243
244 //
245 // Build the appropriate command line, substituting our URL parameter
246 //
247 TCHAR szLaunchCommand[ 2000 ];
248
249 LPTSTR pszParam = _tcsstr( szShellOpenCommand, _T( "\"%1\"" ) );
250
251 if( NULL == pszParam )
252 {
253 pszParam = _tcsstr( szShellOpenCommand, _T( "\"%*\"" ) );
254 }
255
256 if( NULL != pszParam )
257 {
258 *pszParam = _T( '\0' ) ;
259
260 wsprintf( szLaunchCommand, _T( "%s%ws%s" ), szShellOpenCommand, pszURL, pszParam + 4 );
261 }
262 else
263 {
264 wsprintf( szLaunchCommand, _T( "%s %ws" ), szShellOpenCommand, pszURL );
265 }
266
267 //
268 // Find the application name, stripping quotes if necessary
269 //
270 TCHAR szExe[ MAX_PATH * 2 ];
271 LPTSTR pchFirst = szShellOpenCommand;
272 LPTSTR pchNext = NULL;
273
274 while( _T( ' ' ) == *pchFirst )
275 {
276 pchFirst++;
277 }
278
279 if( _T( '"' ) == *pchFirst )
280 {
281 pchFirst++;
282
283 pchNext = _tcschr( pchFirst, _T( '"' ) );
284 }
285 else
286 {
287 pchNext = _tcschr( pchFirst + 1, _T( ' ' ) );
288 }
289
290 if( NULL == pchNext )
291 {
292 pchNext = szShellOpenCommand + _tcslen( szShellOpenCommand );
293 }
294
295 _tcsncpy( szExe, pchFirst, pchNext - pchFirst );
296 szExe[ pchNext - pchFirst ] = _T( '\0' ) ;
297
298 //
299 // Because of the extremely long length of the URLs, neither
300 // WinExec, nor ShellExecute, were working correctly. For this reason
301 // we use CreateProcess. The CreateProcess documentation in MSDN says
302 // that the most robust way to call CreateProcess is to pass the full
303 // command line, where the first element is the application name, in the
304 // lpCommandLine parameter. In our case this is necesssary to get Netscape
305 // to function properly.
306 //
307 PROCESS_INFORMATION ProcInfo;
308 ZeroMemory( (LPVOID)&ProcInfo, sizeof( PROCESS_INFORMATION ) );
309
310 STARTUPINFO StartUp;
311 ZeroMemory( (LPVOID)&StartUp, sizeof( STARTUPINFO ) );
312
313 StartUp.cb = sizeof(STARTUPINFO);
314
315 if( !CreateProcess( szExe, szLaunchCommand, NULL, NULL,
316 FALSE, 0, NULL, NULL, &StartUp, &ProcInfo) )
317 {
318 hr = HRESULT_FROM_WIN32( GetLastError() );
319 }
320 else
321 {
322 //
323 // CreateProcess succeeded and we do not need the handles to the thread
324 // or the process, so close them now.
325 //
326 if( NULL != ProcInfo.hThread )
327 {
328 CloseHandle( ProcInfo.hThread );
329 }
330
331 if( NULL != ProcInfo.hProcess )
332 {
333 CloseHandle( ProcInfo.hProcess );
334 }
335 }
336
337 return( hr );
338}
#define NULL
Definition BaseType.h:92
#define TRUE
Definition BaseType.h:109
#define FALSE
Definition BaseType.h:113
unsigned char BYTE
Definition bittype.h:59
unsigned long DWORD
Definition bittype.h:57
LPVOID(__stdcall *SnmpUtilMemAllocPtr)(IN DWORD bytes)
#define BOOL
Definition Wnd_File.h:57
HRESULT LaunchURL(LPCWSTR pszURL)
HRESULT MakeEscapedURL(LPWSTR pszInURL, LPWSTR *ppszOutURL)
Definition urllaunch.cpp:26
#define FILE_PREFIX
Definition urllaunch.cpp:22
HRESULT GetShellOpenCommand(LPTSTR ptszShellOpenCommand, DWORD cbShellOpenCommand)