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.

644 lines
16 KiB

  1. //
  2. // CTBShell.cpp
  3. //
  4. // Contains the methods and properties for the shell object used in TBScript.
  5. // In scripting, to access any members you must prefix the member with "TS.".
  6. //
  7. // Copyright (C) 2001 Microsoft Corporation
  8. //
  9. // Author: a-devjen (Devin Jenson)
  10. //
  11. #include <crtdbg.h>
  12. #include "CTBShell.h"
  13. #define CTBOBJECT CTBShell
  14. #include "virtualdefs.h"
  15. // CTBShell::CTBShell
  16. //
  17. // The constructor.. just initializes data.
  18. //
  19. // No return value.
  20. CTBShell::CTBShell(void)
  21. {
  22. // Initialize base object stuff
  23. Init(IID_ITBShell);
  24. Connection = NULL;
  25. // Clean up local structures
  26. ZeroMemory(&CurrentUser, sizeof(CurrentUser));
  27. ZeroMemory(&LastErrorString, sizeof(LastErrorString));
  28. ZeroMemory(&DesiredData, sizeof(DesiredData));
  29. // Set default resolution
  30. DesiredData.xRes = SCP_DEFAULT_RES_X;
  31. DesiredData.yRes = SCP_DEFAULT_RES_Y;
  32. // Set default words per minute
  33. SetDefaultWPM(T2_DEFAULT_WORDS_PER_MIN);
  34. SetLatency(T2_DEFAULT_LATENCY);
  35. }
  36. // CTBShell::~CTBShell
  37. //
  38. // The destructor.. just unitializes data.
  39. //
  40. // No return value.
  41. CTBShell::~CTBShell(void)
  42. {
  43. UnInit();
  44. }
  45. // CTBShell::RecordLastError
  46. //
  47. // This method simply records the last error string, and
  48. // if specified, records the TRUE/FALSE success state according
  49. // to the specified string.
  50. //
  51. // Returns S_OK to prevent script exceptions.
  52. HRESULT CTBShell::RecordLastError(LPCSTR Error, BOOL *Result)
  53. {
  54. // Just terminate our error string if no error is passed in
  55. if (Error == NULL)
  56. *LastErrorString = OLECHAR('\0');
  57. // Otherwise, convert the string from ASCII to multibyte
  58. else
  59. mbstowcs(LastErrorString, Error,
  60. sizeof(LastErrorString) / sizeof(*LastErrorString));
  61. // If we want the result, enter that in as well
  62. if (Result != NULL)
  63. *Result = (Error == NULL) ? TRUE : FALSE;
  64. // Return the proper HRESULT
  65. return S_OK;
  66. }
  67. // CTBShell::RecordOrThrow
  68. //
  69. // This first calls RecordLastError to complete the
  70. // recording operation. Then if Error is non-NULL,
  71. // a return value is returned to indicate to OLE that
  72. // an exception should be thrown
  73. //
  74. // Returns S_OK if the string is NULL, and E_FAIL if not.
  75. HRESULT CTBShell::RecordOrThrow(LPCSTR Error, BOOL *Result, HRESULT ErrReturn)
  76. {
  77. // Do the normal record operation
  78. RecordLastError(Error, Result);
  79. // If we have failure indication, return E_FAIL which causes OLE
  80. // to cause an error in the script.
  81. return (Error == NULL) ? S_OK : ErrReturn;
  82. }
  83. // CTBShell::SetParam
  84. //
  85. // Sets a user defined LPARAM value needed for callback purposes.
  86. //
  87. // No return value.
  88. void CTBShell::SetParam(LPARAM lParam)
  89. {
  90. this->lParam = lParam;
  91. }
  92. // CTBShell::SetDesiredData
  93. //
  94. // Allows for the class to reference to access
  95. // user-desired data passed to the app.
  96. //
  97. // No return value.
  98. void CTBShell::SetDesiredData(TSClientData *DesiredDataPtr)
  99. {
  100. // Simply copy over the structure
  101. if (DesiredDataPtr != NULL)
  102. DesiredData = *DesiredDataPtr;
  103. // Validate the resolution.. note we don't have to go too
  104. // far here because TCLIENT does some better checks.
  105. if (DesiredData.xRes == 0)
  106. DesiredData.xRes = SCP_DEFAULT_RES_X;
  107. if (DesiredData.yRes == 0)
  108. DesiredData.yRes = SCP_DEFAULT_RES_Y;
  109. // We have this data, now modify the Words Per Minute value.
  110. SetDefaultWPM(DesiredData.WordsPerMinute);
  111. }
  112. // CTBShell::SetDefaultWPM
  113. //
  114. // Sets the default WPM for the shell.
  115. //
  116. // No return value.
  117. void CTBShell::SetDefaultWPM(DWORD WordsPerMinute)
  118. {
  119. // If WordsPerMinute is 0 (which in essence, would not be typing
  120. // at all), change it to the default.
  121. if (WordsPerMinute == 0)
  122. WordsPerMinute = T2_DEFAULT_WORDS_PER_MIN;
  123. // Change global desired data structure to reflect the new value.
  124. DesiredData.WordsPerMinute = WordsPerMinute;
  125. // And change the value over on TCLIENT2 as well
  126. if (Connection != NULL)
  127. T2SetDefaultWPM(Connection, WordsPerMinute);
  128. }
  129. // CTBShell::GetDefaultWPM
  130. //
  131. // Retrieves the default WPM for the shell.
  132. //
  133. // Returns the default words per minute.
  134. DWORD CTBShell::GetDefaultWPM(void)
  135. {
  136. return DesiredData.WordsPerMinute;
  137. }
  138. // CTBGlobal::GetLatency
  139. //
  140. // Retreives the current latency for multi-action commands.
  141. //
  142. // Returns the current latency.
  143. DWORD CTBShell::GetLatency(void)
  144. {
  145. return CurrentLatency;
  146. }
  147. // CTBShell::SetLatency
  148. //
  149. // Changes the current latency for multi-action commands.
  150. //
  151. // No return value.
  152. void CTBShell::SetLatency(DWORD Latency)
  153. {
  154. // Change it locally
  155. CurrentLatency = Latency;
  156. // And also via the TCLIENT2 API
  157. if (Connection != NULL)
  158. T2SetLatency(Connection, Latency);
  159. }
  160. // CTBShell::GetArguments
  161. //
  162. // Retrieves arguments which the shell was originally started with.
  163. // Do not modify this value!! It is only used for copying. The
  164. // only way to modify this value is during creation of the ScriptEngine
  165. // within the DesiredData structure - you pass in an argument string.
  166. //
  167. // Returns a pointer to the arguments string.
  168. LPCWSTR CTBShell::GetArguments(void)
  169. {
  170. return DesiredData.Arguments;
  171. }
  172. // CTBShell::GetDesiredUserName
  173. //
  174. // Retrieves the name in which the app initially wanted to login with.
  175. // Do not modify this value!! It is only used for copying. The
  176. // only way to modify this value is during creation of the ScriptEngine
  177. // within the DesiredData structure - you set the user name there.
  178. //
  179. // Returns a pointer to a string containing a user name.
  180. LPCWSTR CTBShell::GetDesiredUserName(void)
  181. {
  182. return DesiredData.User;
  183. }
  184. //
  185. //
  186. // Begin methods which are directly exported through COM into script.
  187. //
  188. //
  189. // CTBShell::Connect
  190. //
  191. // Simply way to connect to the desired server.
  192. STDMETHODIMP CTBShell::Connect(BOOL *Result)
  193. {
  194. return ConnectEx(
  195. DesiredData.Server,
  196. DesiredData.User,
  197. DesiredData.Pass,
  198. DesiredData.Domain,
  199. DesiredData.xRes,
  200. DesiredData.yRes,
  201. DesiredData.Flags,
  202. DesiredData.BPP,
  203. DesiredData.AudioFlags,
  204. Result);
  205. }
  206. // CTBShell::Connect
  207. //
  208. // Extended way to connect to a server.
  209. STDMETHODIMP CTBShell::ConnectEx(BSTR ServerName, BSTR UserName,
  210. BSTR Password, BSTR Domain, INT xRes, INT yRes,
  211. INT Flags, INT BPP, INT AudioFlags, BOOL *Result)
  212. {
  213. LPCSTR LastError;
  214. // Make sure we don't have a connection yet
  215. if (Connection != NULL)
  216. return RecordLastError("Already connected", Result);
  217. // Use the T2ConnectEx function in TCLIENT2 API to connect
  218. LastError = T2ConnectEx(ServerName, UserName, Password, Domain,
  219. L"explorer", xRes, yRes, Flags, BPP, AudioFlags, &Connection);
  220. // Verify connection...
  221. if (LastError == NULL) {
  222. // Successful, save the current user
  223. wcscpy(CurrentUser, UserName);
  224. // And default data for the connection
  225. T2SetParam(Connection, lParam);
  226. T2SetDefaultWPM(Connection, DesiredData.WordsPerMinute);
  227. T2SetLatency(Connection, CurrentLatency);
  228. }
  229. return RecordLastError(LastError, Result);
  230. }
  231. // CTBShell::Disconnect
  232. //
  233. // Disconnect from an active server.
  234. STDMETHODIMP CTBShell::Disconnect(BOOL *Result)
  235. {
  236. LPCSTR LastError;
  237. // Sanity check the connection
  238. if (Connection == NULL)
  239. return RecordLastError("Not connected", Result);
  240. // Disconnect
  241. if ((LastError = T2Disconnect(Connection)) == NULL)
  242. Connection = NULL;
  243. return RecordLastError(LastError, Result);
  244. }
  245. // CTBShell::GetBuildNumber
  246. //
  247. // Retrieves the build number if retrieved while
  248. // connecting. If no build number has been retreived,
  249. // 0 (zero) is the result.
  250. STDMETHODIMP CTBShell::GetBuildNumber(DWORD *BuildNum)
  251. {
  252. LPCSTR LastError;
  253. // Sanity check the connection
  254. if (Connection == NULL) {
  255. *BuildNum = 0;
  256. return RecordLastError("Not connected");
  257. }
  258. // Get the build number and return
  259. LastError = T2GetBuildNumber(Connection, BuildNum);
  260. return RecordLastError(LastError, NULL);
  261. }
  262. // CTBShell::GetCurrentUserName
  263. //
  264. // If connected, retreives the logged on name.
  265. STDMETHODIMP CTBShell::GetCurrentUserName(BSTR *UserName)
  266. {
  267. // Sanity check the connection
  268. if (Connection == NULL) {
  269. *UserName = SysAllocString(L"");
  270. return RecordLastError("Not connected");
  271. }
  272. // Copy the username
  273. *UserName = SysAllocString(CurrentUser);
  274. // Check the result
  275. if (*UserName == NULL)
  276. return RecordOrThrow("Not enough memory", NULL, E_OUTOFMEMORY);
  277. return S_OK;
  278. }
  279. // CTBShell::GetLastError
  280. //
  281. // Retreives a description of the last error that occured.
  282. STDMETHODIMP CTBShell::GetLastError(BSTR *LastError)
  283. {
  284. // Copy the string over OLE
  285. *LastError = SysAllocString(LastErrorString);
  286. // Check the result
  287. if (*LastError == NULL)
  288. return RecordOrThrow("Not enough memory", NULL, E_OUTOFMEMORY);
  289. return S_OK;
  290. }
  291. // CTBShell::IsConnected
  292. //
  293. // Retreives a boolean indicating whether the handle is fully
  294. // connected or not.
  295. STDMETHODIMP CTBShell::IsConnected(BOOL *Result)
  296. {
  297. *Result = (Connection == NULL) ? FALSE : TRUE;
  298. return S_OK;
  299. }
  300. // CTBShell::Logoff
  301. //
  302. // Attempts to have the active connection logoff.
  303. STDMETHODIMP CTBShell::Logoff(BOOL *Result)
  304. {
  305. LPCSTR LastError;
  306. // Sanity check the connection
  307. if (Connection == NULL)
  308. return RecordLastError("Not connected", Result);
  309. // Use the TCLIENT2 API to logoff
  310. if ((LastError = T2Logoff(Connection)) == NULL)
  311. Connection = NULL;
  312. // Return success state
  313. return RecordLastError(LastError, Result);
  314. }
  315. // CTBShell::WaitForText
  316. //
  317. // Puts the current thread into a wait state until the specified
  318. // text is passed from the active connection. Optionally, you can set
  319. // a timeout value which will make the function fail over the specified
  320. // number of milliseconds.
  321. STDMETHODIMP CTBShell::WaitForText(BSTR Text, INT Timeout, BOOL *Result)
  322. {
  323. // Sanity check the connection
  324. if (Connection == NULL)
  325. return RecordLastError("Not connected", Result);
  326. // Call the API
  327. LPCSTR LastError = T2WaitForText(Connection, Text, Timeout);
  328. // Retirm success state
  329. return RecordLastError(LastError, Result);
  330. }
  331. // CTBShell::WaitForTextAndSleep
  332. //
  333. // This is exactly the same as a combonation of two calls:
  334. //
  335. // TS.WaitForText();
  336. // TS.Sleep();
  337. //
  338. // but put into one function. This is because this combonation is
  339. // used so frequently, using this method drastically shrinks the size
  340. // of a script.
  341. STDMETHODIMP CTBShell::WaitForTextAndSleep(BSTR Text, INT Time, BOOL *Result)
  342. {
  343. // Call TS.WaitForText()
  344. HRESULT OLEResult = WaitForText(Text, -1, Result);
  345. // Call Sleep()
  346. if (OLEResult == S_OK)
  347. Sleep(Time);
  348. return OLEResult;
  349. }
  350. // CTBShell::SendMessage
  351. //
  352. // Sends a Windows Message the active terminal connection.
  353. STDMETHODIMP CTBShell::SendMessage(UINT Message,
  354. WPARAM wParam, LPARAM lParam, BOOL *Result)
  355. {
  356. LPCSTR LastError;
  357. // Sanity check the connection
  358. if (Connection == NULL)
  359. return RecordLastError("Not connected", Result);
  360. // Call the TCLIENT2 API
  361. LastError = T2SendData(Connection, Message, wParam, lParam);
  362. return RecordLastError(LastError, Result);
  363. }
  364. // CTBShell::TypeText
  365. //
  366. // Types text at a specified rate.
  367. STDMETHODIMP CTBShell::TypeText(BSTR Text, UINT WordsPerMin, BOOL *Result)
  368. {
  369. LPCSTR LastError;
  370. // Sanity check the connection
  371. if (Connection == NULL)
  372. return RecordLastError("Not connected", Result);
  373. // Call the TCLIENT2 API
  374. LastError = T2TypeText(Connection, Text, WordsPerMin);
  375. return RecordLastError(LastError, Result);
  376. }
  377. // CTBShell::OpenStartMenu
  378. //
  379. // Does a CTRL-ESC on the remote client to bring up the start menu.
  380. STDMETHODIMP CTBShell::OpenStartMenu(BOOL *Result)
  381. {
  382. // CTRL+ESC for the Start Menu
  383. VKeyCtrl(VK_ESCAPE, Result);
  384. if (Result == FALSE)
  385. return RecordLastError("Failed to CTRL-ESC", NULL);
  386. // Wait for "Shut Down" on the start menu to appear
  387. return WaitForText(OLESTR("Shut Down"), T2INFINITE, Result);
  388. }
  389. // CTBShell::OpenSystemMenu
  390. //
  391. // Does an ALT-SPACE on the remote client to bring up the system menu.
  392. STDMETHODIMP CTBShell::OpenSystemMenu(BOOL *Result)
  393. {
  394. // ALT+SPACE to open the system menu
  395. VKeyAlt(VK_SPACE, Result);
  396. if (Result == FALSE)
  397. return RecordLastError("Failed to ALT-SPACE", NULL);
  398. // Wait for "Close" on the system menu to appear
  399. return WaitForText(OLESTR("Close"), T2INFINITE, Result);
  400. }
  401. // CTBShell::Maximize
  402. //
  403. // Attempts to use the system menu to maximize the active window.
  404. STDMETHODIMP CTBShell::Maximize(BOOL *Result)
  405. {
  406. // Open the system menu
  407. HRESULT OLEResult = OpenSystemMenu(Result);
  408. // Hit 'x' for maximize
  409. if (Result != FALSE)
  410. OLEResult = KeyPress(OLESTR("x"), Result);
  411. return OLEResult;
  412. }
  413. // CTBShell::Minimize
  414. //
  415. // Attempts to use the system menu to minimize the active window.
  416. STDMETHODIMP CTBShell::Minimize(BOOL *Result)
  417. {
  418. // Open the system menu
  419. HRESULT OLEResult = OpenSystemMenu(Result);
  420. // Hit 'x' for maximize
  421. if (Result != FALSE)
  422. OLEResult = KeyPress(OLESTR("n"), Result);
  423. return OLEResult;
  424. }
  425. // CTBShell::Start
  426. //
  427. // Uses the TCLIENT2 function to open the start menu,
  428. // hit r (for run), and type the specified name to run
  429. // a program.
  430. STDMETHODIMP CTBShell::Start(BSTR Name, BOOL *Result)
  431. {
  432. LPCSTR LastError;
  433. // Sanity check the connection.
  434. if (Connection == NULL)
  435. return RecordLastError("Not connected", Result);
  436. // Call the API
  437. LastError = T2Start(Connection, Name);
  438. return RecordLastError(LastError, Result);
  439. }
  440. // CTBShell::SwitchToProcess
  441. //
  442. // Uses the TCLIENT2 function to ALT-TAB between programs until the
  443. // specified text is found, which then the current application is opened.
  444. STDMETHODIMP CTBShell::SwitchToProcess(BSTR Name, BOOL *Result)
  445. {
  446. LPCSTR LastError;
  447. // Sanity check the connection.
  448. if (Connection == NULL)
  449. return RecordLastError("Not connected", Result);
  450. // Call the API
  451. LastError = T2SwitchToProcess(Connection, Name);
  452. return RecordLastError(LastError, Result);
  453. }
  454. // This macros allows to quickly define the key methods.
  455. // Because they are so similar, this macro is nice as it
  456. // only makes you to change code once if need be.
  457. #define CTBSHELL_ENABLEPTR *
  458. #define CTBSHELL_DISABLEPTR
  459. #define CTBSHELL_KEYFUNCTYPE(Name, Type, Ptr) \
  460. STDMETHODIMP CTBShell::Name(Type Key, BOOL *Result) \
  461. { \
  462. LPCSTR LastError = T2##Name(Connection, Ptr Key); \
  463. if (Connection == NULL) \
  464. return RecordLastError("Not connected", Result); \
  465. return RecordLastError(LastError, Result); \
  466. }
  467. // This quick macro allows for declaring both the ASCII
  468. // version and the virtual key code one both in one swipe.
  469. #define CTBSHELL_KEYFUNCS(Name) \
  470. CTBSHELL_KEYFUNCTYPE(Name, BSTR, CTBSHELL_ENABLEPTR); \
  471. CTBSHELL_KEYFUNCTYPE(V##Name, INT, CTBSHELL_DISABLEPTR);
  472. // Key function defintions
  473. CTBSHELL_KEYFUNCS(KeyAlt);
  474. CTBSHELL_KEYFUNCS(KeyCtrl);
  475. CTBSHELL_KEYFUNCS(KeyDown);
  476. CTBSHELL_KEYFUNCS(KeyPress);
  477. CTBSHELL_KEYFUNCS(KeyUp);