Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenstartup.c
Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2002 Andreas Mohr 00003 * Copyright (C) 2002 Shachar Shemesh 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00018 */ 00019 00020 /* Based on the Wine "bootup" handler application 00021 * 00022 * This app handles the various "hooks" windows allows for applications to perform 00023 * as part of the bootstrap process. Theses are roughly devided into three types. 00024 * Knowledge base articles that explain this are 137367, 179365, 232487 and 232509. 00025 * Also, 119941 has some info on grpconv.exe 00026 * The operations performed are (by order of execution): 00027 * 00028 * Preboot (prior to fully loading the Windows kernel): 00029 * - wininit.exe (rename operations left in wininit.ini - Win 9x only) 00030 * - PendingRenameOperations (rename operations left in the registry - Win NT+ only) 00031 * 00032 * Startup (before the user logs in) 00033 * - Services (NT, ?semi-synchronous?, not implemented yet) 00034 * - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce (9x, asynch) 00035 * - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices (9x, asynch) 00036 * 00037 * After log in 00038 * - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce (all, synch) 00039 * - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run (all, asynch) 00040 * - HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run (all, asynch) 00041 * - Startup folders (all, ?asynch?, no imp) 00042 * - HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce (all, asynch) 00043 * 00044 * Somewhere in there is processing the RunOnceEx entries (also no imp) 00045 * 00046 * Bugs: 00047 * - If a pending rename registry does not start with \??\ the entry is 00048 * processed anyways. I'm not sure that is the Windows behaviour. 00049 * - Need to check what is the windows behaviour when trying to delete files 00050 * and directories that are read-only 00051 * - In the pending rename registry processing - there are no traces of the files 00052 * processed (requires translations from Unicode to Ansi). 00053 */ 00054 00055 #include <stdio.h> 00056 #include <windows.h> 00057 #include <ctype.h> 00058 00059 EXTERN_C HRESULT WINAPI SHCreateSessionKey(REGSAM samDesired, PHKEY phKey); 00060 00065 static BOOL wininit() 00066 { 00067 return TRUE; 00068 } 00069 00070 static BOOL pendingRename() 00071 { 00072 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g', 00073 'F','i','l','e','R','e','n','a','m','e', 00074 'O','p','e','r','a','t','i','o','n','s',0}; 00075 static const WCHAR SessionW[] = { 'S','y','s','t','e','m','\\', 00076 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 00077 'C','o','n','t','r','o','l','\\', 00078 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0}; 00079 WCHAR *buffer=NULL; 00080 const WCHAR *src=NULL, *dst=NULL; 00081 DWORD dataLength=0; 00082 HKEY hSession=NULL; 00083 DWORD res; 00084 00085 printf("Entered\n"); 00086 00087 if ((res=RegOpenKeyExW(HKEY_LOCAL_MACHINE, SessionW, 0, KEY_ALL_ACCESS, &hSession)) 00088 !=ERROR_SUCCESS) 00089 { 00090 if (res==ERROR_FILE_NOT_FOUND) 00091 { 00092 printf("The key was not found - skipping\n"); 00093 res=TRUE; 00094 } 00095 else 00096 { 00097 printf("Couldn't open key, error %ld\n", res); 00098 res=FALSE; 00099 } 00100 00101 goto end; 00102 } 00103 00104 res=RegQueryValueExW(hSession, ValueName, NULL, NULL /* The value type does not really interest us, as it is not 00105 truely a REG_MULTI_SZ anyways */, 00106 NULL, &dataLength); 00107 if (res==ERROR_FILE_NOT_FOUND) 00108 { 00109 /* No value - nothing to do. Great! */ 00110 printf("Value not present - nothing to rename\n"); 00111 res=TRUE; 00112 goto end; 00113 } 00114 00115 if (res!=ERROR_SUCCESS) 00116 { 00117 printf("Couldn't query value's length (%ld)\n", res); 00118 res=FALSE; 00119 goto end; 00120 } 00121 00122 buffer=malloc(dataLength); 00123 if (buffer==NULL) 00124 { 00125 printf("Couldn't allocate %lu bytes for the value\n", dataLength); 00126 res=FALSE; 00127 goto end; 00128 } 00129 00130 res=RegQueryValueExW(hSession, ValueName, NULL, NULL, (LPBYTE)buffer, &dataLength); 00131 if (res!=ERROR_SUCCESS) 00132 { 00133 printf("Couldn't query value after successfully querying before (%lu),\n" 00134 "please report to wine-devel@winehq.org\n", res); 00135 res=FALSE; 00136 goto end; 00137 } 00138 00139 /* Make sure that the data is long enough and ends with two NULLs. This 00140 * simplifies the code later on. 00141 */ 00142 if (dataLength<2*sizeof(buffer[0]) || 00143 buffer[dataLength/sizeof(buffer[0])-1]!='\0' || 00144 buffer[dataLength/sizeof(buffer[0])-2]!='\0') 00145 { 00146 printf("Improper value format - doesn't end with NULL\n"); 00147 res=FALSE; 00148 goto end; 00149 } 00150 00151 for(src=buffer; (src-buffer)*sizeof(src[0])<dataLength && *src!='\0'; 00152 src=dst+lstrlenW(dst)+1) 00153 { 00154 DWORD dwFlags=0; 00155 00156 printf("processing next command\n"); 00157 00158 dst=src+lstrlenW(src)+1; 00159 00160 /* We need to skip the \??\ header */ 00161 if (src[0]=='\\' && src[1]=='?' && src[2]=='?' && src[3]=='\\') 00162 src+=4; 00163 00164 if (dst[0]=='!') 00165 { 00166 dwFlags|=MOVEFILE_REPLACE_EXISTING; 00167 dst++; 00168 } 00169 00170 if (dst[0]=='\\' && dst[1]=='?' && dst[2]=='?' && dst[3]=='\\') 00171 dst+=4; 00172 00173 if (*dst!='\0') 00174 { 00175 /* Rename the file */ 00176 MoveFileExW(src, dst, dwFlags); 00177 } else 00178 { 00179 /* Delete the file or directory */ 00180 res = GetFileAttributesW (src); 00181 if (res != (DWORD)-1) 00182 { 00183 if ((res&FILE_ATTRIBUTE_DIRECTORY)==0) 00184 { 00185 /* It's a file */ 00186 DeleteFileW(src); 00187 } else 00188 { 00189 /* It's a directory */ 00190 RemoveDirectoryW(src); 00191 } 00192 } else 00193 { 00194 printf("couldn't get file attributes (%ld)\n", GetLastError()); 00195 } 00196 } 00197 } 00198 00199 if ((res=RegDeleteValueW(hSession, ValueName))!=ERROR_SUCCESS) 00200 { 00201 printf("Error deleting the value (%lu)\n", GetLastError()); 00202 res=FALSE; 00203 } else 00204 res=TRUE; 00205 00206 end: 00207 if (buffer!=NULL) 00208 free(buffer); 00209 00210 if (hSession!=NULL) 00211 RegCloseKey(hSession); 00212 00213 return res; 00214 } 00215 00216 enum runkeys { 00217 RUNKEY_RUN, RUNKEY_RUNONCE, RUNKEY_RUNSERVICES, RUNKEY_RUNSERVICESONCE 00218 }; 00219 00220 const WCHAR runkeys_names[][30]= 00221 { 00222 {'R','u','n',0}, 00223 {'R','u','n','O','n','c','e',0}, 00224 {'R','u','n','S','e','r','v','i','c','e','s',0}, 00225 {'R','u','n','S','e','r','v','i','c','e','s','O','n','c','e',0} 00226 }; 00227 00228 #define INVALID_RUNCMD_RETURN -1 00229 00241 static int runCmd(LPWSTR cmdline, LPCWSTR dir, BOOL wait, BOOL minimized) 00242 { 00243 STARTUPINFOW si; 00244 PROCESS_INFORMATION info; 00245 DWORD exit_code=0; 00246 WCHAR szCmdLineExp[MAX_PATH+1]= L"\0"; 00247 00248 ExpandEnvironmentStrings(cmdline, szCmdLineExp, sizeof(szCmdLineExp)); 00249 00250 memset(&si, 0, sizeof(si)); 00251 si.cb=sizeof(si); 00252 if (minimized) 00253 { 00254 si.dwFlags=STARTF_USESHOWWINDOW; 00255 si.wShowWindow=SW_MINIMIZE; 00256 } 00257 memset(&info, 0, sizeof(info)); 00258 00259 if (!CreateProcessW(NULL, szCmdLineExp, NULL, NULL, FALSE, 0, NULL, dir, &si, &info)) 00260 { 00261 printf("Failed to run command (%ld)\n", GetLastError()); 00262 00263 return INVALID_RUNCMD_RETURN; 00264 } 00265 00266 printf("Successfully ran command\n"); //%s - Created process handle %p\n", 00267 //wine_dbgstr_w(szCmdLineExp), info.hProcess); 00268 00269 if (wait) 00270 { /* wait for the process to exit */ 00271 WaitForSingleObject(info.hProcess, INFINITE); 00272 GetExitCodeProcess(info.hProcess, &exit_code); 00273 } 00274 00275 CloseHandle(info.hThread); 00276 CloseHandle(info.hProcess); 00277 00278 return exit_code; 00279 } 00280 00290 static BOOL ProcessRunKeys(HKEY hkRoot, LPCWSTR szKeyName, BOOL bDelete, 00291 BOOL bSynchronous) 00292 { 00293 static const WCHAR WINKEY_NAME[]={'S','o','f','t','w','a','r','e','\\', 00294 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', 00295 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0}; 00296 HKEY hkWin=NULL, hkRun=NULL; 00297 LONG res=ERROR_SUCCESS; 00298 DWORD i, nMaxCmdLine=0, nMaxValue=0; 00299 WCHAR *szCmdLine=NULL; 00300 WCHAR *szValue=NULL; 00301 00302 if (hkRoot==HKEY_LOCAL_MACHINE) 00303 wprintf(L"processing %s entries under HKLM\n", szKeyName); 00304 else 00305 wprintf(L"processing %s entries under HKCU\n", szKeyName); 00306 00307 if ((res=RegOpenKeyExW(hkRoot, WINKEY_NAME, 0, KEY_READ, &hkWin))!=ERROR_SUCCESS) 00308 { 00309 printf("RegOpenKey failed on Software\\Microsoft\\Windows\\CurrentVersion (%ld)\n", 00310 res); 00311 00312 goto end; 00313 } 00314 00315 if ((res=RegOpenKeyExW(hkWin, szKeyName, 0, bDelete?KEY_ALL_ACCESS:KEY_READ, &hkRun))!= 00316 ERROR_SUCCESS) 00317 { 00318 if (res==ERROR_FILE_NOT_FOUND) 00319 { 00320 printf("Key doesn't exist - nothing to be done\n"); 00321 00322 res=ERROR_SUCCESS; 00323 } 00324 else 00325 printf("RegOpenKey failed on run key (%ld)\n", res); 00326 00327 goto end; 00328 } 00329 00330 if ((res=RegQueryInfoKeyW(hkRun, NULL, NULL, NULL, NULL, NULL, NULL, &i, &nMaxValue, 00331 &nMaxCmdLine, NULL, NULL))!=ERROR_SUCCESS) 00332 { 00333 printf("Couldn't query key info (%ld)\n", res); 00334 00335 goto end; 00336 } 00337 00338 if (i==0) 00339 { 00340 printf("No commands to execute.\n"); 00341 00342 res=ERROR_SUCCESS; 00343 goto end; 00344 } 00345 00346 if ((szCmdLine=malloc(nMaxCmdLine))==NULL) 00347 { 00348 printf("Couldn't allocate memory for the commands to be executed\n"); 00349 00350 res=ERROR_NOT_ENOUGH_MEMORY; 00351 goto end; 00352 } 00353 00354 if ((szValue=malloc((++nMaxValue)*sizeof(*szValue)))==NULL) 00355 { 00356 printf("Couldn't allocate memory for the value names\n"); 00357 00358 free(szCmdLine); 00359 res=ERROR_NOT_ENOUGH_MEMORY; 00360 goto end; 00361 } 00362 00363 while(i>0) 00364 { 00365 DWORD nValLength=nMaxValue, nDataLength=nMaxCmdLine; 00366 DWORD type; 00367 00368 --i; 00369 00370 if ((res=RegEnumValueW(hkRun, i, szValue, &nValLength, 0, &type, 00371 (LPBYTE)szCmdLine, &nDataLength))!=ERROR_SUCCESS) 00372 { 00373 printf("Couldn't read in value %ld - %ld\n", i, res); 00374 00375 continue; 00376 } 00377 00378 /* safe mode - force to run if prefixed with asterisk */ 00379 if (GetSystemMetrics(SM_CLEANBOOT) && (szValue[0] != L'*')) continue; 00380 00381 if (bDelete && (res=RegDeleteValueW(hkRun, szValue))!=ERROR_SUCCESS) 00382 { 00383 printf("Couldn't delete value - %ld, %ld. Running command anyways.\n", i, res); 00384 } 00385 00386 if (type!=REG_SZ) 00387 { 00388 printf("Incorrect type of value #%ld (%ld)\n", i, type); 00389 00390 continue; 00391 } 00392 00393 if ((res=runCmd(szCmdLine, NULL, bSynchronous, FALSE))==INVALID_RUNCMD_RETURN) 00394 { 00395 printf("Error running cmd #%ld (%ld)\n", i, GetLastError()); 00396 } 00397 00398 printf("Done processing cmd #%ld\n", i); 00399 } 00400 00401 free(szValue); 00402 free(szCmdLine); 00403 res=ERROR_SUCCESS; 00404 00405 end: 00406 if (hkRun!=NULL) 00407 RegCloseKey(hkRun); 00408 if (hkWin!=NULL) 00409 RegCloseKey(hkWin); 00410 00411 printf("done\n"); 00412 00413 return res==ERROR_SUCCESS?TRUE:FALSE; 00414 } 00415 00417 struct op_mask { 00418 BOOL w9xonly; /* Perform only operations done on Windows 9x */ 00419 BOOL ntonly; /* Perform only operations done on Windows NT */ 00420 BOOL startup; /* Perform the operations that are performed every boot */ 00421 BOOL preboot; /* Perform file renames typically done before the system starts */ 00422 BOOL prelogin; /* Perform the operations typically done before the user logs in */ 00423 BOOL postlogin; /* Operations done after login */ 00424 }; 00425 00426 static const struct op_mask 00427 SESSION_START = {FALSE, FALSE, TRUE, TRUE, TRUE, TRUE}, 00428 SETUP = {FALSE, FALSE, FALSE, TRUE, TRUE, TRUE}; 00429 #define DEFAULT SESSION_START 00430 00431 int startup(int argc, const char *argv[]) 00432 { 00433 struct op_mask ops; /* Which of the ops do we want to perform? */ 00434 /* First, set the current directory to SystemRoot */ 00435 TCHAR gen_path[MAX_PATH]; 00436 DWORD res; 00437 HKEY hSessionKey, hKey; 00438 HRESULT hr; 00439 00440 res = GetWindowsDirectory(gen_path, sizeof(gen_path)); 00441 00442 if (res==0) 00443 { 00444 printf("Couldn't get the windows directory - error %ld\n", 00445 GetLastError()); 00446 00447 return 100; 00448 } 00449 00450 if (!SetCurrentDirectory(gen_path)) 00451 { 00452 wprintf(L"Cannot set the dir to %s (%ld)\n", gen_path, GetLastError()); 00453 00454 return 100; 00455 } 00456 00457 hr = SHCreateSessionKey(KEY_WRITE, &hSessionKey); 00458 if (SUCCEEDED(hr)) 00459 { 00460 LONG Error; 00461 DWORD dwDisp; 00462 00463 Error = RegCreateKeyEx(hSessionKey, L"StartupHasBeenRun", 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp); 00464 RegCloseKey(hSessionKey); 00465 if (Error == ERROR_SUCCESS) 00466 { 00467 RegCloseKey(hKey); 00468 if (dwDisp == REG_OPENED_EXISTING_KEY) 00469 { 00470 /* Startup programs has already been run */ 00471 return 0; 00472 } 00473 } 00474 } 00475 00476 if (argc > 1) 00477 { 00478 switch(argv[1][0]) 00479 { 00480 case 'r': /* Restart */ 00481 ops = SETUP; 00482 break; 00483 case 's': /* Full start */ 00484 ops = SESSION_START; 00485 break; 00486 default: 00487 ops = DEFAULT; 00488 break; 00489 } 00490 } else 00491 ops = DEFAULT; 00492 00493 /* do not run certain items in Safe Mode */ 00494 if(GetSystemMetrics(SM_CLEANBOOT)) ops.startup = FALSE; 00495 00496 /* Perform the ops by order, stopping if one fails, skipping if necessary */ 00497 /* Shachar: Sorry for the perl syntax */ 00498 res = TRUE; 00499 if (res && !ops.ntonly && ops.preboot) 00500 res = wininit(); 00501 if (res && !ops.w9xonly && ops.preboot) 00502 res = pendingRename(); 00503 if (res && !ops.ntonly && ops.prelogin) 00504 res = ProcessRunKeys(HKEY_LOCAL_MACHINE, runkeys_names[RUNKEY_RUNSERVICESONCE], TRUE, FALSE); 00505 if (res && !ops.ntonly && ops.prelogin && ops.startup) 00506 res = ProcessRunKeys(HKEY_LOCAL_MACHINE, runkeys_names[RUNKEY_RUNSERVICES], FALSE, FALSE); 00507 if (res && ops.postlogin) 00508 res = ProcessRunKeys(HKEY_LOCAL_MACHINE, runkeys_names[RUNKEY_RUNONCE], TRUE, TRUE); 00509 if (res && ops.postlogin && ops.startup) 00510 res = ProcessRunKeys(HKEY_LOCAL_MACHINE, runkeys_names[RUNKEY_RUN], FALSE, FALSE); 00511 if (res && ops.postlogin && ops.startup) 00512 res = ProcessRunKeys(HKEY_CURRENT_USER, runkeys_names[RUNKEY_RUN], FALSE, FALSE); 00513 if (res && ops.postlogin && ops.startup) 00514 res = ProcessRunKeys(HKEY_CURRENT_USER, runkeys_names[RUNKEY_RUNONCE], TRUE, FALSE); 00515 00516 printf("Operation done\n"); 00517 00518 return res ? 0 : 101; 00519 } Generated on Sat May 26 2012 04:17:29 for ReactOS by
1.7.6.1
|