ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

startup.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.