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.

789 lines
21 KiB

  1. //
  2. // CTBGlobal.cpp
  3. //
  4. // Contains the methods and properties for the global object used in TBScript.
  5. // In scripting, you do not need to references these prefixed by "Global.",
  6. // you can simply use them like any other global method or propery.
  7. //
  8. // Copyright (C) 2001 Microsoft Corporation
  9. //
  10. // Author: a-devjen (Devin Jenson)
  11. //
  12. #include "CTBGlobal.h"
  13. #include <time.h>
  14. #include <crtdbg.h>
  15. #include <shellapi.h>
  16. #define CTBOBJECT CTBGlobal
  17. #include "virtualdefs.h"
  18. // This is a workaround for a Microsoft header file bug
  19. #ifndef INVALID_SET_FILE_POINTER
  20. #define INVALID_SET_FILE_POINTER ((DWORD)-1)
  21. #endif // INVALID_SET_FILE_POINTER
  22. // This is the function format for each property
  23. #define PROPCODE(Name, Value) \
  24. STDMETHODIMP CTBGlobal::get_##Name(DWORD *Result) \
  25. { \
  26. *Result = Value; \
  27. return NOERROR; \
  28. }
  29. PROPCODE(TSFLAG_COMPRESSION, 0x01);
  30. PROPCODE(TSFLAG_BITMAPCACHE, 0x02);
  31. PROPCODE(TSFLAG_FULLSCREEN, 0x04);
  32. PROPCODE(VK_CANCEL, 0x03); // Control-break processing
  33. PROPCODE(VK_BACK, 0x08); // BACKSPACE key
  34. PROPCODE(VK_TAB, 0x09); // TAB key
  35. PROPCODE(VK_CLEAR, 0x0C); // CLEAR key
  36. PROPCODE(VK_RETURN, 0x0D); // ENTER key
  37. PROPCODE(VK_ENTER, 0x0D); // ENTER key (backward compatibility ONLY)
  38. PROPCODE(VK_SHIFT, 0x10); // SHIFT key
  39. PROPCODE(VK_CONTROL, 0x11); // CTRL key
  40. PROPCODE(VK_MENU, 0x12); // ALT key
  41. PROPCODE(VK_PAUSE, 0x13); // PAUSE key
  42. PROPCODE(VK_ESCAPE, 0x1B); // ESC key
  43. PROPCODE(VK_SPACE, 0x20); // SPACEBAR
  44. PROPCODE(VK_PRIOR, 0x21); // PAGE UP key
  45. PROPCODE(VK_NEXT, 0x22); // PAGE DOWN key
  46. PROPCODE(VK_END, 0x23); // END key
  47. PROPCODE(VK_HOME, 0x24); // HOME key
  48. PROPCODE(VK_LEFT, 0x25); // LEFT ARROW key
  49. PROPCODE(VK_UP, 0x26); // UP ARROW key
  50. PROPCODE(VK_RIGHT, 0x27); // RIGHT ARROW key
  51. PROPCODE(VK_DOWN, 0x28); // DOWN ARROW key
  52. PROPCODE(VK_SNAPSHOT, 0x2C); // PRINT SCREEN key
  53. PROPCODE(VK_INSERT, 0x2D); // INS key
  54. PROPCODE(VK_DELETE, 0x2E); // DEL key
  55. PROPCODE(VK_0, 0x30); // 0 key
  56. PROPCODE(VK_1, 0x31); // 1 key
  57. PROPCODE(VK_2, 0x32); // 2 key
  58. PROPCODE(VK_3, 0x33); // 3 key
  59. PROPCODE(VK_4, 0x34); // 4 key
  60. PROPCODE(VK_5, 0x35); // 5 key
  61. PROPCODE(VK_6, 0x36); // 6 key
  62. PROPCODE(VK_7, 0x37); // 7 key
  63. PROPCODE(VK_8, 0x38); // 8 key
  64. PROPCODE(VK_9, 0x39); // 9 key
  65. PROPCODE(VK_A, 0x41); // A key
  66. PROPCODE(VK_B, 0x42); // B key
  67. PROPCODE(VK_C, 0x43); // C key
  68. PROPCODE(VK_D, 0x44); // D key
  69. PROPCODE(VK_E, 0x45); // E key
  70. PROPCODE(VK_F, 0x46); // F key
  71. PROPCODE(VK_G, 0x47); // G key
  72. PROPCODE(VK_H, 0x48); // H key
  73. PROPCODE(VK_I, 0x49); // I key
  74. PROPCODE(VK_J, 0x4A); // J key
  75. PROPCODE(VK_K, 0x4B); // K key
  76. PROPCODE(VK_L, 0x4C); // L key
  77. PROPCODE(VK_M, 0x4D); // M key
  78. PROPCODE(VK_N, 0x4E); // N key
  79. PROPCODE(VK_O, 0x4F); // O key
  80. PROPCODE(VK_P, 0x50); // P key
  81. PROPCODE(VK_Q, 0x51); // Q key
  82. PROPCODE(VK_R, 0x52); // R key
  83. PROPCODE(VK_S, 0x53); // S key
  84. PROPCODE(VK_T, 0x54); // T key
  85. PROPCODE(VK_U, 0x55); // U key
  86. PROPCODE(VK_V, 0x56); // V key
  87. PROPCODE(VK_W, 0x57); // W key
  88. PROPCODE(VK_X, 0x58); // X key
  89. PROPCODE(VK_Y, 0x59); // Y key
  90. PROPCODE(VK_Z, 0x5A); // Z key
  91. PROPCODE(VK_LWIN, 0x5B); // Left Windows key
  92. PROPCODE(VK_RWIN, 0x5C); // Right Windows key
  93. PROPCODE(VK_APPS, 0x5D); // Applications key
  94. PROPCODE(VK_NUMPAD0, 0x60); // Numeric keypad 0 key
  95. PROPCODE(VK_NUMPAD1, 0x61); // Numeric keypad 1 key
  96. PROPCODE(VK_NUMPAD2, 0x62); // Numeric keypad 2 key
  97. PROPCODE(VK_NUMPAD3, 0x63); // Numeric keypad 3 key
  98. PROPCODE(VK_NUMPAD4, 0x64); // Numeric keypad 4 key
  99. PROPCODE(VK_NUMPAD5, 0x65); // Numeric keypad 5 key
  100. PROPCODE(VK_NUMPAD6, 0x66); // Numeric keypad 6 key
  101. PROPCODE(VK_NUMPAD7, 0x67); // Numeric keypad 7 key
  102. PROPCODE(VK_NUMPAD8, 0x68); // Numeric keypad 8 key
  103. PROPCODE(VK_NUMPAD9, 0x69); // Numeric keypad 9 key
  104. PROPCODE(VK_MULTIPLY, 0x6A); // Multiply key
  105. PROPCODE(VK_ADD, 0x6B); // Add key
  106. PROPCODE(VK_SEPARATOR, 0x6C); // Separator key
  107. PROPCODE(VK_SUBTRACT, 0x6D); // Subtract key
  108. PROPCODE(VK_DECIMAL, 0x6E); // Decimal key
  109. PROPCODE(VK_DIVIDE, 0x6F); // Divide key
  110. PROPCODE(VK_F1, 0x70); // F1 key
  111. PROPCODE(VK_F2, 0x71); // F2 key
  112. PROPCODE(VK_F3, 0x72); // F3 key
  113. PROPCODE(VK_F4, 0x73); // F4 key
  114. PROPCODE(VK_F5, 0x74); // F5 key
  115. PROPCODE(VK_F6, 0x75); // F6 key
  116. PROPCODE(VK_F7, 0x76); // F7 key
  117. PROPCODE(VK_F8, 0x77); // F8 key
  118. PROPCODE(VK_F9, 0x78); // F9 key
  119. PROPCODE(VK_F10, 0x79); // F10 key
  120. PROPCODE(VK_F11, 0x7A); // F11 key
  121. PROPCODE(VK_F12, 0x7B); // F12 key
  122. PROPCODE(VK_F13, 0x7C); // F13 key
  123. PROPCODE(VK_F14, 0x7D); // F14 key
  124. PROPCODE(VK_F15, 0x7E); // F15 key
  125. PROPCODE(VK_F16, 0x7F); // F16 key
  126. PROPCODE(VK_F17, 0x80); // F17 key
  127. PROPCODE(VK_F18, 0x81); // F18 key
  128. PROPCODE(VK_F19, 0x82); // F19 key
  129. PROPCODE(VK_F20, 0x83); // F20 key
  130. PROPCODE(VK_F21, 0x84); // F21 key
  131. PROPCODE(VK_F22, 0x85); // F22 key
  132. PROPCODE(VK_F23, 0x86); // F23 key
  133. PROPCODE(VK_F24, 0x87); // F24 key
  134. // CTBGlobal::CTBGlobal
  135. //
  136. // The constructor. Loads the TypeInfo for interface.
  137. //
  138. // No return value.
  139. CTBGlobal::CTBGlobal(void)
  140. {
  141. // Initialize base object stuff
  142. Init(IID_ITBGlobal);
  143. ScriptEngine = NULL;
  144. fnPrintMessage = NULL;
  145. TBShell = NULL;
  146. // Get the performance frequency (used if the
  147. // script called GetInterval()
  148. if (QueryPerformanceFrequency(&SysPerfFrequency) == FALSE)
  149. SysPerfFrequency.QuadPart = 0;
  150. }
  151. // CTBGlobal::~CTBGlobal
  152. //
  153. // The destructor.
  154. //
  155. // No return value.
  156. CTBGlobal::~CTBGlobal(void)
  157. {
  158. // Release the shell if we have a handle
  159. if (TBShell != NULL)
  160. TBShell->Release();
  161. TBShell = NULL;
  162. UnInit();
  163. }
  164. // Sets the script engine handle needed for LoadScript()
  165. void CTBGlobal::SetScriptEngine(HANDLE ScriptEngineHandle)
  166. {
  167. ScriptEngine = ScriptEngineHandle;
  168. }
  169. // Sets a pointer to the callback routine needed for DebugMessage()
  170. void CTBGlobal::SetPrintMessage(PFNPRINTMESSAGE PrintMessage)
  171. {
  172. fnPrintMessage = PrintMessage;
  173. }
  174. // This is to make it possible to globally access the shell
  175. void CTBGlobal::SetShellObjPtr(CTBShell *TBShellPtr)
  176. {
  177. // Make sure we arn't setting a shell we already have
  178. if (TBShellPtr == TBShell)
  179. return;
  180. // If we already have a handle, release the current one
  181. if (TBShell != NULL)
  182. TBShell->Release();
  183. // Set the new one
  184. TBShell = TBShellPtr;
  185. // Add a reference to the new one
  186. if (TBShell != NULL)
  187. TBShell->AddRef();
  188. }
  189. // CTBGlobal::WinExecuteEx
  190. //
  191. // Executes the specified command into a new process, and
  192. // optionally return immediately or wait. This function is
  193. // used as a helper function only.
  194. //
  195. // If WaitForProcess is FALSE, Result will contain TRUE or FALSE.
  196. // If WaitForProcess is TRUE, Result will contain the ExitCode.
  197. //
  198. // Returns S_OK on success, or E_FAIL on failure.
  199. HRESULT CTBGlobal::WinExecuteEx(BSTR Command, BOOL WaitForProcess, DWORD *Result)
  200. {
  201. PROCESS_INFORMATION ProcessInfo = { 0 };
  202. STARTUPINFOW StartupInfo = { 0 };
  203. OLECHAR CommandEval[MAX_PATH] = { 0 };
  204. // Evaluate environment variables first of all
  205. if (ExpandEnvironmentStringsW(Command, CommandEval,
  206. SIZEOF_ARRAY(CommandEval)) == 0) {
  207. if (WaitForProcess == TRUE)
  208. *Result = -1;
  209. else
  210. *Result = FALSE;
  211. // Cause an exception
  212. return E_FAIL;
  213. }
  214. // Initialize the structure size
  215. StartupInfo.cb = sizeof(STARTUPINFO);
  216. // Begin the process
  217. if (CreateProcessW(NULL, CommandEval, NULL, NULL, FALSE,
  218. NORMAL_PRIORITY_CLASS, NULL, NULL, &StartupInfo,
  219. &ProcessInfo) == FALSE) {
  220. // Process didn't execute, could be just an invalid name
  221. if (WaitForProcess == TRUE)
  222. *Result = -1;
  223. else
  224. *Result = FALSE;
  225. // Don't cause an exception
  226. return S_OK;
  227. }
  228. // Wait for the process to complete (if specified)
  229. if (WaitForProcess == TRUE)
  230. WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
  231. // Get the result/exit code
  232. if (WaitForProcess == TRUE)
  233. *Result = GetExitCodeProcess(ProcessInfo.hProcess, Result);
  234. else
  235. *Result = TRUE;
  236. // Close process handles
  237. CloseHandle(ProcessInfo.hThread);
  238. CloseHandle(ProcessInfo.hProcess);
  239. return S_OK;
  240. }
  241. //
  242. //
  243. // Begin Methods used within script
  244. //
  245. //
  246. // CTBGlobal::DebugAlert
  247. //
  248. // Opens a Win32 MessageBox containing the specified text.
  249. // Used for debugging purposes.
  250. //
  251. // Returns S_OK.
  252. STDMETHODIMP CTBGlobal::DebugAlert(BSTR Text)
  253. {
  254. if (Text != NULL)
  255. MessageBoxW(0, Text, L"Alert", MB_SETFOREGROUND);
  256. return S_OK;
  257. }
  258. // CTBGlobal::DebugAlert
  259. //
  260. // Opens a Win32 MessageBox containing the specified text.
  261. // Used for debugging purposes.
  262. //
  263. // Returns S_OK on success or E_OUTOFMEMORY on failure.
  264. STDMETHODIMP CTBGlobal::DebugMessage(BSTR Text)
  265. {
  266. if (fnPrintMessage != NULL && Text != NULL && *Text != OLECHAR('\0')) {
  267. // Create a new buffer for us to use
  268. int BufLen = wcslen(Text) + 1;
  269. char *TextA = (char *)HeapAlloc(GetProcessHeap(),
  270. HEAP_ZERO_MEMORY, BufLen);
  271. // Validate
  272. if (TextA == NULL)
  273. return E_OUTOFMEMORY;
  274. // Copy WC over to our character string
  275. wcstombs(TextA, Text, BufLen);
  276. // Broadcast our new find
  277. if (fnPrintMessage != NULL)
  278. fnPrintMessage(SCRIPT_MESSAGE, "%s", TextA);
  279. // Free the memory
  280. HeapFree(GetProcessHeap(), 0, TextA);
  281. }
  282. return S_OK;
  283. }
  284. // CTBGlobal::GetArguments
  285. //
  286. // Retrieves the user defined argument string passed into the
  287. // scripting interface when first created.
  288. //
  289. // Returns S_OK on success or E_OUTOFMEMORY on failure.
  290. STDMETHODIMP CTBGlobal::GetArguments(BSTR *Args)
  291. {
  292. // Create and allocate the string over OLE.
  293. *Args = SysAllocString(TBShell->GetArguments());
  294. // Check allocation
  295. if (*Args == NULL)
  296. return E_OUTOFMEMORY;
  297. return S_OK;
  298. }
  299. // CTBGlobal::GetDesiredUserName
  300. //
  301. // Retrieves the username which was originally desired to
  302. // be used when the script was first started.
  303. //
  304. // Returns S_OK on success or E_OUTOFMEMORY on failure.
  305. STDMETHODIMP CTBGlobal::GetDesiredUserName(BSTR *UserName)
  306. {
  307. // Create and allocate the string over OLE.
  308. *UserName = SysAllocString(TBShell->GetDesiredUserName());
  309. // Check allocation
  310. if (*UserName == NULL)
  311. return E_OUTOFMEMORY;
  312. return S_OK;
  313. }
  314. // CTBGlobal::LoadScript
  315. //
  316. // Loads a new script, and begins execution in the specified
  317. // file. The method returns when execution in the file
  318. // has terminated.
  319. //
  320. // Returns S_OK on success or E_FAIL on failure.
  321. STDMETHODIMP CTBGlobal::LoadScript(BSTR FileName, BOOL *Result)
  322. {
  323. // Do a quick check on the file name
  324. if (FileName != NULL && *FileName != OLECHAR('\0')) {
  325. // Run the file
  326. if (SCPParseScriptFile(ScriptEngine, FileName) == FALSE) {
  327. *Result = FALSE;
  328. return E_FAIL;
  329. }
  330. // We succeeded
  331. *Result = TRUE;
  332. }
  333. else
  334. // We failed to parse the script, but invalid file name
  335. // is not merit to bring up a script exception.
  336. *Result = FALSE;
  337. return S_OK;
  338. }
  339. // CTBGlobal::Sleep
  340. //
  341. // Uses the Win32 API Sleep() to sleep for the specified time.
  342. //
  343. // Returns S_OK.
  344. STDMETHODIMP CTBGlobal::Sleep(DWORD Milliseconds)
  345. {
  346. if(Milliseconds > 0)
  347. ::Sleep(Milliseconds);
  348. return S_OK;
  349. }
  350. // CTBGlobal::GetDefaultWPM
  351. //
  352. // Returns the recorded default Words Per Minute.
  353. //
  354. // Returns S_OK.
  355. STDMETHODIMP CTBGlobal::GetDefaultWPM(DWORD *WordsPerMinute)
  356. {
  357. _ASSERT(TBShell != NULL);
  358. *WordsPerMinute = TBShell->GetDefaultWPM();
  359. return S_OK;
  360. }
  361. // CTBGlobal::SetDefaultWPM
  362. //
  363. // Changes the default Words Per Minute for typing.
  364. //
  365. // Returns S_OK.
  366. STDMETHODIMP CTBGlobal::SetDefaultWPM(DWORD WordsPerMinute)
  367. {
  368. _ASSERT(TBShell != NULL);
  369. TBShell->SetDefaultWPM(WordsPerMinute);
  370. return S_OK;
  371. }
  372. // CTBGlobal::GetLatency
  373. //
  374. // Retreives the current latency for multi-action commands.
  375. //
  376. // Returns S_OK.
  377. STDMETHODIMP CTBGlobal::GetLatency(DWORD *Latency)
  378. {
  379. _ASSERT(TBShell != NULL);
  380. *Latency = TBShell->GetLatency();
  381. return S_OK;
  382. }
  383. // CTBGlobal::SetLatency
  384. //
  385. // Changes the current latency for multi-action commands.
  386. //
  387. // Returns S_OK.
  388. STDMETHODIMP CTBGlobal::SetLatency(DWORD Latency)
  389. {
  390. _ASSERT(TBShell != NULL);
  391. TBShell->SetLatency(Latency);
  392. return S_OK;
  393. }
  394. // CTBGlobal::GetInterval
  395. //
  396. // Results the number of milliseconds since the local machine
  397. // has been started. The result is zero if the machine does not
  398. // support performance queries. WARNING: the value has a huge
  399. // potential to wrap back to zero if the machine has been up for
  400. // a substantial amount of time.
  401. //
  402. // Returns S_OK.
  403. STDMETHODIMP CTBGlobal::GetInterval(DWORD *Time)
  404. {
  405. LARGE_INTEGER Counter;
  406. // Grab the data
  407. if (QueryPerformanceCounter(&Counter) == FALSE ||
  408. SysPerfFrequency.QuadPart == 0)
  409. // One of the functions failed if we reached here,
  410. // Set the result as 0
  411. *Time = 0;
  412. else
  413. // Otherwise, set the milliseconds
  414. *Time = (DWORD)((Counter.QuadPart * 1000) /
  415. SysPerfFrequency.QuadPart);
  416. return S_OK;
  417. }
  418. // CTBGlobal::DeleteFile
  419. //
  420. // Deletes a file on the local file system.
  421. //
  422. // Returns S_OK.
  423. STDMETHODIMP CTBGlobal::DeleteFile(BSTR FileName, BOOL *Result)
  424. {
  425. *Result = DeleteFileW(FileName);
  426. return S_OK;
  427. }
  428. // CTBGlobal::MoveFile
  429. //
  430. // Moves a file on the local file system. If the destination
  431. // filename already exists, it is overwritten.
  432. //
  433. // Returns S_OK.
  434. STDMETHODIMP CTBGlobal::MoveFile(BSTR OldFileName,
  435. BSTR NewFileName, BOOL *Result)
  436. {
  437. *Result = MoveFileExW(OldFileName, NewFileName,
  438. MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
  439. return S_OK;
  440. }
  441. // CTBGlobal::CopyFile
  442. //
  443. // Copies a file on the local file system. If the destination
  444. // filename already exists, it is overwritten.
  445. //
  446. // Returns S_OK.
  447. STDMETHODIMP CTBGlobal::CopyFile(BSTR OldFileName,
  448. BSTR NewFileName, BOOL *Result)
  449. {
  450. *Result = CopyFileW(OldFileName, NewFileName, FALSE);
  451. return S_OK;
  452. }
  453. // CTBGlobal::CreateDirectory
  454. //
  455. // Creates a directory on the local file system.
  456. //
  457. // Returns S_OK.
  458. STDMETHODIMP CTBGlobal::CreateDirectory(BSTR DirName, BOOL *Result)
  459. {
  460. *Result = CreateDirectoryW(DirName, NULL);
  461. return S_OK;
  462. }
  463. // CTBGlobal::RemoveDirectory
  464. //
  465. // Recursively removes a directory and all members under it. This
  466. // works like the old DELTREE DOS command.
  467. //
  468. // Returns S_OK.
  469. STDMETHODIMP CTBGlobal::RemoveDirectory(BSTR DirName, BOOL *Result)
  470. {
  471. // Use the shell method so we don't have to write a
  472. // long annoying recursive function
  473. SHFILEOPSTRUCTW FileOp = { 0 };
  474. FileOp.wFunc = FO_DELETE;
  475. FileOp.pFrom = DirName;
  476. FileOp.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
  477. // Call the shell API - now wasn't that easy?
  478. *Result = (SHFileOperationW(&FileOp) == 0);
  479. return S_OK;
  480. }
  481. // CTBGlobal::FileExists
  482. //
  483. // Checks whether the file exists or not, this will also work on
  484. // directories. The result is TRUE if the file exists, otherwise
  485. // FALSE.
  486. //
  487. // Returns S_OK.
  488. STDMETHODIMP CTBGlobal::FileExists(BSTR FileName, BOOL *Result)
  489. {
  490. // Simply open the file
  491. HANDLE File = CreateFileW(FileName, 0,
  492. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  493. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  494. // If File is invalid, it didn't exist
  495. *Result = (File != INVALID_HANDLE_VALUE);
  496. // Close the file
  497. if (File != INVALID_HANDLE_VALUE)
  498. CloseHandle(File);
  499. return S_OK;
  500. }
  501. // CTBGlobal::SetCurrentDirectory
  502. //
  503. // Sets the current working directory.
  504. //
  505. // Returns S_OK.
  506. STDMETHODIMP CTBGlobal::SetCurrentDirectory(BSTR Directory, BOOL *Result)
  507. {
  508. *Result = SetCurrentDirectoryW(Directory);
  509. return S_OK;
  510. }
  511. // CTBGlobal::GetCurrentDirectory
  512. //
  513. // Gets the current working directory.
  514. //
  515. // Returns S_OK or E_OUTOFMEMORY.
  516. STDMETHODIMP CTBGlobal::GetCurrentDirectory(BSTR *Directory)
  517. {
  518. OLECHAR *Buffer = NULL;
  519. DWORD BufLenResult;
  520. // First get the number of bytes needed for our buffer
  521. DWORD BufferLen = GetCurrentDirectoryW(0, NULL);
  522. _ASSERT(BufferLen != 0);
  523. // Allocate our local buffer
  524. Buffer = (OLECHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
  525. sizeof(OLECHAR) * BufferLen);
  526. if ( Buffer == NULL ) {
  527. return E_OUTOFMEMORY;
  528. }
  529. // Copy the current directory to our buffer
  530. BufLenResult = GetCurrentDirectoryW(BufferLen, Buffer);
  531. // Check if we failed some freakish way
  532. _ASSERT(BufLenResult < BufferLen);
  533. // Now copy the string over to an OLE buffer
  534. *Directory = SysAllocString(Buffer);
  535. // Free our old buffer
  536. HeapFree(GetProcessHeap(), 0, Buffer);
  537. // Return proper result
  538. return (*Directory != NULL) ? S_OK : E_OUTOFMEMORY;
  539. }
  540. // CTBGlobal::WriteToFile
  541. //
  542. // Appends the specified text to teh specified file. If the file
  543. // does not exist, it is created.
  544. //
  545. // Returns S_OK or E_OUTOFMEMORY.
  546. STDMETHODIMP CTBGlobal::WriteToFile(BSTR FileName, BSTR Text, BOOL *Result)
  547. {
  548. DWORD SetFilePtrResult;
  549. DWORD BytesWritten;
  550. char *TextA;
  551. int BufLen;
  552. HANDLE File;
  553. // Don't do anything for writing empty strings
  554. if (Text == NULL || *Text == OLECHAR('\0')) {
  555. // We didn't write anything, but this is not merit for an exception
  556. *Result = FALSE;
  557. return S_OK;
  558. }
  559. // Get the destination buffer length
  560. BufLen = wcslen(Text) + 1;
  561. // Allocate the buffer
  562. TextA = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufLen);
  563. if (TextA == NULL) {
  564. *Result = FALSE;
  565. return E_OUTOFMEMORY;
  566. }
  567. // Copy the OLE string over to our ASCII buffer
  568. wcstombs(TextA, Text, BufLen);
  569. // Open/Create the file
  570. File = CreateFileW(FileName, GENERIC_READ | GENERIC_WRITE,
  571. 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  572. // Check the result of opening the file
  573. if (File == INVALID_HANDLE_VALUE) {
  574. HeapFree(GetProcessHeap(), 0, TextA);
  575. *Result = FALSE;
  576. return S_OK;
  577. }
  578. // Move the pointer to the end of the file
  579. SetFilePtrResult = SetFilePointer(File, 0, NULL, FILE_END);
  580. _ASSERT(SetFilePtrResult != INVALID_SET_FILE_POINTER);
  581. // Write the text
  582. *Result = WriteFile(File, TextA, BufLen - 1, &BytesWritten, NULL);
  583. // Close the file and return
  584. CloseHandle(File);
  585. // Free the temp ASCII buffer
  586. HeapFree(GetProcessHeap(), 0, TextA);
  587. return (*Result == FALSE) ? E_FAIL : S_OK;
  588. }
  589. // CTBGlobal::WinCommand
  590. //
  591. // Executes the specified command into a new process.
  592. // The function only returns when the new process has terminated.
  593. //
  594. // Returns S_OK on success, or E_FAIL on failure.
  595. STDMETHODIMP CTBGlobal::WinCommand(BSTR Command, DWORD *Result)
  596. {
  597. // Call the helper API
  598. return WinExecuteEx(Command, TRUE, Result);
  599. }
  600. // CTBGlobal::WinExecute
  601. //
  602. // Executes the specified command into a new process, and returns.
  603. // The function does not wait for the new process to terminate.
  604. //
  605. // Returns S_OK or E_OUTOFMEMORY.
  606. STDMETHODIMP CTBGlobal::WinExecute(BSTR Command, BOOL *Result)
  607. {
  608. // Call the helper API
  609. return WinExecuteEx(Command, FALSE, (DWORD *)Result);
  610. }