Leaked source code of windows server 2003
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.

1168 lines
34 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright(c) Microsoft Corp., 1999 **
  4. //*********************************************************************
  5. //
  6. // API.CPP - Header for the implementation of CAPI
  7. //
  8. // HISTORY:
  9. //
  10. // 1/27/99 a-jaswed Created.
  11. //
  12. #include "api.h"
  13. #include "appdefs.h"
  14. #include "dispids.h"
  15. #include "msobmain.h"
  16. #include "resource.h"
  17. #include <shlobj.h> // bugbug SHGetFolderPath should be used in the future
  18. #include <shlwapi.h>
  19. #include <util.h>
  20. //
  21. // List of characters that are not legal in netnames.
  22. //
  23. static const WCHAR IllegalNetNameChars[] = L"\"/\\[]:|<>+=;,.?* ";
  24. #define REGSTR_PATH_COMPUTERNAME \
  25. L"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName"
  26. #define REGSTR_PATH_ACTIVECOMPUTERNAME \
  27. L"System\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName"
  28. #define REGSTR_PATH_TCPIP_PARAMETERS \
  29. L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
  30. #define REGSTR_PATH_VOLATILEENVIRONMENT \
  31. L"VolatileEnvironment"
  32. #define REGSTR_VALUE_HOSTNAME L"Hostname"
  33. #define REGSTR_VALUE_LOGONSERVER L"LOGONSERVER"
  34. DISPATCHLIST APIExternalInterface[] =
  35. {
  36. {L"SaveFile", DISPID_API_SAVEFILE },
  37. {L"SaveFileByCSIDL", DISPID_API_SAVEFILEBYCSIDL },
  38. {L"get_INIKey", DISPID_API_GET_INIKEY },
  39. {L"get_RegValue", DISPID_API_GET_REGVALUE },
  40. {L"set_RegValue", DISPID_API_SET_REGVALUE },
  41. {L"DeleteRegValue", DISPID_API_DELETEREGVALUE },
  42. {L"DeleteRegKey", DISPID_API_DELETEREGKEY },
  43. {L"get_SystemDirectory", DISPID_API_GET_SYSTEMDIRECTORY },
  44. {L"get_CSIDLDirectory", DISPID_API_GET_CSIDLDIRECTORY },
  45. {L"LoadFile", DISPID_API_LOADFILE, },
  46. {L"get_UserDefaultLCID", DISPID_API_GET_USERDEFAULTLCID },
  47. {L"get_ComputerName", DISPID_API_GET_COMPUTERNAME },
  48. {L"set_ComputerName", DISPID_API_SET_COMPUTERNAME },
  49. {L"FlushRegKey", DISPID_API_FLUSHREGKEY },
  50. {L"ValidateComputername", DISPID_API_VALIDATECOMPUTERNAME },
  51. {L"OEMComputername", DISPID_API_OEMCOMPUTERNAME },
  52. {L"FormatMessage", DISPID_API_FORMATMESSAGE },
  53. {L"set_ComputerDesc", DISPID_API_SET_COMPUTERDESC },
  54. {L"get_UserDefaultUILanguage", DISPID_API_GET_USERDEFAULTUILANGUAGE }
  55. };
  56. /////////////////////////////////////////////////////////////
  57. // CAPI::CAPI
  58. CAPI::CAPI(HINSTANCE hInstance)
  59. {
  60. m_cRef = 0;
  61. }
  62. /////////////////////////////////////////////////////////////
  63. // CAPI::~CAPI
  64. CAPI::~CAPI()
  65. {
  66. MYASSERT(m_cRef == 0);
  67. }
  68. ////////////////////////////////////////////////
  69. ////////////////////////////////////////////////
  70. //// GET / SET :: APILocale
  71. ////
  72. HRESULT CAPI::SaveFile(LPCWSTR szPath, LPCWSTR szURL, LPCWSTR szNewFileName)
  73. {
  74. WCHAR szFilePath[MAX_PATH];
  75. lstrcpy(szFilePath, szPath);
  76. lstrcat(szFilePath, szNewFileName);
  77. return URLDownloadToFile(NULL, szURL, szFilePath, 0, NULL);
  78. }
  79. //SHGetSpecialFolderPath is only available if you have the new shell32.dll that came with IE 4.0
  80. typedef BOOL (WINAPI* PFNSHGetPath)(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate);
  81. // bugbug SHGetFolderPath should be used in the future
  82. HRESULT CAPI::WrapSHGetSpecialFolderPath(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate)
  83. {
  84. HRESULT hr = E_NOTIMPL;
  85. HINSTANCE hShell32 = LoadLibrary(L"SHELL32.DLL");
  86. if (NULL != hShell32)
  87. {
  88. PFNSHGetPath pfnGetPath = (PFNSHGetPath)GetProcAddress(hShell32, "SHGetSpecialFolderPathW");
  89. if (NULL != pfnGetPath)
  90. {
  91. hr = pfnGetPath(hwndOwner, lpszPath, nFolder, fCreate) ? S_OK : E_FAIL;
  92. }
  93. FreeLibrary(hShell32);
  94. }
  95. return hr;
  96. }
  97. HRESULT CAPI::SaveFile(INT iCSIDLPath, BSTR bstrURL, BSTR bstrNewFileName)
  98. {
  99. WCHAR szFilePath[MAX_PATH];
  100. // bugbug should we always create this?
  101. HRESULT hr = WrapSHGetSpecialFolderPath(NULL, szFilePath, iCSIDLPath, TRUE);
  102. if (FAILED(hr))
  103. return (hr);
  104. lstrcat(szFilePath, L"\\");
  105. return SaveFile(szFilePath, bstrURL, bstrNewFileName);
  106. }
  107. HRESULT CAPI::SaveFile(BSTR bstrPath, BSTR bstrURL)
  108. {
  109. WCHAR szURLPath[MAX_PATH];
  110. lstrcpy(szURLPath, bstrURL);
  111. LPWSTR pchFileName = wcsrchr(szURLPath, L'/');
  112. if (NULL != pchFileName)
  113. {
  114. *pchFileName++;
  115. return SaveFile(bstrPath, szURLPath, pchFileName);
  116. }
  117. else
  118. return E_FAIL;
  119. }
  120. HRESULT CAPI::SaveFile(INT iCSIDLPath, BSTR bstrURL)
  121. {
  122. WCHAR szURLPath[MAX_PATH];
  123. WCHAR szFilePath[MAX_PATH];
  124. // bugbug should we always create this?
  125. HRESULT hr = WrapSHGetSpecialFolderPath(NULL, szFilePath, iCSIDLPath, TRUE);
  126. if (FAILED(hr))
  127. return (hr);
  128. lstrcpy(szURLPath, bstrURL);
  129. LPWSTR pchFileName = wcsrchr(szURLPath, L'/');
  130. if (NULL != pchFileName)
  131. {
  132. *pchFileName++;
  133. lstrcat(szFilePath, L"\\");
  134. return SaveFile(szFilePath, szURLPath, pchFileName);
  135. }
  136. else
  137. return E_FAIL;
  138. }
  139. HRESULT CAPI::get_INIKey(BSTR bstrINIFileName, BSTR bstrSectionName, BSTR bstrKeyName, LPVARIANT pvResult)
  140. {
  141. WCHAR szItem[1024]; //bugbug bad constants
  142. VariantInit(pvResult);
  143. if (GetPrivateProfileString(bstrSectionName, bstrKeyName, L"",
  144. szItem, MAX_CHARS_IN_BUFFER(szItem), bstrINIFileName))
  145. {
  146. V_VT(pvResult) = VT_BSTR;
  147. V_BSTR(pvResult) = SysAllocString(szItem);
  148. return S_OK;
  149. }
  150. else
  151. return S_FALSE;
  152. }
  153. bool VerifyHKEY(HKEY hkey)
  154. {
  155. if (HKEY_CLASSES_ROOT == hkey ||
  156. HKEY_CURRENT_USER == hkey ||
  157. HKEY_LOCAL_MACHINE == hkey ||
  158. HKEY_USERS == hkey ||
  159. HKEY_PERFORMANCE_DATA == hkey ||
  160. HKEY_CURRENT_CONFIG == hkey ||
  161. HKEY_DYN_DATA == hkey)
  162. return true;
  163. return false;
  164. }
  165. HRESULT CAPI::FlushRegKey(HKEY hkey)
  166. {
  167. DWORD dwResult;
  168. dwResult = RegFlushKey(hkey);
  169. return ERROR_SUCCESS == dwResult ? S_OK : E_FAIL;
  170. }
  171. HRESULT CAPI::set_RegValue(HKEY hkey, BSTR bstrSubKey, BSTR bstrValue, LPVARIANT pvData)
  172. {
  173. if (!VerifyHKEY(hkey))
  174. return E_INVALIDARG;
  175. DWORD dwResult, dwData;
  176. switch (V_VT(pvData))
  177. {
  178. default:
  179. dwResult = E_FAIL;
  180. break;
  181. case VT_R8:
  182. dwData = (DWORD) V_R8(pvData);
  183. dwResult = SHSetValue(hkey, bstrSubKey, bstrValue,
  184. REG_DWORD, (LPVOID) &dwData, sizeof(dwData));
  185. break;
  186. case VT_I4:
  187. dwResult = SHSetValue(hkey, bstrSubKey, bstrValue,
  188. REG_DWORD, (LPVOID) &V_I4(pvData), sizeof(V_I4(pvData)));
  189. break;
  190. case VT_BSTR:
  191. dwResult = SHSetValue(hkey, bstrSubKey, bstrValue,
  192. REG_SZ, (LPVOID) (V_BSTR(pvData)), BYTES_REQUIRED_BY_SZ(V_BSTR(pvData)));
  193. break;
  194. }
  195. return ERROR_SUCCESS == dwResult ? S_OK : E_FAIL;
  196. }
  197. HRESULT CAPI::get_RegValue(HKEY hkey, BSTR bstrSubKey,
  198. BSTR bstrValue, LPVARIANT pvResult)
  199. {
  200. if (!VerifyHKEY(hkey))
  201. return E_INVALIDARG;
  202. DWORD dwType = REG_DWORD, cbData = 1024;
  203. BYTE rgbData[1024]; // bugbug data size
  204. HRESULT hr = ERROR_SUCCESS == SHGetValue(hkey, bstrSubKey, bstrValue,
  205. &dwType, (LPVOID) rgbData, &cbData) ? S_OK : E_FAIL;
  206. VariantInit(pvResult);
  207. switch (dwType)
  208. {
  209. default:
  210. case REG_DWORD:
  211. V_VT(pvResult) = VT_I4;
  212. V_I4(pvResult) = (SUCCEEDED(hr) && cbData >= sizeof(long)) ? * (long *) &rgbData : 0;
  213. break;
  214. case REG_SZ:
  215. V_VT(pvResult) = VT_BSTR;
  216. V_BSTR(pvResult) = SysAllocString(SUCCEEDED(hr) ? (LPCWSTR) rgbData : L"");
  217. break;
  218. }
  219. return hr;
  220. }
  221. HRESULT CAPI::DeleteRegKey(HKEY hkey, BSTR bstrSubKey)
  222. {
  223. if (!VerifyHKEY(hkey))
  224. return E_INVALIDARG;
  225. return ERROR_SUCCESS == SHDeleteKey(hkey, bstrSubKey) ? S_OK : E_FAIL;
  226. }
  227. HRESULT CAPI::DeleteRegValue(HKEY hkey, BSTR bstrSubKey, BSTR bstrValue)
  228. {
  229. if (!VerifyHKEY(hkey))
  230. return E_INVALIDARG;
  231. return ERROR_SUCCESS == SHDeleteValue(hkey, bstrSubKey, bstrValue) ? S_OK : E_FAIL;
  232. }
  233. HRESULT CAPI::get_SystemDirectory(LPVARIANT pvResult)
  234. {
  235. WCHAR szSysPath[MAX_PATH];
  236. if (0 == GetSystemDirectory(szSysPath, MAX_PATH))
  237. return E_FAIL;
  238. V_VT(pvResult) = VT_BSTR;
  239. V_BSTR(pvResult) = SysAllocString(szSysPath);
  240. return S_OK;
  241. };
  242. HRESULT CAPI::get_CSIDLDirectory(UINT iCSIDLPath, LPVARIANT pvResult)
  243. {
  244. WCHAR szSysPath[MAX_PATH];
  245. // bugbug should we always create this?
  246. HRESULT hr = WrapSHGetSpecialFolderPath(NULL, szSysPath, iCSIDLPath, TRUE);
  247. V_VT(pvResult) = VT_BSTR;
  248. V_BSTR(pvResult) = SysAllocString(SUCCEEDED(hr) ? (LPCWSTR) szSysPath : L"");
  249. return hr ;
  250. };
  251. HRESULT CAPI::LoadFile(BSTR bstrPath, LPVARIANT pvResult)
  252. {
  253. HANDLE fh = INVALID_HANDLE_VALUE;
  254. HRESULT hr = E_FAIL;
  255. VariantInit(pvResult);
  256. V_VT(pvResult) = VT_BSTR;
  257. V_BSTR(pvResult) = NULL;
  258. fh = CreateFile(bstrPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  259. if (fh != INVALID_HANDLE_VALUE)
  260. {
  261. DWORD cbSizeHigh = 0;
  262. DWORD cbSizeLow = GetFileSize(fh, &cbSizeHigh);
  263. BYTE* pbContents = new BYTE[cbSizeLow+1];
  264. // We don't plan to read files greater than a DWORD in length, but we
  265. // want to know if we do.
  266. MYASSERT(0 == cbSizeHigh);
  267. if (NULL != pbContents)
  268. {
  269. if (ReadFile(fh, pbContents, cbSizeLow, &cbSizeHigh, NULL))
  270. {
  271. // File contains ANSI chars
  272. //
  273. USES_CONVERSION;
  274. LPSTR szContents = (LPSTR) pbContents;
  275. pbContents[cbSizeLow] = '\0';
  276. // Make sure there's no imbedded NULs because we rely on lstrlen
  277. MYASSERT( strlen((const char *)pbContents) == cbSizeLow );
  278. V_BSTR(pvResult) = SysAllocString(A2W(szContents));
  279. if (V_BSTR(pvResult)
  280. )
  281. {
  282. hr = S_OK;
  283. }
  284. szContents = NULL;
  285. }
  286. delete [] pbContents;
  287. pbContents = NULL;
  288. }
  289. CloseHandle(fh);
  290. fh = INVALID_HANDLE_VALUE;
  291. }
  292. return hr;
  293. }
  294. HRESULT CAPI::get_UserDefaultLCID(LPVARIANT pvResult)
  295. {
  296. VariantInit(pvResult);
  297. V_VT(pvResult) = VT_I4;
  298. V_I4(pvResult) = GetUserDefaultLCID();
  299. return S_OK;
  300. };
  301. STDMETHODIMP
  302. CAPI::get_UserDefaultUILanguage(
  303. LPVARIANT pvResult
  304. )
  305. {
  306. if (pvResult != NULL) {
  307. VariantInit(pvResult);
  308. V_VT(pvResult) = VT_I4;
  309. V_I4(pvResult) = GetUserDefaultUILanguage();
  310. }
  311. return S_OK;
  312. }
  313. HRESULT
  314. CAPI::get_ComputerName(
  315. LPVARIANT pvResult
  316. )
  317. {
  318. HRESULT hr = S_OK;
  319. WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  320. DWORD cch = sizeof(szComputerName) / sizeof(WCHAR);
  321. if (! ::GetComputerName( szComputerName, &cch))
  322. {
  323. DWORD dwErr = ::GetLastError();
  324. TRACE1(L"GetComputerName failed (0x%08X)", dwErr);
  325. szComputerName[0] = '\0';
  326. hr = HRESULT_FROM_WIN32(dwErr);
  327. }
  328. if (SUCCEEDED(hr))
  329. {
  330. V_VT(pvResult) = VT_BSTR;
  331. V_BSTR(pvResult) = SysAllocString(szComputerName);
  332. if (NULL == V_BSTR(pvResult))
  333. {
  334. hr = E_OUTOFMEMORY;
  335. }
  336. }
  337. return hr;
  338. }
  339. //////////////////////////////////////////////////////////////////////////////
  340. //
  341. // set_ComputerName
  342. //
  343. // Sets the computer name to a given string. SetComputerNameEx adjusts most
  344. // of the registry entries. However, the following need to be changed
  345. // directly because WinLogon changes them prior to running msoobe.exe:
  346. // * System\CurrentControlSet\Control\ComputerName\\ActiveComputerName
  347. // \ComputerName
  348. // * HKLM\System\CurrentControlSet\Services\Tcpip\Parameters
  349. // \Hostname
  350. // * HKEY_CURRENT_USER\VolatileEnvironment
  351. // \LOGONSERVER
  352. //
  353. // The ActiveComputerName key contains the name currently used by the computer
  354. // and returned by GetComputerName.
  355. //
  356. // The Tcpip\Parameters\Hostname value contains the non-volatile hostname
  357. // returned by ??.
  358. //
  359. // The LOGONSERVER value is used as the value of the LOGONSERVER environment
  360. // variable.
  361. //
  362. HRESULT
  363. CAPI::set_ComputerName(
  364. BSTR bstrComputerName
  365. )
  366. {
  367. HRESULT hr = S_OK;
  368. LRESULT lResult;
  369. HKEY hkey = NULL;
  370. MYASSERT(NULL != bstrComputerName);
  371. if ( NULL == bstrComputerName
  372. || MAX_COMPUTERNAME_LENGTH < lstrlen((LPCWSTR)bstrComputerName)
  373. )
  374. {
  375. return E_INVALIDARG;
  376. }
  377. // Trim spaces before we use the name
  378. StrTrim(bstrComputerName, TEXT(" "));
  379. // SetComputerNameEx validates the name,sets
  380. // HKLM\System\CurrentControlSet\Control\ComputerName\ComputerName, and
  381. // changes the appropriate network registry entries.
  382. if (! ::SetComputerNameEx(ComputerNamePhysicalDnsHostname,
  383. (LPCWSTR)bstrComputerName)
  384. )
  385. {
  386. DWORD dwErr = ::GetLastError();
  387. TRACE2(L"SetComputerNameEx(%s) failed (0x%08X)",
  388. (LPCWSTR)bstrComputerName, dwErr
  389. );
  390. return HRESULT_FROM_WIN32(dwErr);
  391. }
  392. // The following keys must be set explicitly because SetComputerNameEx does
  393. // not set them.
  394. //
  395. // HKLM\System\CurrentControlSet\Control\ComputerName\ActiveComputerName
  396. // must be set because it is the key that is used to determine the
  397. // current computer name.
  398. //
  399. lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  400. REGSTR_PATH_ACTIVECOMPUTERNAME,
  401. 0,
  402. KEY_WRITE,
  403. &hkey
  404. );
  405. if (ERROR_SUCCESS == lResult)
  406. {
  407. lResult = RegSetValueEx(hkey,
  408. REGSTR_VAL_COMPUTERNAME,
  409. 0,
  410. REG_SZ,
  411. (LPBYTE)bstrComputerName,
  412. BYTES_REQUIRED_BY_SZ(bstrComputerName)
  413. );
  414. RegCloseKey(hkey);
  415. hkey = NULL;
  416. }
  417. if (ERROR_SUCCESS != lResult)
  418. {
  419. TRACE3(L"Failed to set %s to %s (0x%08X)\n",
  420. REGSTR_VAL_COMPUTERNAME,
  421. (LPCWSTR)bstrComputerName,
  422. lResult
  423. );
  424. }
  425. // HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\Hostname
  426. // contains the volatile hostname (ie this is the entry that is changed on
  427. // the fly) Winlogon has already updated this entry during boot so we
  428. // must update it ourselves.
  429. //
  430. lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  431. REGSTR_PATH_TCPIP_PARAMETERS,
  432. 0,
  433. KEY_WRITE,
  434. &hkey
  435. );
  436. if (ERROR_SUCCESS == lResult)
  437. {
  438. lResult = RegSetValueEx(hkey,
  439. REGSTR_VALUE_HOSTNAME,
  440. 0,
  441. REG_SZ,
  442. (LPBYTE)bstrComputerName,
  443. BYTES_REQUIRED_BY_SZ(bstrComputerName)
  444. );
  445. RegCloseKey(hkey);
  446. hkey = NULL;
  447. }
  448. if (ERROR_SUCCESS != lResult)
  449. {
  450. TRACE3(L"Failed to set %s to %s (0x%08X)\n",
  451. REGSTR_VALUE_HOSTNAME,
  452. (LPCWSTR)bstrComputerName,
  453. lResult
  454. );
  455. }
  456. // Key should have been closed already.
  457. //
  458. MYASSERT(NULL == hkey);
  459. if (!SetAccountsDomainSid(0, bstrComputerName))
  460. {
  461. TRACE(L"SetAccountsDomainSid failed\n\r");
  462. }
  463. return S_OK;
  464. }
  465. HRESULT CAPI::ValidateComputername(BSTR bstrComputername)
  466. {
  467. HRESULT hr = E_FAIL;
  468. UINT Length,u;
  469. if (!bstrComputername)
  470. return hr;
  471. // Trim spaces before validation.
  472. StrTrim(bstrComputername, TEXT(" "));
  473. Length = lstrlen(bstrComputername);
  474. if ((Length == 0) || (Length > MAX_COMPUTERNAME_LENGTH))
  475. return hr;
  476. u = 0;
  477. hr = S_OK;
  478. while ((hr == S_OK) && (u < Length))
  479. {
  480. //
  481. // Control chars are invalid, as are characters in the illegal chars list.
  482. //
  483. if((bstrComputername[u] < L' ') || wcschr(IllegalNetNameChars,bstrComputername[u]))
  484. {
  485. hr = E_FAIL;
  486. }
  487. u++;
  488. }
  489. return hr;
  490. }
  491. STDMETHODIMP CAPI::OEMComputername()
  492. {
  493. WCHAR szIniFile[MAX_PATH] = L"";
  494. WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  495. HRESULT hr = E_FAIL;
  496. // Get the name from the INI file.
  497. if (GetCanonicalizedPath(szIniFile, INI_SETTINGS_FILENAME))
  498. {
  499. if (GetPrivateProfileString(USER_INFO_KEYNAME,
  500. L"Computername",
  501. L"\0",
  502. szComputerName,
  503. MAX_CHARS_IN_BUFFER(szComputerName),
  504. szIniFile) != 0)
  505. {
  506. if (SUCCEEDED(hr = ValidateComputername(szComputerName)))
  507. {
  508. hr = set_ComputerName(szComputerName);
  509. if (hr != S_OK)
  510. {
  511. TRACE2(TEXT("OEMComputername: set_ComputerName on %s failed with %lx"), szComputerName, hr);
  512. }
  513. }
  514. else
  515. {
  516. TRACE1(TEXT("OEMComputername: Computername %s is invalid"), szComputerName);
  517. }
  518. }
  519. }
  520. return hr;
  521. }
  522. STDMETHODIMP CAPI::FormatMessage( LPVARIANT pvResult, // message buffer
  523. BSTR bstrSource, // message source
  524. int cArgs, // number of inserts
  525. VARIANTARG *rgArgs // array of message inserts
  526. )
  527. {
  528. DWORD dwErr;
  529. BSTR* rgbstr = NULL;
  530. LPTSTR str = NULL;
  531. if (pvResult == NULL)
  532. {
  533. return S_OK;
  534. }
  535. VariantInit(pvResult);
  536. if (bstrSource == NULL)
  537. {
  538. return E_FAIL;
  539. }
  540. if (cArgs > 0 && rgArgs != NULL)
  541. {
  542. rgbstr = (BSTR*)LocalAlloc(LPTR, cArgs * sizeof(BSTR));
  543. if (rgbstr == NULL)
  544. {
  545. return E_FAIL;
  546. }
  547. // Since IDispatch::Invoke gets argument right to left, and
  548. // since we need to pass argument to FormatMessage left to right,
  549. // we need to reverse the order of argument while copying.
  550. for (int i = 0; i < cArgs; i++)
  551. {
  552. rgbstr[cArgs - 1 - i] = V_BSTR(&rgArgs[i]);
  553. }
  554. }
  555. dwErr = ::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  556. bstrSource,
  557. 0,
  558. 0,
  559. (LPTSTR)&str,
  560. MAX_PATH,
  561. (va_list *)rgbstr
  562. );
  563. if (dwErr != 0)
  564. {
  565. V_VT(pvResult) = VT_BSTR;
  566. V_BSTR(pvResult) = SysAllocString(str);
  567. }
  568. if (str != NULL)
  569. {
  570. LocalFree(str);
  571. }
  572. if (rgbstr != NULL)
  573. {
  574. LocalFree(rgbstr);
  575. }
  576. return (dwErr != 0 ? S_OK : E_FAIL);
  577. }
  578. STDMETHODIMP CAPI::set_ComputerDesc(BSTR bstrComputerDesc)
  579. {
  580. WCHAR szKeyName[] = REG_KEY_OOBE_TEMP;
  581. HKEY hKey;
  582. if ( bstrComputerDesc )
  583. {
  584. if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS )
  585. {
  586. RegSetValueEx(hKey, REG_VAL_COMPUTERDESCRIPTION, 0, REG_SZ, (LPBYTE) bstrComputerDesc, BYTES_REQUIRED_BY_SZ(bstrComputerDesc));
  587. RegFlushKey(hKey);
  588. RegCloseKey(hKey);
  589. }
  590. }
  591. return S_OK;
  592. }
  593. /////////////////////////////////////////////////////////////
  594. /////////////////////////////////////////////////////////////
  595. /////////////////////////////////////////////////////////////
  596. /////// IUnknown implementation
  597. ///////
  598. ///////
  599. /////////////////////////////////////////////////////////////
  600. // CAPI::QueryInterface
  601. STDMETHODIMP CAPI::QueryInterface(REFIID riid, LPVOID* ppvObj)
  602. {
  603. // must set out pointer parameters to NULL
  604. *ppvObj = NULL;
  605. if ( riid == IID_IUnknown)
  606. {
  607. AddRef();
  608. *ppvObj = (IUnknown*)this;
  609. return ResultFromScode(S_OK);
  610. }
  611. if (riid == IID_IDispatch)
  612. {
  613. AddRef();
  614. *ppvObj = (IDispatch*)this;
  615. return ResultFromScode(S_OK);
  616. }
  617. // Not a supported interface
  618. return ResultFromScode(E_NOINTERFACE);
  619. }
  620. /////////////////////////////////////////////////////////////
  621. // CAPI::AddRef
  622. STDMETHODIMP_(ULONG) CAPI::AddRef()
  623. {
  624. return ++m_cRef;
  625. }
  626. /////////////////////////////////////////////////////////////
  627. // CAPI::Release
  628. STDMETHODIMP_(ULONG) CAPI::Release()
  629. {
  630. return --m_cRef;
  631. }
  632. /////////////////////////////////////////////////////////////
  633. /////////////////////////////////////////////////////////////
  634. /////////////////////////////////////////////////////////////
  635. /////// IDispatch implementation
  636. ///////
  637. ///////
  638. /////////////////////////////////////////////////////////////
  639. // CAPI::GetTypeInfo
  640. STDMETHODIMP CAPI::GetTypeInfo(UINT, LCID, ITypeInfo**)
  641. {
  642. return E_NOTIMPL;
  643. }
  644. /////////////////////////////////////////////////////////////
  645. // CAPI::GetTypeInfoCount
  646. STDMETHODIMP CAPI::GetTypeInfoCount(UINT* pcInfo)
  647. {
  648. return E_NOTIMPL;
  649. }
  650. /////////////////////////////////////////////////////////////
  651. // CAPI::GetIDsOfNames
  652. STDMETHODIMP CAPI::GetIDsOfNames(REFIID riid,
  653. OLECHAR** rgszNames,
  654. UINT cNames,
  655. LCID lcid,
  656. DISPID* rgDispId)
  657. {
  658. HRESULT hr = DISP_E_UNKNOWNNAME;
  659. rgDispId[0] = DISPID_UNKNOWN;
  660. for (int iX = 0; iX < sizeof(APIExternalInterface)/sizeof(DISPATCHLIST); iX ++)
  661. {
  662. if(lstrcmp(APIExternalInterface[iX].szName, rgszNames[0]) == 0)
  663. {
  664. rgDispId[0] = APIExternalInterface[iX].dwDispID;
  665. hr = NOERROR;
  666. break;
  667. }
  668. }
  669. // Set the disid's for the parameters
  670. if (cNames > 1)
  671. {
  672. // Set a DISPID for function parameters
  673. for (UINT i = 1; i < cNames ; i++)
  674. rgDispId[i] = DISPID_UNKNOWN;
  675. }
  676. return hr;
  677. }
  678. /////////////////////////////////////////////////////////////
  679. // CAPI::Invoke
  680. HRESULT CAPI::Invoke
  681. (
  682. DISPID dispidMember,
  683. REFIID riid,
  684. LCID lcid,
  685. WORD wFlags,
  686. DISPPARAMS* pdispparams,
  687. VARIANT* pvarResult,
  688. EXCEPINFO* pexcepinfo,
  689. UINT* puArgErr
  690. )
  691. {
  692. // Assume everything is hunky-dory. Only return an HRESULT other than S_OK
  693. // in case of a catastrophic failure. Result codes should be returned to
  694. // script via pvarResult.
  695. //
  696. HRESULT hr = S_OK;
  697. switch(dispidMember)
  698. {
  699. case DISPID_API_SAVEFILE:
  700. {
  701. TRACE(L"DISPID_API_SAVEFILE\n");
  702. if (NULL != pdispparams)
  703. {
  704. if (2 < pdispparams->cArgs)
  705. SaveFile(V_BSTR(&pdispparams->rgvarg[2]), V_BSTR(&pdispparams->rgvarg[1]), V_BSTR(&pdispparams->rgvarg[0]));
  706. else
  707. if (1 < pdispparams->cArgs)
  708. SaveFile(V_BSTR(&pdispparams->rgvarg[1]), V_BSTR(&pdispparams->rgvarg[0]));
  709. }
  710. break;
  711. }
  712. // bugbug If VariantChangeType returns DISP_E_TYPEMISMATCH, the implementor would set *puArgErr to 0 (indicating the argument in error) and return DISP_E_TYPEMISMATCH from IDispatch::Invoke.
  713. case DISPID_API_SAVEFILEBYCSIDL:
  714. {
  715. TRACE(L"DISPID_API_SAVEFILEBYCSIDL\n");
  716. if (NULL != pdispparams)
  717. {
  718. VARIANTARG vaConverted;
  719. VariantInit(&vaConverted);
  720. if (2 < pdispparams->cArgs)
  721. {
  722. hr = VariantChangeType(&vaConverted, &pdispparams->rgvarg[2], 0, VT_I4);
  723. if (SUCCEEDED(hr))
  724. hr = SaveFile(V_I4(&vaConverted), V_BSTR(&pdispparams->rgvarg[1]), V_BSTR(&pdispparams->rgvarg[0]));
  725. }
  726. else
  727. if (1 < pdispparams->cArgs)
  728. {
  729. hr = VariantChangeType(&vaConverted, &pdispparams->rgvarg[1], 0, VT_I4);
  730. if (SUCCEEDED(hr))
  731. hr = SaveFile(V_I4(&vaConverted), V_BSTR(&pdispparams->rgvarg[0]));
  732. }
  733. }
  734. hr = S_OK; // don't cause script engine to throw exception
  735. break;
  736. }
  737. case DISPID_API_GET_INIKEY:
  738. {
  739. TRACE(L"DISPID_API_GET_INIKEY\n");
  740. if (pdispparams != NULL && pvarResult != NULL)
  741. {
  742. if (pdispparams->cArgs > 2)
  743. {
  744. get_INIKey(
  745. V_BSTR(&pdispparams->rgvarg[2]),
  746. V_BSTR(&pdispparams->rgvarg[1]),
  747. V_BSTR(&pdispparams->rgvarg[0]),
  748. pvarResult
  749. );
  750. }
  751. else if (pdispparams->cArgs == 2)
  752. {
  753. BSTR bstrFile = SysAllocStringLen(NULL, MAX_PATH);
  754. if (bstrFile)
  755. {
  756. if (GetCanonicalizedPath(bstrFile, INI_SETTINGS_FILENAME))
  757. {
  758. get_INIKey(
  759. bstrFile,
  760. V_BSTR(&pdispparams->rgvarg[1]),
  761. V_BSTR(&pdispparams->rgvarg[0]),
  762. pvarResult
  763. );
  764. }
  765. SysFreeString(bstrFile);
  766. }
  767. }
  768. }
  769. break;
  770. }
  771. case DISPID_API_SET_REGVALUE:
  772. TRACE(L"DISPID_API_SET_REGVALUE: ");
  773. if (NULL != pdispparams && 3 < pdispparams->cArgs)
  774. {
  775. BSTR bstrSubKey = NULL;
  776. BSTR bstrValueName = NULL;
  777. BOOL bValid = TRUE;
  778. switch (V_VT(&pdispparams->rgvarg[1]))
  779. {
  780. case VT_NULL:
  781. bstrValueName = NULL;
  782. break;
  783. case VT_BSTR:
  784. bstrValueName = V_BSTR(&pdispparams->rgvarg[1]);
  785. break;
  786. default:
  787. bValid = FALSE;
  788. }
  789. bstrSubKey = V_BSTR(&pdispparams->rgvarg[2]);
  790. if (bValid)
  791. {
  792. TRACE2(L"%s, %s\n", bstrSubKey, bstrValueName);
  793. set_RegValue((HKEY) (DWORD_PTR) V_R8(&pdispparams->rgvarg[3]),
  794. bstrSubKey,
  795. bstrValueName,
  796. &pdispparams->rgvarg[0]);
  797. }
  798. }
  799. break;
  800. case DISPID_API_GET_REGVALUE:
  801. TRACE(L"DISPID_API_GET_REGVALUE: ");
  802. if (NULL != pdispparams && NULL != pvarResult && 2 < pdispparams->cArgs)
  803. {
  804. BSTR bstrSubKey = NULL;
  805. BSTR bstrValueName = NULL;
  806. BOOL bValid = TRUE;
  807. switch (V_VT(&pdispparams->rgvarg[0]))
  808. {
  809. case VT_NULL:
  810. bstrValueName = NULL;
  811. break;
  812. case VT_BSTR:
  813. bstrValueName = V_BSTR(&pdispparams->rgvarg[0]);
  814. break;
  815. default:
  816. bValid = FALSE;
  817. }
  818. bstrSubKey = V_BSTR(&pdispparams->rgvarg[1]);
  819. if (bValid)
  820. {
  821. TRACE2(L"%s: %s", bstrSubKey, bstrValueName);
  822. get_RegValue((HKEY) (DWORD_PTR) V_R8(&pdispparams->rgvarg[2]),
  823. bstrSubKey,
  824. bstrValueName,
  825. pvarResult);
  826. }
  827. }
  828. break;
  829. case DISPID_API_DELETEREGVALUE:
  830. TRACE(L"DISPID_API_DELETEREGVALUE\n");
  831. if (NULL != pdispparams && 1 < pdispparams->cArgs)
  832. DeleteRegValue((HKEY) (DWORD_PTR) V_R8(&pdispparams->rgvarg[2]),
  833. V_BSTR(&pdispparams->rgvarg[1]),
  834. V_BSTR(&pdispparams->rgvarg[0]));
  835. break;
  836. case DISPID_API_DELETEREGKEY:
  837. TRACE(L"DISPID_API_DELETEREGKEY\n");
  838. if (NULL != pdispparams && 1 < pdispparams->cArgs)
  839. DeleteRegKey((HKEY) (DWORD_PTR) V_R8(&pdispparams->rgvarg[1]),
  840. V_BSTR(&pdispparams->rgvarg[0]));
  841. break;
  842. case DISPID_API_GET_SYSTEMDIRECTORY:
  843. TRACE(L"DISPID_API_GET_SYSTEMDIRECTORY\n");
  844. if (NULL != pvarResult)
  845. get_SystemDirectory(pvarResult);
  846. break;
  847. case DISPID_API_GET_CSIDLDIRECTORY:
  848. TRACE(L"DISPID_API_GET_CSIDLDIRECTORY\n");
  849. if (NULL != pdispparams && 0 < pdispparams->cArgs && pvarResult != NULL)
  850. get_CSIDLDirectory(V_I4(&pdispparams->rgvarg[0]), pvarResult);
  851. break;
  852. case DISPID_API_LOADFILE:
  853. TRACE(L"DISPID_API_LOADFILE\n");
  854. if (NULL != pdispparams && 0 < pdispparams->cArgs && pvarResult != NULL)
  855. {
  856. LoadFile(V_BSTR(&pdispparams->rgvarg[0]), pvarResult);
  857. }
  858. break;
  859. case DISPID_API_GET_USERDEFAULTLCID:
  860. TRACE(L"DISPID_API_GET_USERDEFAULTLCID\n");
  861. if (pvarResult != NULL)
  862. get_UserDefaultLCID(pvarResult);
  863. break;
  864. case DISPID_API_GET_COMPUTERNAME:
  865. TRACE(L"DISPID_API_GET_COMPUTERNAME\n");
  866. if (NULL != pvarResult)
  867. {
  868. get_ComputerName(pvarResult);
  869. }
  870. break;
  871. case DISPID_API_SET_COMPUTERNAME:
  872. TRACE(L"DISPID_API_SET_COMPUTERNAME\n");
  873. if (pdispparams && &(pdispparams[0].rgvarg[0]))
  874. {
  875. hr = set_ComputerName(pdispparams[0].rgvarg[0].bstrVal);
  876. if (pvarResult)
  877. {
  878. VariantInit(pvarResult);
  879. V_VT(pvarResult) = VT_BOOL;
  880. V_BOOL(pvarResult) = Bool2VarBool(SUCCEEDED(hr));
  881. }
  882. }
  883. hr = S_OK; // don't cause an exception in the scripting engine.
  884. break;
  885. case DISPID_API_FLUSHREGKEY:
  886. TRACE(L"DISPID_API_FLUSHREGKEY\n");
  887. if (pdispparams && &(pdispparams[0].rgvarg[0]))
  888. {
  889. FlushRegKey((HKEY) (DWORD_PTR) V_R8(&pdispparams->rgvarg[0]));
  890. }
  891. break;
  892. case DISPID_API_VALIDATECOMPUTERNAME:
  893. TRACE(L"DISPID_API_VALIDATECOMPUTERNAME\n");
  894. if (pdispparams && (0 < pdispparams->cArgs))
  895. {
  896. hr = ValidateComputername(pdispparams[0].rgvarg[0].bstrVal);
  897. if (pvarResult)
  898. {
  899. VariantInit(pvarResult);
  900. V_VT(pvarResult) = VT_BOOL;
  901. V_BOOL(pvarResult) = Bool2VarBool(SUCCEEDED(hr));
  902. }
  903. }
  904. hr = S_OK; // don't cause an exception in the scripting engine.
  905. break;
  906. case DISPID_API_OEMCOMPUTERNAME:
  907. TRACE(L"DISPID_API_OEMCOMPUTERNAME");
  908. hr = OEMComputername();
  909. if (pvarResult)
  910. {
  911. VariantInit(pvarResult);
  912. V_VT(pvarResult) = VT_BOOL;
  913. V_BOOL(pvarResult) = Bool2VarBool(SUCCEEDED(hr));
  914. }
  915. hr = S_OK; // don't cause an exception in the scripting engine.
  916. break;
  917. case DISPID_API_FORMATMESSAGE:
  918. TRACE(L"DISPID_API_FORMATMESSAGE");
  919. if (pdispparams != NULL)
  920. {
  921. int cArgs = pdispparams->cArgs - 1;
  922. if (cArgs >= 0 && V_VT(&pdispparams->rgvarg[cArgs]) == VT_BSTR)
  923. {
  924. FormatMessage(pvarResult, V_BSTR(&pdispparams->rgvarg[cArgs]), cArgs, &pdispparams->rgvarg[0]);
  925. }
  926. }
  927. break;
  928. case DISPID_API_SET_COMPUTERDESC:
  929. TRACE(L"DISPID_API_SET_COMPUTERDESC\n");
  930. if (pdispparams && &(pdispparams[0].rgvarg[0]))
  931. {
  932. hr = set_ComputerDesc(pdispparams[0].rgvarg[0].bstrVal);
  933. if (pvarResult)
  934. {
  935. VariantInit(pvarResult);
  936. V_VT(pvarResult) = VT_BOOL;
  937. V_BOOL(pvarResult) = Bool2VarBool(SUCCEEDED(hr));
  938. }
  939. }
  940. hr = S_OK; // don't cause an exception in the scripting engine.
  941. break;
  942. case DISPID_API_GET_USERDEFAULTUILANGUAGE:
  943. TRACE(L"DISPID_API_GET_USERDEFAULTUILANGUAGE");
  944. get_UserDefaultUILanguage(pvarResult);
  945. break;
  946. default:
  947. {
  948. hr = DISP_E_MEMBERNOTFOUND;
  949. break;
  950. }
  951. }
  952. return hr;
  953. }