Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

352 lines
6.8 KiB

  1. // Active Directory Display Specifier Upgrade Tool
  2. //
  3. // Copyright (c) 2001 Microsoft Corporation
  4. //
  5. // 1 Mar 2001 sburns
  6. #include "headers.hxx"
  7. #include "resource.h"
  8. #include "AdsiHelpers.hpp"
  9. #include "Repairer.hpp"
  10. #include "Amanuensis.hpp"
  11. #include "Analyst.hpp"
  12. HINSTANCE hResourceModuleHandle = 0;
  13. const wchar_t* HELPFILE_NAME = 0; // no context help available
  14. // don't change this: it is also the name of a mutex that the ui
  15. // uses to determine if it is already running.
  16. const wchar_t* RUNTIME_NAME = L"dspecup";
  17. DWORD DEFAULT_LOGGING_OPTIONS =
  18. Log::OUTPUT_TO_FILE
  19. | Log::OUTPUT_FUNCCALLS
  20. | Log::OUTPUT_LOGS
  21. | Log::OUTPUT_ERRORS
  22. | Log::OUTPUT_HEADER;
  23. Popup popup(IDS_APP_TITLE, false);
  24. // this is the mutex that indicates the program is running.
  25. HANDLE appRunningMutex = INVALID_HANDLE_VALUE;
  26. // these are the valid exit codes returned as the process exit code
  27. enum ExitCode
  28. {
  29. // the operation failed.
  30. EXIT_CODE_UNSUCCESSFUL = 0,
  31. // the operation succeeded
  32. EXIT_CODE_SUCCESSFUL = 1,
  33. };
  34. // returns true if the parameter was extracted. If so, it is removed from
  35. // args
  36. bool
  37. ExtractParameter(
  38. ArgMap& args,
  39. const String& parameterName,
  40. String& parameterValue)
  41. {
  42. LOG_FUNCTION2(ExtractParameter, parameterName);
  43. ASSERT(!parameterName.empty());
  44. parameterValue.erase();
  45. bool result = false;
  46. ArgMap::iterator itr = args.find(parameterName);
  47. if (itr != args.end())
  48. {
  49. parameterValue = itr->second;
  50. args.erase(itr);
  51. result = true;
  52. }
  53. LOG_BOOL(result);
  54. LOG(parameterValue);
  55. return result;
  56. }
  57. // Returns false if the command line is malformed.
  58. bool
  59. ParseCommandLine(
  60. String& targetMachine,
  61. String& csvFilename)
  62. {
  63. LOG_FUNCTION(ParseCommandLine);
  64. targetMachine.erase();
  65. csvFilename.erase();
  66. bool result = true;
  67. ArgMap args;
  68. MapCommandLineArgs(args);
  69. // check for target domain controller parameter
  70. static const String TARGETDC(L"dc");
  71. ExtractParameter(args, TARGETDC, targetMachine);
  72. // check for csv filename parameter
  73. static const String CSVFILE(L"csv");
  74. ExtractParameter(args, CSVFILE, csvFilename);
  75. // anything left over gets you command line help, (one arg will always
  76. // remain: the name of the exe)
  77. if (args.size() > 1)
  78. {
  79. LOG(L"Unrecognized command line options specified");
  80. result = false;
  81. }
  82. LOG_BOOL(result);
  83. LOG(targetMachine);
  84. LOG(csvFilename);
  85. return result;
  86. }
  87. HRESULT
  88. FindCsvFile(const String& targetPath, String& csvFilePath)
  89. {
  90. LOG_FUNCTION(CheckPreconditions);
  91. csvFilePath.erase();
  92. HRESULT hr = S_OK;
  93. do
  94. {
  95. // look for dcpromo.csv file in system or current directory
  96. if (targetPath.empty())
  97. {
  98. // no preference given, so check the default of
  99. // %windir%\system32\mui\dispspec\dcpromo.csv and
  100. // .\dcpromo.csv
  101. static const String csvname(L"dcpromo.csv");
  102. String sys32dir = Win::GetSystemDirectory();
  103. String csvPath = sys32dir + L"\\mui\\dispspec\\" + csvname;
  104. if (FS::FileExists(csvPath))
  105. {
  106. csvFilePath = csvPath;
  107. break;
  108. }
  109. csvPath = L".\\" + csvname;
  110. if (FS::FileExists(csvPath))
  111. {
  112. csvFilePath = csvPath;
  113. break;
  114. }
  115. }
  116. else
  117. {
  118. if (FS::FileExists(targetPath))
  119. {
  120. csvFilePath = targetPath;
  121. break;
  122. }
  123. }
  124. // not found.
  125. hr = S_FALSE;
  126. }
  127. while (0);
  128. LOG_HRESULT(hr);
  129. LOG(csvFilePath);
  130. return hr;
  131. }
  132. HRESULT
  133. Start()
  134. {
  135. LOG_FUNCTION(Start);
  136. HRESULT hr = S_OK;
  137. do
  138. {
  139. //
  140. // parse the command line options
  141. //
  142. String targetDomainControllerName;
  143. String csvFilename;
  144. ParseCommandLine(
  145. targetDomainControllerName,
  146. csvFilename);
  147. //
  148. // find the dcpromo.csv file to use
  149. //
  150. hr = FindCsvFile(csvFilename, csvFilename);
  151. if (FAILED(hr))
  152. {
  153. // encountered an error looking for the csv file
  154. popup.Error(
  155. Win::GetDesktopWindow(),
  156. hr,
  157. IDS_ERROR_LOOKING_FOR_CSV_FILE);
  158. break;
  159. }
  160. if (hr == S_FALSE)
  161. {
  162. // no error looking, just not found.
  163. popup.Error(
  164. Win::GetDesktopWindow(),
  165. IDS_DCPROMO_CSV_FILE_MISSING);
  166. break;
  167. }
  168. //
  169. // Determine the target domain controller
  170. //
  171. if (targetDomainControllerName.empty())
  172. {
  173. // no target specified, default to the current machine
  174. targetDomainControllerName =
  175. Win::GetComputerNameEx(ComputerNameDnsFullyQualified);
  176. if (targetDomainControllerName.empty())
  177. {
  178. // no DNS name? that's not right...
  179. LOG(L"no default DNS computer name found. Using netbios name.");
  180. targetDomainControllerName = Win::GetComputerNameEx(ComputerNameNetBIOS);
  181. }
  182. }
  183. //
  184. // Analysis Phase
  185. //
  186. // First we need a Repairer object to keep track of the changes we
  187. // will make during the Repair Phase.
  188. Repairer
  189. repairer(
  190. csvFilename
  191. // might also need domain NC,
  192. // might also need targetMachine full name
  193. );
  194. // Then we need a scribe to record the analysis.
  195. Amanuensis amanuensis;
  196. // Then we need an Analyst to figure out what's broken and how to
  197. // fix it.
  198. Analyst analyst(targetDomainControllerName, amanuensis, repairer);
  199. hr = analyst.AnalyzeDisplaySpecifiers();
  200. BREAK_ON_FAILED_HRESULT(hr);
  201. //
  202. // Repair Phase
  203. //
  204. // CODEWORK: get user confirmation to apply repairs
  205. hr = repairer.BuildRepairFiles();
  206. BREAK_ON_FAILED_HRESULT(hr);
  207. hr = repairer.ApplyRepairs();
  208. BREAK_ON_FAILED_HRESULT(hr);
  209. }
  210. while (0);
  211. LOG_HRESULT(hr);
  212. return hr;
  213. }
  214. int WINAPI
  215. WinMain(
  216. HINSTANCE hInstance,
  217. HINSTANCE /* hPrevInstance */ ,
  218. PSTR /* lpszCmdLine */ ,
  219. int /* nCmdShow */)
  220. {
  221. hResourceModuleHandle = hInstance;
  222. ExitCode exitCode = EXIT_CODE_UNSUCCESSFUL;
  223. HRESULT hr = Win::CreateMutex(0, true, RUNTIME_NAME, appRunningMutex);
  224. if (hr == Win32ToHresult(ERROR_ALREADY_EXISTS))
  225. {
  226. // The application is already running
  227. // CODEWORK: use FindWindowEx and BringWindowToTop,
  228. // SetForegroundWindow to transfer focus
  229. // to the other instance?
  230. }
  231. else
  232. {
  233. hr = ::CoInitialize(0);
  234. ASSERT(SUCCEEDED(hr));
  235. hr = Start();
  236. if (SUCCEEDED(hr))
  237. {
  238. exitCode = EXIT_CODE_SUCCESSFUL;
  239. }
  240. }
  241. return static_cast<int>(exitCode);
  242. }