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.

2380 lines
80 KiB

  1. /****************************************************************************/
  2. // tssdsql.cpp
  3. //
  4. // Terminal Server Session Directory Interface common component code.
  5. //
  6. // Copyright (C) 2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <windows.h>
  9. #include <stdio.h>
  10. #include <process.h>
  11. #include <ole2.h>
  12. #include <objbase.h>
  13. #include <comdef.h>
  14. #include <adoid.h>
  15. #include <adoint.h>
  16. #include <regapi.h>
  17. #include "tssdsql.h"
  18. #include "trace.h"
  19. #include "resource.h"
  20. /****************************************************************************/
  21. // Types
  22. /****************************************************************************/
  23. // Shortcut VARIANT class to handle cleanup on destruction and common code
  24. // inlining.
  25. class CVar : public VARIANT
  26. {
  27. public:
  28. CVar() { VariantInit(this); }
  29. CVar(VARTYPE vt, SCODE scode = 0) {
  30. VariantInit(this);
  31. this->vt = vt;
  32. this->scode = scode;
  33. }
  34. CVar(VARIANT var) { *this = var; }
  35. ~CVar() { VariantClear(this); }
  36. void InitNull() { this->vt = VT_NULL; }
  37. void InitFromLong(long L) { this->vt = VT_I4; this->lVal = L; }
  38. void InitNoParam() {
  39. this->vt = VT_ERROR;
  40. this->lVal = DISP_E_PARAMNOTFOUND;
  41. }
  42. HRESULT InitFromWSTR(PCWSTR WStr) {
  43. this->bstrVal = SysAllocString(WStr);
  44. if (this->bstrVal != NULL) {
  45. this->vt = VT_BSTR;
  46. return S_OK;
  47. }
  48. else {
  49. return E_OUTOFMEMORY;
  50. }
  51. }
  52. // Inits from a non-NULL-terminated set of WCHARs.
  53. HRESULT InitFromWChars(WCHAR *WChars, unsigned Len) {
  54. this->bstrVal = SysAllocStringLen(WChars, Len);
  55. if (this->bstrVal != NULL) {
  56. this->vt = VT_BSTR;
  57. return S_OK;
  58. }
  59. else {
  60. return E_OUTOFMEMORY;
  61. }
  62. }
  63. HRESULT InitEmptyBSTR(unsigned Size) {
  64. this->bstrVal = SysAllocStringLen(L"", Size);
  65. if (this->bstrVal != NULL) {
  66. this->vt = VT_BSTR;
  67. return S_OK;
  68. }
  69. else {
  70. return E_OUTOFMEMORY;
  71. }
  72. }
  73. HRESULT Clear() { return VariantClear(this); }
  74. };
  75. /****************************************************************************/
  76. // Prototypes
  77. /****************************************************************************/
  78. INT_PTR CALLBACK CustomUIDlg(HWND, UINT, WPARAM, LPARAM);
  79. void FindSqlValue(LPTSTR, LPTSTR, LPTSTR);
  80. LPTSTR ModifySqlValue( LPTSTR * , LPTSTR , LPTSTR );
  81. LPTSTR FindField( LPTSTR pszString , LPTSTR pszKeyName );
  82. VOID strtrim( TCHAR **pszStr);
  83. /****************************************************************************/
  84. // Globals
  85. /****************************************************************************/
  86. extern HINSTANCE g_hInstance;
  87. // The COM object counter (declared in server.cpp)
  88. extern long g_lObjects;
  89. /****************************************************************************/
  90. // CTSSessionDirectory::CTSSessionDirectory
  91. // CTSSessionDirectory::~CTSSessionDirectory
  92. //
  93. // Constructor and destructor
  94. /****************************************************************************/
  95. CTSSessionDirectory::CTSSessionDirectory() :
  96. m_RefCount(0), m_pConnection(NULL)
  97. {
  98. InterlockedIncrement(&g_lObjects);
  99. m_LocalServerAddress[0] = L'\0';
  100. m_DBConnectStr = NULL;
  101. m_DBPwdStr = NULL;
  102. m_DBUserStr = NULL;
  103. m_fEnabled = 0;
  104. m_pszOpaqueString = NULL;
  105. }
  106. CTSSessionDirectory::~CTSSessionDirectory()
  107. {
  108. HRESULT hr;
  109. // If the database connection exists, release it.
  110. if (m_pConnection != NULL) {
  111. hr = ExecServerOffline();
  112. if (FAILED(hr)) {
  113. ERR((TB,"Destr: ExecSvrOffline failed, hr=0x%X", hr));
  114. }
  115. hr = m_pConnection->Close();
  116. if (FAILED(hr)) {
  117. ERR((TB,"pConn->Close() failed, hr=0x%X", hr));
  118. }
  119. m_pConnection->Release();
  120. m_pConnection = NULL;
  121. }
  122. // Decrement the global COM object counter
  123. InterlockedDecrement(&g_lObjects);
  124. if (m_DBConnectStr != NULL)
  125. SysFreeString(m_DBConnectStr);
  126. if (m_DBPwdStr != NULL)
  127. SysFreeString(m_DBPwdStr);
  128. if (m_DBUserStr != NULL)
  129. SysFreeString(m_DBUserStr);
  130. }
  131. /****************************************************************************/
  132. // CTSSessionDirectory::QueryInterface
  133. //
  134. // Standard COM IUnknown function.
  135. /****************************************************************************/
  136. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::QueryInterface(
  137. REFIID riid,
  138. void **ppv)
  139. {
  140. if (riid == IID_IUnknown) {
  141. *ppv = (LPVOID)(IUnknown *)(ITSSessionDirectory *)this;
  142. }
  143. else if (riid == IID_ITSSessionDirectory) {
  144. *ppv = (LPVOID)(ITSSessionDirectory *)this;
  145. }
  146. else if (riid == IID_IExtendServerSettings) {
  147. *ppv = (LPVOID)(IExtendServerSettings *)this;
  148. }
  149. else {
  150. ERR((TB,"QI: Unknown interface"));
  151. return E_NOINTERFACE;
  152. }
  153. ((IUnknown *)*ppv)->AddRef();
  154. return S_OK;
  155. }
  156. /****************************************************************************/
  157. // CTSSessionDirectory::AddRef
  158. //
  159. // Standard COM IUnknown function.
  160. /****************************************************************************/
  161. ULONG STDMETHODCALLTYPE CTSSessionDirectory::AddRef()
  162. {
  163. return InterlockedIncrement(&m_RefCount);
  164. }
  165. /****************************************************************************/
  166. // CTSSessionDirectory::Release
  167. //
  168. // Standard COM IUnknown function.
  169. /****************************************************************************/
  170. ULONG STDMETHODCALLTYPE CTSSessionDirectory::Release()
  171. {
  172. long lRef = InterlockedDecrement(&m_RefCount);
  173. if (lRef == 0)
  174. delete this;
  175. return lRef;
  176. }
  177. /****************************************************************************/
  178. // CTSSessionDirectory::Initialize
  179. //
  180. // ITSSessionDirectory function. Called soon after object instantiation to
  181. // intiialize the directory. LocalServerAddress provides a text representation
  182. // of the local server's load balance IP address. This information should be
  183. // used as the server IP address in the session directory for client
  184. // redirection by other pool servers to this server. StoreServerName,
  185. // ClusterName, and OpaqueSettings are generic reg entries known to TermSrv
  186. // which cover config info across any type of session directory
  187. // implementation. The contents of these strings are designed to be parsed
  188. // by the session directory providers.
  189. /****************************************************************************/
  190. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::Initialize(
  191. LPWSTR LocalServerAddress,
  192. LPWSTR StoreServerName,
  193. LPWSTR ClusterName,
  194. LPWSTR OpaqueSettings,
  195. DWORD Flags,
  196. DWORD (*repopfn)())
  197. {
  198. HRESULT hr = S_OK;
  199. unsigned Len;
  200. WCHAR *pSearch;
  201. WCHAR ConnectString[384];
  202. ASSERT((LocalServerAddress != NULL),(TB,"Init: LocalServerAddr null!"));
  203. ASSERT((StoreServerName != NULL),(TB,"Init: StoreServerName null!"));
  204. ASSERT((ClusterName != NULL),(TB,"Init: ClusterName null!"));
  205. ASSERT((OpaqueSettings != NULL),(TB,"Init: OpaqueSettings null!"));
  206. // Copy off the server address and cluster name for later use.
  207. wcsncpy(m_LocalServerAddress, LocalServerAddress,
  208. sizeof(m_LocalServerAddress) / sizeof(WCHAR) - 1);
  209. m_LocalServerAddress[sizeof(m_LocalServerAddress) / sizeof(WCHAR) - 1] =
  210. L'\0';
  211. wcsncpy(m_ClusterName, ClusterName,
  212. sizeof(m_ClusterName) / sizeof(WCHAR) - 1);
  213. m_ClusterName[sizeof(m_ClusterName) / sizeof(WCHAR) - 1] = L'\0';
  214. // Create the SQL connect string using the OpaqueSettings string
  215. // (which should contain some of the conn str including SQL security
  216. // username and password, sub-table names, provider type, etc.).
  217. // We add onto the end a semicolon (if not already present) and the
  218. // data source (from StoreServerName), if the "data source" substring
  219. // is not already in the connect string.
  220. pSearch = OpaqueSettings;
  221. while (*pSearch != L'\0') {
  222. if (*pSearch == L'D' || *pSearch == L'd') {
  223. if (!_wcsnicmp(pSearch, L"data source", wcslen(L"data source"))) {
  224. // Transfer the OpaqueSettings string as a whole to become
  225. // the connect str.
  226. wcscpy(ConnectString, OpaqueSettings);
  227. goto PostConnStrSetup;
  228. }
  229. }
  230. pSearch++;
  231. }
  232. Len = wcslen(OpaqueSettings);
  233. if (Len == 0 || OpaqueSettings[Len - 1] == L';')
  234. wsprintfW(ConnectString, L"%sData Source=%s", OpaqueSettings,
  235. StoreServerName);
  236. else
  237. wsprintfW(ConnectString, L"%s;Data Source=%s", OpaqueSettings,
  238. StoreServerName);
  239. PostConnStrSetup:
  240. TRC1((TB,"Initialize: Svr addr=%S, StoreSvrName=%S, ClusterName=%S, "
  241. "OpaqueSettings=%S, final connstr=%S",
  242. m_LocalServerAddress, StoreServerName, m_ClusterName,
  243. OpaqueSettings, ConnectString));
  244. // Alloc the BSTRs for the connection strings.
  245. m_DBConnectStr = SysAllocString(ConnectString);
  246. if (m_DBConnectStr != NULL) {
  247. m_DBUserStr = SysAllocString(L"");
  248. if (m_DBUserStr != NULL) {
  249. m_DBPwdStr = SysAllocString(L"");
  250. if (m_DBPwdStr == NULL) {
  251. ERR((TB,"Failed alloc bstr for pwdstr"));
  252. goto ExitFunc;
  253. }
  254. }
  255. else {
  256. ERR((TB,"Failed alloc bstr for userstr"));
  257. goto ExitFunc;
  258. }
  259. }
  260. else {
  261. ERR((TB,"Failed alloc bstr for connstr"));
  262. goto ExitFunc;
  263. }
  264. // Create an ADO connection instance and connect.
  265. hr = CoCreateInstance(CLSID_CADOConnection, NULL,
  266. CLSCTX_INPROC_SERVER, IID_IADOConnection,
  267. (LPVOID *)&m_pConnection);
  268. if (SUCCEEDED(hr)) {
  269. // Set the connection timeout to only 8 seconds. Standard is 15
  270. // but we don't want to be holding up TermSrv's initialization.
  271. m_pConnection->put_ConnectionTimeout(8);
  272. // Do the open.
  273. hr = OpenConnection();
  274. if (SUCCEEDED(hr)) {
  275. // Signal the server is online.
  276. hr = ExecServerOnline();
  277. }
  278. else {
  279. m_pConnection->Release();
  280. m_pConnection = NULL;
  281. }
  282. }
  283. else {
  284. ERR((TB,"CoCreate(ADOConn) returned 0x%X", hr));
  285. }
  286. ExitFunc:
  287. return hr;
  288. }
  289. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::Update(
  290. LPWSTR LocalServerAddress,
  291. LPWSTR StoreServerName,
  292. LPWSTR ClusterName,
  293. LPWSTR OpaqueSettings,
  294. DWORD Flags)
  295. {
  296. return E_NOTIMPL;
  297. }
  298. /****************************************************************************/
  299. // CTSSessionDirectory::OpenConnection
  300. //
  301. // Opens the connection to the SQL server based on the pre-existing
  302. // connect string and allocated connection. This is called at init time,
  303. // plus whenever the database connection times out and gets closed, but is
  304. // still required
  305. /****************************************************************************/
  306. HRESULT CTSSessionDirectory::OpenConnection()
  307. {
  308. HRESULT hr;
  309. ASSERT((m_pConnection != NULL),(TB,"OpenConn: NULL pconn"));
  310. ASSERT((m_DBConnectStr != NULL),(TB,"OpenConn: NULL connstr"));
  311. ASSERT((m_DBUserStr != NULL),(TB,"OpenConn: NULL userstr"));
  312. ASSERT((m_DBPwdStr != NULL),(TB,"OpenConn: NULL pwdstr"));
  313. hr = m_pConnection->Open(m_DBConnectStr, m_DBUserStr, m_DBPwdStr,
  314. adOpenUnspecified);
  315. if (FAILED(hr)) {
  316. ERR((TB,"OpenConn: Failed open DB, connstring=%S, hr=0x%X",
  317. m_DBConnectStr, hr));
  318. }
  319. return hr;
  320. }
  321. /****************************************************************************/
  322. // GetRowArrayStringField
  323. //
  324. // Retrieves a WSTR from a specified row and field of the given SafeArray.
  325. // Returns failure if the target field is not a string. MaxOutStr is max
  326. // WCHARs not including NULL.
  327. /****************************************************************************/
  328. HRESULT GetRowArrayStringField(
  329. SAFEARRAY *pSA,
  330. unsigned RowIndex,
  331. unsigned FieldIndex,
  332. WCHAR *OutStr,
  333. unsigned MaxOutStr)
  334. {
  335. HRESULT hr;
  336. CVar varField;
  337. long DimIndices[2];
  338. DimIndices[0] = FieldIndex;
  339. DimIndices[1] = RowIndex;
  340. SafeArrayGetElement(pSA, DimIndices, &varField);
  341. if (varField.vt == VT_BSTR) {
  342. wcsncpy(OutStr, varField.bstrVal, MaxOutStr);
  343. hr = S_OK;
  344. }
  345. else if (varField.vt == VT_NULL) {
  346. OutStr[0] = L'\0';
  347. hr = S_OK;
  348. }
  349. else {
  350. ERR((TB,"GetRowStrField: Row %u Col %u value %d is not a string",
  351. RowIndex, FieldIndex, varField.vt));
  352. hr = E_FAIL;
  353. }
  354. return hr;
  355. }
  356. /****************************************************************************/
  357. // GetRowArrayDWORDField
  358. //
  359. // Retrieves a DWORD from a specified row and field of the given SafeArray.
  360. // Returns failure if the target field is not a 4-byte integer.
  361. /****************************************************************************/
  362. HRESULT GetRowArrayDWORDField(
  363. SAFEARRAY *pSA,
  364. unsigned RowIndex,
  365. unsigned FieldIndex,
  366. DWORD *pOutValue)
  367. {
  368. HRESULT hr;
  369. CVar varField;
  370. long DimIndices[2];
  371. DimIndices[0] = FieldIndex;
  372. DimIndices[1] = RowIndex;
  373. SafeArrayGetElement(pSA, DimIndices, &varField);
  374. if (varField.vt == VT_I4) {
  375. *pOutValue = (DWORD)varField.lVal;
  376. hr = S_OK;
  377. }
  378. else if (varField.vt == VT_NULL) {
  379. *pOutValue = 0;
  380. hr = S_OK;
  381. }
  382. else {
  383. ERR((TB,"GetRowDWField: Row %u Col %u value %d is not a VT_I4",
  384. RowIndex, FieldIndex, varField.vt));
  385. hr = E_FAIL;
  386. }
  387. return hr;
  388. }
  389. /****************************************************************************/
  390. // CTSSessionDirectory::GetUserDisconnectedSessions
  391. //
  392. // Called to perform a query against the session directory, to provide the
  393. // list of disconnected sessions for the provided username and domain.
  394. // Returns zero or more TSSD_DisconnectedSessionInfo blocks in SessionBuf.
  395. // *pNumSessionsReturned receives the number of blocks.
  396. /****************************************************************************/
  397. #define NumOutputFields 11
  398. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::GetUserDisconnectedSessions(
  399. LPWSTR UserName,
  400. LPWSTR Domain,
  401. DWORD __RPC_FAR *pNumSessionsReturned,
  402. TSSD_DisconnectedSessionInfo __RPC_FAR SessionBuf[
  403. TSSD_MaxDisconnectedSessions])
  404. {
  405. DWORD NumSessions = 0;
  406. long State;
  407. long NumRecords;
  408. HRESULT hr;
  409. unsigned i, j;
  410. unsigned NumFailed;
  411. TSSD_DisconnectedSessionInfo *pInfo;
  412. ADOCommand *pCommand;
  413. ADOParameters *pParameters;
  414. ADORecordset *pResultRecordSet;
  415. ADOFields *pFields;
  416. CVar varRows;
  417. CVar varFields;
  418. CVar varStart;
  419. HRESULT hrFields[NumOutputFields];
  420. TRC2((TB,"GetUserDisconnectedSessions"));
  421. ASSERT((pNumSessionsReturned != NULL),(TB,"NULL pNumSess"));
  422. ASSERT((SessionBuf != NULL),(TB,"NULL SessionBuf"));
  423. hr = CreateADOStoredProcCommand(L"SP_TSSDGetUserDisconnectedSessions",
  424. &pCommand, &pParameters);
  425. if (SUCCEEDED(hr)) {
  426. hr = AddADOInputStringParam(UserName, L"UserName", pCommand,
  427. pParameters, FALSE);
  428. if (SUCCEEDED(hr)) {
  429. hr = AddADOInputStringParam(Domain, L"Domain", pCommand,
  430. pParameters, FALSE);
  431. if (SUCCEEDED(hr)) {
  432. hr = AddADOInputDWORDParam(m_ClusterID, L"ClusterID",
  433. pCommand, pParameters);
  434. if (SUCCEEDED(hr)) {
  435. // Execute the command.
  436. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc,
  437. &pResultRecordSet);
  438. if (FAILED(hr)) {
  439. // If we've not used the connection for awhile, it
  440. // might have been disconnected and the connection
  441. // object will be invalid. Attempt a reopen then
  442. // reissue the command.
  443. TRC2((TB,"GetUserDisc: Failed cmd, hr=0x%X, retrying",
  444. hr));
  445. m_pConnection->Close();
  446. hr = OpenConnection();
  447. if (SUCCEEDED(hr)) {
  448. hr = pCommand->Execute(NULL, NULL,
  449. adCmdStoredProc, &pResultRecordSet);
  450. if (FAILED(hr)) {
  451. ERR((TB,"GetUserDisc: Failed cmd, hr=0x%X",
  452. hr));
  453. }
  454. }
  455. else {
  456. ERR((TB,"GetUserDisc: Failed reopen conn, hr=0x%X",
  457. hr));
  458. }
  459. }
  460. }
  461. else {
  462. ERR((TB,"GetUserDisc: Failed add cluster, hr=0x%X", hr));
  463. }
  464. }
  465. else {
  466. ERR((TB,"GetUserDisc: Failed add sessid, hr=0x%X", hr));
  467. }
  468. }
  469. else {
  470. ERR((TB,"GetUserDisc: Failed add svraddr, hr=0x%X", hr));
  471. }
  472. pParameters->Release();
  473. pCommand->Release();
  474. }
  475. else {
  476. ERR((TB,"GetUserDisc: Failed create cmd, hr=0x%X", hr));
  477. }
  478. // At this point we have a result recordset containing the server rows
  479. // corresponding to all of the disconnected sessions.
  480. if (SUCCEEDED(hr)) {
  481. long State;
  482. NumSessions = 0;
  483. hr = pResultRecordSet->get_State(&State);
  484. if (SUCCEEDED(hr)) {
  485. if (!(State & adStateClosed)) {
  486. VARIANT_BOOL VB;
  487. // If EOF the recordset is empty.
  488. hr = pResultRecordSet->get_EOF(&VB);
  489. if (SUCCEEDED(hr)) {
  490. if (VB) {
  491. TRC1((TB,"GetUserDisc: Result recordset EOF, 0 rows"));
  492. goto PostUnpackResultSet;
  493. }
  494. }
  495. else {
  496. ERR((TB,"GetUserDisc: Failed get_EOF, hr=0x%X", hr));
  497. goto PostUnpackResultSet;
  498. }
  499. }
  500. else {
  501. ERR((TB,"GetUserDisc: Closed result recordset"));
  502. goto PostUnpackResultSet;
  503. }
  504. }
  505. else {
  506. ERR((TB,"GetUserDisc: get_State failed, hr=0x%X", hr));
  507. goto PostUnpackResultSet;
  508. }
  509. // Grab the result data into a safearray, starting with the default
  510. // current row and all fields.
  511. varStart.InitNoParam();
  512. varFields.InitNoParam();
  513. hr = pResultRecordSet->GetRows(TSSD_MaxDisconnectedSessions, varStart,
  514. varFields, &varRows);
  515. if (SUCCEEDED(hr)) {
  516. NumRecords = 0;
  517. hr = SafeArrayGetUBound(varRows.parray, 2, &NumRecords);
  518. if (SUCCEEDED(hr)) {
  519. // 0-based array bound was returned, num rows is that + 1.
  520. NumRecords++;
  521. ASSERT((NumRecords <= TSSD_MaxDisconnectedSessions),
  522. (TB,"GetUserDisc: NumRecords %u greater than expected %u",
  523. NumRecords, TSSD_MaxDisconnectedSessions));
  524. TRC1((TB,"%d rows retrieved from safearray", NumRecords));
  525. }
  526. else {
  527. ERR((TB,"GetUserDisc: Failed safearray getubound, hr=0x%X", hr));
  528. goto PostUnpackResultSet;
  529. }
  530. }
  531. else {
  532. ERR((TB,"GetUserDisc: Failed to get rows, hr=0x%X", hr));
  533. goto PostUnpackResultSet;
  534. }
  535. // Loop through and get the contents of each row, translating into
  536. // the output DiscSession structs.
  537. pInfo = SessionBuf;
  538. for (i = 0; i < (unsigned)NumRecords; i++) {
  539. // Stack up the hr's for each field before checking them all.
  540. hrFields[0] = GetRowArrayStringField(varRows.parray, i, 0,
  541. pInfo->ServerAddress, sizeof(pInfo->ServerAddress) /
  542. sizeof(TCHAR) - 1);
  543. hrFields[1] = GetRowArrayDWORDField(varRows.parray, i, 1,
  544. &pInfo->SessionID);
  545. hrFields[2] = GetRowArrayDWORDField(varRows.parray, i, 2,
  546. &pInfo->TSProtocol);
  547. hrFields[3] = GetRowArrayStringField(varRows.parray, i, 7,
  548. pInfo->ApplicationType, sizeof(pInfo->ApplicationType) /
  549. sizeof(TCHAR) - 1);
  550. hrFields[4] = GetRowArrayDWORDField(varRows.parray, i, 8,
  551. &pInfo->ResolutionWidth);
  552. hrFields[5] = GetRowArrayDWORDField(varRows.parray, i, 9,
  553. &pInfo->ResolutionHeight);
  554. hrFields[6] = GetRowArrayDWORDField(varRows.parray, i, 10,
  555. &pInfo->ColorDepth);
  556. hrFields[7] = GetRowArrayDWORDField(varRows.parray, i, 3,
  557. &pInfo->CreateTime.dwLowDateTime);
  558. hrFields[8] = GetRowArrayDWORDField(varRows.parray, i, 4,
  559. &pInfo->CreateTime.dwHighDateTime);
  560. hrFields[9] = GetRowArrayDWORDField(varRows.parray, i, 5,
  561. &pInfo->DisconnectionTime.dwLowDateTime);
  562. hrFields[10] = GetRowArrayDWORDField(varRows.parray, i, 6,
  563. &pInfo->DisconnectionTime.dwHighDateTime);
  564. NumFailed = 0;
  565. for (j = 0; j < NumOutputFields; j++) {
  566. if (SUCCEEDED(hrFields[j])) {
  567. continue;
  568. }
  569. else {
  570. ERR((TB,"GetUserDisc: Row %u field %u returned hr=0x%X",
  571. i, j, hrFields[j]));
  572. NumFailed++;
  573. }
  574. }
  575. if (!NumFailed) {
  576. NumSessions++;
  577. pInfo++;
  578. }
  579. }
  580. PostUnpackResultSet:
  581. pResultRecordSet->Release();
  582. }
  583. else {
  584. ERR((TB,"GetUserDisc: Failed exec, hr=0x%X", hr));
  585. }
  586. *pNumSessionsReturned = NumSessions;
  587. return hr;
  588. }
  589. /****************************************************************************/
  590. // CTSSessionDirectory::NotifyCreateLocalSession
  591. //
  592. // ITSSessionDirectory function. Called when a session is created to add the
  593. // session to the session directory. Note that other interface functions
  594. // access the session directory by either the username/domain or the
  595. // session ID; the directory schema should take this into account for
  596. // performance optimization.
  597. /****************************************************************************/
  598. #define NumCreateParams 11
  599. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::NotifyCreateLocalSession(
  600. TSSD_CreateSessionInfo __RPC_FAR *pCreateInfo)
  601. {
  602. unsigned i, NumFailed;
  603. HRESULT hr;
  604. HRESULT hrParam[NumCreateParams];
  605. ADOCommand *pCommand;
  606. ADOParameters *pParameters;
  607. ADORecordset *pResultRecordSet;
  608. TRC2((TB,"NotifyCreateLocalSession, SessID=%u", pCreateInfo->SessionID));
  609. ASSERT((pCreateInfo != NULL),(TB,"NotifyCreate: NULL CreateInfo"));
  610. hr = CreateADOStoredProcCommand(L"SP_TSSDCreateSession", &pCommand,
  611. &pParameters);
  612. if (SUCCEEDED(hr)) {
  613. // Create and add the params in one fell swoop. We'll check all
  614. // of the return values in a batch later.
  615. hrParam[0] = AddADOInputStringParam(pCreateInfo->UserName,
  616. L"UserName", pCommand, pParameters, FALSE);
  617. hrParam[1] = AddADOInputStringParam(pCreateInfo->Domain,
  618. L"Domain", pCommand, pParameters, FALSE);
  619. hrParam[2] = AddADOInputDWORDParam(m_ServerID,
  620. L"ServerID", pCommand, pParameters);
  621. hrParam[3] = AddADOInputDWORDParam(pCreateInfo->SessionID,
  622. L"SessionID", pCommand, pParameters);
  623. hrParam[4] = AddADOInputDWORDParam(pCreateInfo->TSProtocol,
  624. L"TSProtocol", pCommand, pParameters);
  625. hrParam[5] = AddADOInputStringParam(pCreateInfo->ApplicationType,
  626. L"AppType", pCommand, pParameters);
  627. hrParam[6] = AddADOInputDWORDParam(pCreateInfo->ResolutionWidth,
  628. L"ResolutionWidth", pCommand, pParameters);
  629. hrParam[7] = AddADOInputDWORDParam(pCreateInfo->ResolutionHeight,
  630. L"ResolutionHeight", pCommand, pParameters);
  631. hrParam[8] = AddADOInputDWORDParam(pCreateInfo->ColorDepth,
  632. L"ColorDepth", pCommand, pParameters);
  633. hrParam[9] = AddADOInputDWORDParam(pCreateInfo->CreateTime.dwLowDateTime,
  634. L"CreateTimeLow", pCommand, pParameters);
  635. hrParam[10] = AddADOInputDWORDParam(pCreateInfo->CreateTime.dwHighDateTime,
  636. L"CreateTimeHigh", pCommand, pParameters);
  637. NumFailed = 0;
  638. for (i = 0; i < NumCreateParams; i++) {
  639. if (SUCCEEDED(hrParam[i])) {
  640. continue;
  641. }
  642. else {
  643. ERR((TB,"NotifyCreate: Failed param create %u", i));
  644. NumFailed++;
  645. hr = hrParam[i];
  646. }
  647. }
  648. if (NumFailed == 0) {
  649. // Execute the command.
  650. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc |
  651. adExecuteNoRecords, &pResultRecordSet);
  652. if (FAILED(hr)) {
  653. // If we've not used the connection for awhile, it might
  654. // have been disconnected and the connection object will
  655. // be invalid. Attempt a reopen then reissue the command.
  656. TRC2((TB,"NotifyCreate: Failed cmd, hr=0x%X, retrying",
  657. hr));
  658. m_pConnection->Close();
  659. hr = OpenConnection();
  660. if (SUCCEEDED(hr)) {
  661. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc |
  662. adExecuteNoRecords, &pResultRecordSet);
  663. if (FAILED(hr)) {
  664. ERR((TB,"NotifyCreate: Failed exec, hr=0x%X", hr));
  665. }
  666. }
  667. else {
  668. ERR((TB,"NotifyCreate: Failed reopen conn, hr=0x%X",
  669. hr));
  670. }
  671. }
  672. }
  673. pParameters->Release();
  674. pCommand->Release();
  675. }
  676. else {
  677. ERR((TB,"NotifyCreate: Failed create cmd, hr=0x%X", hr));
  678. }
  679. return hr;
  680. }
  681. /****************************************************************************/
  682. // CTSSessionDirectory::NotifyDestroyLocalSession
  683. //
  684. // ITSSessionDirectory function. Removes a session from the session database.
  685. /****************************************************************************/
  686. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::NotifyDestroyLocalSession(
  687. DWORD SessionID)
  688. {
  689. HRESULT hr;
  690. ADOCommand *pCommand;
  691. ADOParameters *pParameters;
  692. ADORecordset *pResultRecordSet;
  693. TRC2((TB,"NotifyDestroyLocalSession, SessionID=%u", SessionID));
  694. hr = CreateADOStoredProcCommand(L"SP_TSSDDeleteSession", &pCommand,
  695. &pParameters);
  696. if (SUCCEEDED(hr)) {
  697. hr = AddADOInputDWORDParam(m_ServerID, L"ServerID",
  698. pCommand, pParameters);
  699. if (SUCCEEDED(hr)) {
  700. hr = AddADOInputDWORDParam(SessionID, L"SessionID", pCommand,
  701. pParameters);
  702. if (SUCCEEDED(hr)) {
  703. // Execute the command.
  704. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc |
  705. adExecuteNoRecords, &pResultRecordSet);
  706. if (FAILED(hr)) {
  707. // If we've not used the connection for awhile, it might
  708. // have been disconnected and the connection object will
  709. // be invalid. Attempt a reopen then reissue the command.
  710. TRC2((TB,"NotifyDestroy: Failed cmd, hr=0x%X, retrying",
  711. hr));
  712. m_pConnection->Close();
  713. hr = OpenConnection();
  714. if (SUCCEEDED(hr)) {
  715. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc |
  716. adExecuteNoRecords, &pResultRecordSet);
  717. if (FAILED(hr)) {
  718. ERR((TB,"NotifyDestroy: Failed exec, hr=0x%X", hr));
  719. }
  720. }
  721. else {
  722. ERR((TB,"NotifyDestroy: Failed reopen conn, hr=0x%X",
  723. hr));
  724. }
  725. }
  726. }
  727. else {
  728. ERR((TB,"NotifyDestroy: Failed add sessid, hr=0x%X", hr));
  729. }
  730. }
  731. else {
  732. ERR((TB,"NotifyDestroy: Failed add svraddr, hr=0x%X", hr));
  733. }
  734. pParameters->Release();
  735. pCommand->Release();
  736. }
  737. else {
  738. ERR((TB,"NotifyDestroy: Failed create cmd, hr=0x%X", hr));
  739. }
  740. return hr;
  741. }
  742. /****************************************************************************/
  743. // CTSSessionDirectory::NotifyDisconnectLocalSession
  744. //
  745. // ITSSessionDirectory function. Changes the state of an existing session to
  746. // disconnected. The provided time should be returned in disconnected session
  747. // queries performed by any machine in the server pool.
  748. /****************************************************************************/
  749. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::NotifyDisconnectLocalSession(
  750. DWORD SessionID,
  751. FILETIME DiscTime)
  752. {
  753. HRESULT hr;
  754. ADOCommand *pCommand;
  755. ADOParameters *pParameters;
  756. ADORecordset *pResultRecordSet;
  757. TRC2((TB,"NotifyDisconnectLocalSession, SessionID=%u", SessionID));
  758. hr = CreateADOStoredProcCommand(L"SP_TSSDSetSessionDisconnected",
  759. &pCommand, &pParameters);
  760. if (SUCCEEDED(hr)) {
  761. hr = AddADOInputDWORDParam(m_ServerID, L"ServerID",
  762. pCommand, pParameters);
  763. if (SUCCEEDED(hr)) {
  764. hr = AddADOInputDWORDParam(SessionID, L"SessionID", pCommand,
  765. pParameters);
  766. if (SUCCEEDED(hr)) {
  767. hr = AddADOInputDWORDParam(DiscTime.dwLowDateTime,
  768. L"DiscTimeLow", pCommand, pParameters);
  769. if (SUCCEEDED(hr)) {
  770. hr = AddADOInputDWORDParam(DiscTime.dwHighDateTime,
  771. L"DiscTimeHigh", pCommand, pParameters);
  772. if (SUCCEEDED(hr)) {
  773. // Execute the command.
  774. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc |
  775. adExecuteNoRecords, &pResultRecordSet);
  776. if (FAILED(hr)) {
  777. // If we've not used the connection for awhile, it
  778. // might have been disconnected and the connection
  779. // object will be invalid. Attempt a reopen then
  780. // reissue the command.
  781. TRC2((TB,"NotifyDisc: Failed cmd, hr=0x%X, "
  782. "retrying", hr));
  783. m_pConnection->Close();
  784. hr = OpenConnection();
  785. if (SUCCEEDED(hr)) {
  786. hr = pCommand->Execute(NULL, NULL,
  787. adCmdStoredProc | adExecuteNoRecords,
  788. &pResultRecordSet);
  789. if (FAILED(hr)) {
  790. ERR((TB,"NotifyDisc: Failed exec, hr=0x%X",
  791. hr));
  792. }
  793. }
  794. else {
  795. ERR((TB,"NotifyDisc: Failed reopen conn, "
  796. "hr=0x%X", hr));
  797. }
  798. }
  799. }
  800. else {
  801. ERR((TB,"NotifyDisconn: Failed add disctimehigh, "
  802. "hr=0x%X", hr));
  803. }
  804. }
  805. else {
  806. ERR((TB,"NotifyDisconn: Failed add disctimelow, hr=0x%X",
  807. hr));
  808. }
  809. }
  810. else {
  811. ERR((TB,"NotifyDisconn: Failed add sessid, hr=0x%X", hr));
  812. }
  813. }
  814. else {
  815. ERR((TB,"NotifyDisconn: Failed add svraddr, hr=0x%X", hr));
  816. }
  817. pParameters->Release();
  818. pCommand->Release();
  819. }
  820. else {
  821. ERR((TB,"NotifyDisconn: Failed create cmd, hr=0x%X", hr));
  822. }
  823. return hr;
  824. }
  825. /****************************************************************************/
  826. // CTSSessionDirectory::NotifyReconnectLocalSession
  827. //
  828. // ITSSessionDirectory function. Changes the state of an existing session
  829. // from disconnected to connected.
  830. /****************************************************************************/
  831. #define NumReconnParams 6
  832. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::NotifyReconnectLocalSession(
  833. TSSD_ReconnectSessionInfo __RPC_FAR *pReconnInfo)
  834. {
  835. HRESULT hr;
  836. HRESULT hrParam[NumReconnParams];
  837. unsigned i, NumFailed;
  838. ADOCommand *pCommand;
  839. ADOParameters *pParameters;
  840. ADORecordset *pResultRecordSet;
  841. TRC2((TB,"NotifyReconnectLocalSession, SessionID=%u",
  842. pReconnInfo->SessionID));
  843. hr = CreateADOStoredProcCommand(L"SP_TSSDSetSessionReconnected",
  844. &pCommand, &pParameters);
  845. if (SUCCEEDED(hr)) {
  846. // Add the 5 parameters.
  847. hrParam[0] = AddADOInputDWORDParam(m_ServerID,
  848. L"ServerID", pCommand, pParameters);
  849. hrParam[1] = AddADOInputDWORDParam(pReconnInfo->SessionID,
  850. L"SessionID", pCommand, pParameters);
  851. hrParam[2] = AddADOInputDWORDParam(pReconnInfo->TSProtocol,
  852. L"TSProtocol", pCommand, pParameters);
  853. hrParam[3] = AddADOInputDWORDParam(pReconnInfo->ResolutionWidth,
  854. L"ResWidth", pCommand, pParameters);
  855. hrParam[4] = AddADOInputDWORDParam(pReconnInfo->ResolutionHeight,
  856. L"ResHeight", pCommand, pParameters);
  857. hrParam[5] = AddADOInputDWORDParam(pReconnInfo->ColorDepth,
  858. L"ColorDepth", pCommand, pParameters);
  859. NumFailed = 0;
  860. for (i = 0; i < NumReconnParams; i++) {
  861. if (SUCCEEDED(hrParam[i])) {
  862. continue;
  863. }
  864. else {
  865. ERR((TB,"NotifyReconn: Failed param create %u", i));
  866. NumFailed++;
  867. hr = hrParam[i];
  868. }
  869. }
  870. if (NumFailed == 0) {
  871. // Execute the command.
  872. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc |
  873. adExecuteNoRecords, &pResultRecordSet);
  874. if (FAILED(hr)) {
  875. // If we've not used the connection for awhile, it might
  876. // have been disconnected and the connection object will
  877. // be in a bad state. Close, reopen, and reissue the
  878. // command.
  879. TRC2((TB,"NotifyReconn: Failed exec, hr=0x%X, retrying",
  880. hr));
  881. m_pConnection->Close();
  882. hr = OpenConnection();
  883. if (SUCCEEDED(hr)) {
  884. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc |
  885. adExecuteNoRecords, &pResultRecordSet);
  886. if (FAILED(hr)) {
  887. ERR((TB,"NotifyReconn: Failed exec, hr=0x%X", hr));
  888. }
  889. }
  890. else {
  891. ERR((TB,"NotifyReconn: Failed reopen conn, hr=0x%X",
  892. hr));
  893. }
  894. }
  895. }
  896. pParameters->Release();
  897. pCommand->Release();
  898. }
  899. else {
  900. ERR((TB,"NotifyReconn: Failed create cmd, hr=0x%X", hr));
  901. }
  902. return hr;
  903. }
  904. /****************************************************************************/
  905. // CTSSessionDirectory::NotifyReconnectPending
  906. //
  907. // ITSSessionDirectory function. Informs session directory that a reconnect
  908. // is pending soon because of a revectoring. Used by DIS to determine
  909. // when a server might have gone down. (DIS is the Directory Integrity
  910. // Service, which runs on the machine with the session directory.)
  911. //
  912. // This is a two-phase procedure--we first check the fields, and then we
  913. // add the timestamp only if there is no outstanding timestamp already (i.e.,
  914. // the two Almost-In-Time fields are 0). This prevents constant revectoring
  915. // from updating the timestamp fields, which would prevent the DIS from
  916. // figuring out that a server is down.
  917. //
  918. // These two steps are done in the stored procedure to make the operation
  919. // atomic.
  920. /****************************************************************************/
  921. #define NumReconPendParams 3
  922. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::NotifyReconnectPending(
  923. WCHAR *ServerName)
  924. {
  925. HRESULT hr;
  926. HRESULT hrParam[NumReconPendParams];
  927. unsigned NumFailed, i;
  928. FILETIME ft;
  929. SYSTEMTIME st;
  930. ADOCommand *pCommand;
  931. ADOParameters *pParameters;
  932. ADORecordset *pResultRecordSet;
  933. TRC2((TB,"NotifyReconnectPending"));
  934. ASSERT((ServerName != NULL),(TB,"NotifyReconnectPending: NULL ServerName"));
  935. // Get the current system time.
  936. GetSystemTime(&st);
  937. SystemTimeToFileTime(&st, &ft);
  938. // Call the stored procedure, which will update the fields if they are 0.
  939. hr = CreateADOStoredProcCommand(L"SP_TSSDSetServerReconnectPending",
  940. &pCommand, &pParameters);
  941. if (SUCCEEDED(hr)) {
  942. // Add the 3 parameters.
  943. hrParam[0] = AddADOInputStringParam(ServerName,
  944. L"ServerAddress", pCommand, pParameters, FALSE);
  945. hrParam[1] = AddADOInputDWORDParam(ft.dwLowDateTime,
  946. L"AlmostTimeLow", pCommand, pParameters);
  947. hrParam[2] = AddADOInputDWORDParam(ft.dwHighDateTime,
  948. L"AlmostTimeHigh", pCommand, pParameters);
  949. NumFailed = 0;
  950. for (i = 0; i < NumReconPendParams; i++) {
  951. if (SUCCEEDED(hrParam[i])) {
  952. continue;
  953. }
  954. else {
  955. ERR((TB,"NotifyReconPending: Failed param create %u", i));
  956. NumFailed++;
  957. hr = hrParam[i];
  958. }
  959. }
  960. if (NumFailed == 0) {
  961. // Execute the command.
  962. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc |
  963. adExecuteNoRecords, &pResultRecordSet);
  964. if (FAILED(hr)) {
  965. // If we've not used the connection for awhile, it might
  966. // have been disconnected and the connection object will
  967. // be in a bad state. Close, reopen, and reissue the
  968. // command.
  969. TRC2((TB,"NotifyReconPending: Failed exec, hr=0x%X, retrying",
  970. hr));
  971. m_pConnection->Close();
  972. hr = OpenConnection();
  973. if (SUCCEEDED(hr)) {
  974. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc |
  975. adExecuteNoRecords, &pResultRecordSet);
  976. if (FAILED(hr)) {
  977. ERR((TB,"NotifyReconPending: Failed exec, hr=0x%X", hr));
  978. }
  979. }
  980. else {
  981. ERR((TB,"NotifyReconPending: Failed reopen conn, hr=0x%X",
  982. hr));
  983. }
  984. }
  985. }
  986. pParameters->Release();
  987. pCommand->Release();
  988. }
  989. else {
  990. ERR((TB,"NotifyReconnectPending: Failed create cmd, hr=0x%X", hr));
  991. }
  992. return hr;
  993. }
  994. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::Repopulate(
  995. DWORD WinStationCount,
  996. TSSD_RepopulateSessionInfo *rsi)
  997. {
  998. return E_NOTIMPL;
  999. }
  1000. /****************************************************************************/
  1001. // CreateADOStoredProcCommand
  1002. //
  1003. // Creates and returns a stored proc ADOCommand, plus a ref to its
  1004. // associated Parameters.
  1005. /****************************************************************************/
  1006. HRESULT CTSSessionDirectory::CreateADOStoredProcCommand(
  1007. PWSTR CmdName,
  1008. ADOCommand **ppCommand,
  1009. ADOParameters **ppParameters)
  1010. {
  1011. HRESULT hr;
  1012. BSTR CmdStr;
  1013. ADOCommand *pCommand;
  1014. ADOParameters *pParameters;
  1015. CmdStr = SysAllocString(CmdName);
  1016. if (CmdStr != NULL) {
  1017. hr = CoCreateInstance(CLSID_CADOCommand, NULL, CLSCTX_INPROC_SERVER,
  1018. IID_IADOCommand25, (LPVOID *)&pCommand);
  1019. if (SUCCEEDED(hr)) {
  1020. // Set the connection.
  1021. hr = pCommand->putref_ActiveConnection(m_pConnection);
  1022. if (SUCCEEDED(hr)) {
  1023. // Set the command text.
  1024. hr = pCommand->put_CommandText(CmdStr);
  1025. if (SUCCEEDED(hr)) {
  1026. // Set the command type.
  1027. hr = pCommand->put_CommandType(adCmdStoredProc);
  1028. if (SUCCEEDED(hr)) {
  1029. // Get the Parameters pointer from the Command to
  1030. // allow appending params.
  1031. hr = pCommand->get_Parameters(&pParameters);
  1032. if (FAILED(hr)) {
  1033. ERR((TB,"Failed getParams for command, "
  1034. "hr=0x%X", hr));
  1035. goto PostCreateCommand;
  1036. }
  1037. }
  1038. else {
  1039. ERR((TB,"Failed set cmdtype for command, hr=0x%X",
  1040. hr));
  1041. goto PostCreateCommand;
  1042. }
  1043. }
  1044. else {
  1045. ERR((TB,"Failed set cmdtext for command, hr=0x%X", hr));
  1046. goto PostCreateCommand;
  1047. }
  1048. }
  1049. else {
  1050. ERR((TB,"Command::putref_ActiveConnection hr=0x%X", hr));
  1051. goto PostCreateCommand;
  1052. }
  1053. }
  1054. else {
  1055. ERR((TB,"CoCreate(Command) returned 0x%X", hr));
  1056. goto PostAllocCmdStr;
  1057. }
  1058. SysFreeString(CmdStr);
  1059. }
  1060. else {
  1061. ERR((TB,"Failed to alloc cmd str"));
  1062. hr = E_OUTOFMEMORY;
  1063. goto ExitFunc;
  1064. }
  1065. *ppCommand = pCommand;
  1066. *ppParameters = pParameters;
  1067. return hr;
  1068. // Error handling.
  1069. PostCreateCommand:
  1070. pCommand->Release();
  1071. PostAllocCmdStr:
  1072. SysFreeString(CmdStr);
  1073. ExitFunc:
  1074. *ppCommand = NULL;
  1075. *ppParameters = NULL;
  1076. return hr;
  1077. }
  1078. /****************************************************************************/
  1079. // AddADOInputDWORDParam
  1080. //
  1081. // Creates and adds to the given ADOParameters object a DWORD-initialized
  1082. // parameter value.
  1083. /****************************************************************************/
  1084. HRESULT CTSSessionDirectory::AddADOInputDWORDParam(
  1085. DWORD Param,
  1086. PWSTR ParamName,
  1087. ADOCommand *pCommand,
  1088. ADOParameters *pParameters)
  1089. {
  1090. HRESULT hr;
  1091. CVar varParam;
  1092. BSTR ParamStr;
  1093. ADOParameter *pParam;
  1094. ParamStr = SysAllocString(ParamName);
  1095. if (ParamStr != NULL) {
  1096. varParam.vt = VT_I4;
  1097. varParam.lVal = Param;
  1098. hr = pCommand->CreateParameter(ParamStr, adInteger, adParamInput, -1,
  1099. varParam, &pParam);
  1100. if (SUCCEEDED(hr)) {
  1101. hr = pParameters->Append(pParam);
  1102. if (FAILED(hr)) {
  1103. ERR((TB,"InDWParam: Failed append param %S, hr=0x%X",
  1104. ParamName, hr));
  1105. }
  1106. // ADO will have its own ref for the param.
  1107. pParam->Release();
  1108. }
  1109. else {
  1110. ERR((TB,"InDWParam: Failed CreateParam %S, hr=0x%X",
  1111. ParamName, hr));
  1112. }
  1113. SysFreeString(ParamStr);
  1114. }
  1115. else {
  1116. ERR((TB,"InDWParam: Failed alloc paramname"));
  1117. hr = E_OUTOFMEMORY;
  1118. }
  1119. return hr;
  1120. }
  1121. /****************************************************************************/
  1122. // AddADOInputStringParam
  1123. //
  1124. // Creates and adds to the given ADOParameters object a WSTR-initialized
  1125. // parameter value.
  1126. /****************************************************************************/
  1127. HRESULT CTSSessionDirectory::AddADOInputStringParam(
  1128. PWSTR Param,
  1129. PWSTR ParamName,
  1130. ADOCommand *pCommand,
  1131. ADOParameters *pParameters,
  1132. BOOL bNullOnNull)
  1133. {
  1134. HRESULT hr;
  1135. CVar varParam;
  1136. BSTR ParamStr;
  1137. ADOParameter *pParam;
  1138. int Len;
  1139. ParamStr = SysAllocString(ParamName);
  1140. if (ParamStr != NULL) {
  1141. // ADO does not seem to like accepting string params that are zero
  1142. // length. So, if the string we have is zero length and bNullOnNull says
  1143. // we can, we send a null VARIANT type, resulting in a null value at
  1144. // the SQL server.
  1145. if (wcslen(Param) > 0 || !bNullOnNull) {
  1146. hr = varParam.InitFromWSTR(Param);
  1147. Len = wcslen(Param);
  1148. }
  1149. else {
  1150. varParam.vt = VT_NULL;
  1151. varParam.bstrVal = NULL;
  1152. Len = -1;
  1153. hr = S_OK;
  1154. }
  1155. if (SUCCEEDED(hr)) {
  1156. hr = pCommand->CreateParameter(ParamStr, adVarWChar, adParamInput,
  1157. Len, varParam, &pParam);
  1158. if (SUCCEEDED(hr)) {
  1159. hr = pParameters->Append(pParam);
  1160. if (FAILED(hr)) {
  1161. ERR((TB,"InStrParam: Failed append param %S, hr=0x%X",
  1162. ParamName, hr));
  1163. }
  1164. // ADO will have its own ref for the param.
  1165. pParam->Release();
  1166. }
  1167. else {
  1168. ERR((TB,"InStrParam: Failed CreateParam %S, hr=0x%X",
  1169. ParamName, hr));
  1170. }
  1171. }
  1172. else {
  1173. ERR((TB,"InStrParam: Failed alloc variant bstr, "
  1174. "param %S, hr=0x%X", ParamName, hr));
  1175. }
  1176. SysFreeString(ParamStr);
  1177. }
  1178. else {
  1179. ERR((TB,"InStrParam: Failed alloc paramname"));
  1180. hr = E_OUTOFMEMORY;
  1181. }
  1182. return hr;
  1183. }
  1184. /****************************************************************************/
  1185. // CTSSessionDirectory::ExecServerOnline
  1186. //
  1187. // Encapsulates creation and execution of the SP_TSSDServerOnline
  1188. // stored procedure on the server. Assumes that m_ClusterName is already set.
  1189. /****************************************************************************/
  1190. HRESULT CTSSessionDirectory::ExecServerOnline()
  1191. {
  1192. HRESULT hr;
  1193. ADOCommand *pCommand;
  1194. ADOParameters *pParameters;
  1195. ADORecordset *pResultRecordSet;
  1196. CVar varRows;
  1197. CVar varFields;
  1198. CVar varStart;
  1199. long NumRecords;
  1200. if (m_pConnection != NULL) {
  1201. // Create the command.
  1202. hr = CreateADOStoredProcCommand(L"SP_TSSDServerOnline", &pCommand,
  1203. &pParameters);
  1204. if (SUCCEEDED(hr)) {
  1205. // Server name param.
  1206. hr = AddADOInputStringParam(m_LocalServerAddress,
  1207. L"ServerAddress", pCommand, pParameters, FALSE);
  1208. if (SUCCEEDED(hr)) {
  1209. // Cluster name param.
  1210. hr = AddADOInputStringParam(m_ClusterName,
  1211. L"ClusterName", pCommand, pParameters, TRUE);
  1212. if (SUCCEEDED(hr)) {
  1213. // Execute the command.
  1214. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc,
  1215. &pResultRecordSet);
  1216. if (SUCCEEDED(hr)) {
  1217. TRC2((TB,"ExecOn: Success"));
  1218. }
  1219. else {
  1220. ERR((TB,"Failed exec ServerOnline, hr=0x%X", hr));
  1221. }
  1222. }
  1223. else {
  1224. ERR((TB,"ExecOn: Failed adding ClusterName, hr=0x%X", hr));
  1225. }
  1226. }
  1227. else {
  1228. ERR((TB,"ExecOn: Failed adding ServerAddress, hr=0x%X",
  1229. hr));
  1230. }
  1231. pParameters->Release();
  1232. pCommand->Release();
  1233. }
  1234. else {
  1235. ERR((TB,"ExecOn: Failed create command, hr=0x%X", hr));
  1236. }
  1237. }
  1238. else {
  1239. ERR((TB,"ExecOn: Connection invalid"));
  1240. hr = E_FAIL;
  1241. }
  1242. // Parse out the ServerID and ClusterID from the result recordset.
  1243. if (SUCCEEDED(hr)) {
  1244. long State;
  1245. hr = pResultRecordSet->get_State(&State);
  1246. if (SUCCEEDED(hr)) {
  1247. if (!(State & adStateClosed)) {
  1248. VARIANT_BOOL VB;
  1249. // If EOF the recordset is empty.
  1250. hr = pResultRecordSet->get_EOF(&VB);
  1251. if (SUCCEEDED(hr)) {
  1252. if (VB) {
  1253. TRC1((TB,"ExecOnline: Result recordset EOF"));
  1254. hr = E_FAIL;
  1255. goto PostUnpackResultSet;
  1256. }
  1257. }
  1258. else {
  1259. ERR((TB,"GetUserDisc: Failed get_EOF, hr=0x%X", hr));
  1260. goto PostUnpackResultSet;
  1261. }
  1262. }
  1263. else {
  1264. ERR((TB,"GetUserDisc: Closed result recordset"));
  1265. hr = E_FAIL;
  1266. goto PostUnpackResultSet;
  1267. }
  1268. }
  1269. else {
  1270. ERR((TB,"GetUserDisc: get_State failed, hr=0x%X", hr));
  1271. goto PostUnpackResultSet;
  1272. }
  1273. // Grab the result data into a safearray, starting with the default
  1274. // current row and all fields.
  1275. varStart.InitNoParam();
  1276. varFields.InitNoParam();
  1277. hr = pResultRecordSet->GetRows(1, varStart, varFields, &varRows);
  1278. if (SUCCEEDED(hr)) {
  1279. NumRecords = 0;
  1280. hr = SafeArrayGetUBound(varRows.parray, 2, &NumRecords);
  1281. if (SUCCEEDED(hr)) {
  1282. // 0-based array bound was returned, num rows is that + 1.
  1283. NumRecords++;
  1284. ASSERT((NumRecords == 1),
  1285. (TB,"ExecOnline: NumRecords %u != expected %u",
  1286. NumRecords, 1));
  1287. TRC1((TB,"%d rows retrieved from safearray", NumRecords));
  1288. }
  1289. else {
  1290. ERR((TB,"ExecOnline: Failed safearray getubound, hr=0x%X", hr));
  1291. goto PostUnpackResultSet;
  1292. }
  1293. }
  1294. else {
  1295. ERR((TB,"ExecOnline: Failed to get rows, hr=0x%X", hr));
  1296. goto PostUnpackResultSet;
  1297. }
  1298. // Get the fields.
  1299. hr = GetRowArrayDWORDField(varRows.parray, 0, 0, &m_ServerID);
  1300. if (SUCCEEDED(hr)) {
  1301. hr = GetRowArrayDWORDField(varRows.parray, 0, 1, &m_ClusterID);
  1302. if (FAILED(hr)) {
  1303. ERR((TB,"ExecOnline: Failed retrieve ClusterID, hr=0x%X", hr));
  1304. }
  1305. }
  1306. else {
  1307. ERR((TB,"ExecOnline: Failed retrieve ServerID, hr=0x%X", hr));
  1308. }
  1309. PostUnpackResultSet:
  1310. pResultRecordSet->Release();
  1311. }
  1312. return hr;
  1313. }
  1314. /****************************************************************************/
  1315. // CTSSessionDirectory::ExecServerOffline
  1316. //
  1317. // Encapsulates creation and execution of the SP_TSSDServerOffline
  1318. // stored procedure on the server.
  1319. /****************************************************************************/
  1320. HRESULT CTSSessionDirectory::ExecServerOffline()
  1321. {
  1322. HRESULT hr;
  1323. ADOCommand *pCommand;
  1324. ADOParameters *pParameters;
  1325. ADORecordset *pResultRecordSet;
  1326. if (m_pConnection != NULL) {
  1327. // Create the command.
  1328. hr = CreateADOStoredProcCommand(L"SP_TSSDServerOffline", &pCommand,
  1329. &pParameters);
  1330. if (SUCCEEDED(hr)) {
  1331. // On an offline request, we need fast turn-around since we're
  1332. // likely being called when the system is going down. Set the
  1333. // timeout value for the command to 2 seconds.
  1334. pCommand->put_CommandTimeout(2);
  1335. hr = AddADOInputDWORDParam(m_ServerID,
  1336. L"ServerID", pCommand, pParameters);
  1337. if (SUCCEEDED(hr)) {
  1338. // Execute the command.
  1339. hr = pCommand->Execute(NULL, NULL, adCmdStoredProc |
  1340. adExecuteNoRecords, &pResultRecordSet);
  1341. if (SUCCEEDED(hr)) {
  1342. TRC2((TB,"ExecOff: Success"));
  1343. }
  1344. else {
  1345. ERR((TB,"Failed exec ServerOffline, hr=0x%X", hr));
  1346. }
  1347. }
  1348. else {
  1349. ERR((TB,"ExecOnOff: Failed adding ServerAddress, hr=0x%X",
  1350. hr));
  1351. }
  1352. pParameters->Release();
  1353. pCommand->Release();
  1354. }
  1355. else {
  1356. ERR((TB,"ExecOff: Failed create command, hr=0x%X", hr));
  1357. }
  1358. }
  1359. else {
  1360. ERR((TB,"ExecOff: Connection invalid"));
  1361. hr = E_FAIL;
  1362. }
  1363. return hr;
  1364. }
  1365. /* ------------------------------------------------------------------------
  1366. Plug-in UI interface for TSCC
  1367. ------------------------------------------------------------------------*/
  1368. /* -------------------------------------------------------------------------------
  1369. * describes the name of this entry in server settins
  1370. * -------------------------------------------------------------------------------
  1371. */
  1372. STDMETHODIMP CTSSessionDirectory::GetAttributeName(/* out */ WCHAR *pwszAttribName)
  1373. {
  1374. TCHAR szAN[256];
  1375. ASSERT((pwszAttribName != NULL),(TB,"NULL attrib ptr"));
  1376. LoadString(g_hInstance, IDS_ATTRIBUTE_NAME, szAN, sizeof(szAN) / sizeof(TCHAR));
  1377. lstrcpy(pwszAttribName, szAN);
  1378. return S_OK;
  1379. }
  1380. /* -------------------------------------------------------------------------------
  1381. * for this component the attribute value would indicate if its enabled or not
  1382. * -------------------------------------------------------------------------------
  1383. */
  1384. STDMETHODIMP CTSSessionDirectory::GetDisplayableValueName(
  1385. /* out */WCHAR *pwszAttribValueName)
  1386. {
  1387. TCHAR szAvn[256];
  1388. ASSERT((pwszAttribValueName != NULL),(TB,"NULL attrib ptr"));
  1389. m_fEnabled = IsSessionDirectoryEnabled();
  1390. if (m_fEnabled)
  1391. LoadString(g_hInstance, IDS_ENABLE, szAvn, sizeof(szAvn) / sizeof(TCHAR));
  1392. else
  1393. LoadString(g_hInstance, IDS_DISABLE, szAvn, sizeof(szAvn) / sizeof(TCHAR));
  1394. lstrcpy(pwszAttribValueName, szAvn);
  1395. return S_OK;
  1396. }
  1397. /* -------------------------------------------------------------------------------
  1398. * Custom UI provided here
  1399. * pdwStatus informs Terminal Service Config to update termsrv
  1400. * -------------------------------------------------------------------------------
  1401. */
  1402. STDMETHODIMP CTSSessionDirectory::InvokeUI( /* in */ HWND hParent , /* out */ PDWORD pdwStatus )
  1403. {
  1404. INT_PTR iRet = DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_DIALOG_SDS),
  1405. hParent, (DLGPROC)CustomUIDlg, (LPARAM)this);
  1406. TRC1((TB,"DialogBox returned 0x%x", iRet));
  1407. *pdwStatus = ( DWORD )iRet;
  1408. return S_OK;
  1409. }
  1410. /* -------------------------------------------------------------------------------
  1411. * Custom menu items -- must be freed by LocalFree
  1412. * this is called everytime the user right clicks the listitem
  1413. * so you can alter the settings ( i.e. enable to disable and vice versa )
  1414. * -------------------------------------------------------------------------------
  1415. */
  1416. STDMETHODIMP CTSSessionDirectory::GetMenuItems(
  1417. /* out */ int *pcbItems,
  1418. /* out */ PMENUEXTENSION *pMex)
  1419. {
  1420. ASSERT((pcbItems != NULL),(TB,"NULL items ptr"));
  1421. *pcbItems = 2;
  1422. *pMex = ( PMENUEXTENSION )LocalAlloc( LMEM_FIXED, *pcbItems * sizeof( MENUEXTENSION ) );
  1423. if( *pMex != NULL )
  1424. {
  1425. // display enable or disable
  1426. if( m_fEnabled )
  1427. {
  1428. LoadString(g_hInstance, IDS_DISABLE, (*pMex)[0].MenuItemName,
  1429. sizeof((*pMex)[0].MenuItemName) / sizeof(WCHAR));
  1430. }
  1431. else
  1432. {
  1433. LoadString(g_hInstance, IDS_ENABLE, (*pMex)[0].MenuItemName,
  1434. sizeof((*pMex)[0].MenuItemName) / sizeof(WCHAR));
  1435. }
  1436. LoadString(g_hInstance, IDS_DESCRIP_ENABLE, (*pMex)[0].StatusBarText,
  1437. sizeof((*pMex)[0].StatusBarText) / sizeof(WCHAR));
  1438. // menu items id -- this id will be passed back to u in ExecMenuCmd
  1439. (*pMex)[0].cmd = IDM_MENU_ENABLE;
  1440. LoadString(g_hInstance, IDS_PROPERTIES, (*pMex)[1].MenuItemName,
  1441. sizeof((*pMex)[1].MenuItemName) / sizeof(WCHAR));
  1442. LoadString(g_hInstance, IDS_DESCRIP_PROPS, (*pMex)[1].StatusBarText,
  1443. sizeof((*pMex)[1].StatusBarText) / sizeof(WCHAR));
  1444. // menu items id -- this id will be passed back to u in ExecMenuCmd
  1445. (*pMex)[1].cmd = IDM_MENU_PROPS;
  1446. return S_OK;
  1447. }
  1448. else
  1449. {
  1450. return E_OUTOFMEMORY;
  1451. }
  1452. }
  1453. /* -------------------------------------------------------------------------------
  1454. * When the user selects a menu item the cmd id is passed to this component.
  1455. * the provider ( which is us )
  1456. * -------------------------------------------------------------------------------
  1457. */
  1458. STDMETHODIMP CTSSessionDirectory::ExecMenuCmd(
  1459. /* in */ UINT cmd,
  1460. /* in */ HWND hParent ,
  1461. /* out*/ PDWORD pdwStatus )
  1462. {
  1463. switch (cmd) {
  1464. case IDM_MENU_ENABLE:
  1465. m_fEnabled = m_fEnabled ? 0 : 1;
  1466. TRC1((TB,"%ws was selected", m_fEnabled ? L"Disable" : L"Enable"));
  1467. if( SetSessionDirectoryState( m_fEnabled ) == ERROR_SUCCESS )
  1468. {
  1469. *pdwStatus = UPDATE_TERMSRV_SESSDIR;
  1470. }
  1471. break;
  1472. case IDM_MENU_PROPS:
  1473. INT_PTR iRet = DialogBoxParam(g_hInstance,
  1474. MAKEINTRESOURCE(IDD_DIALOG_SDS),
  1475. hParent,
  1476. (DLGPROC)CustomUIDlg,
  1477. (LPARAM)this);
  1478. *pdwStatus = ( DWORD )iRet;
  1479. }
  1480. return S_OK;
  1481. }
  1482. /* -------------------------------------------------------------------------------
  1483. * Tscc provides a default help menu item, when selected this method is called
  1484. * if we want tscc to handle ( or provide ) help return any value other than zero
  1485. * for those u can't follow logic return zero if you're handling help.
  1486. * -------------------------------------------------------------------------------
  1487. */
  1488. STDMETHODIMP CTSSessionDirectory::OnHelp( /* out */ int *piRet)
  1489. {
  1490. ASSERT((piRet != NULL),(TB,"NULL ret ptr"));
  1491. *piRet = 0;
  1492. return S_OK;
  1493. }
  1494. /* -------------------------------------------------------------------------------
  1495. * IsSessionDirectoryEnabled returns a bool
  1496. * -------------------------------------------------------------------------------
  1497. */
  1498. BOOL CTSSessionDirectory::IsSessionDirectoryEnabled()
  1499. {
  1500. LONG lRet;
  1501. HKEY hKey;
  1502. DWORD dwEnabled = 0;
  1503. DWORD dwSize = sizeof(DWORD);
  1504. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1505. REG_CONTROL_TSERVER,
  1506. 0,
  1507. KEY_READ,
  1508. &hKey);
  1509. if (lRet == ERROR_SUCCESS)
  1510. {
  1511. lRet = RegQueryValueEx( hKey ,
  1512. REG_TS_SESSDIRACTIVE,
  1513. NULL ,
  1514. NULL ,
  1515. ( LPBYTE )&dwEnabled ,
  1516. &dwSize );
  1517. RegCloseKey( hKey );
  1518. }
  1519. return ( BOOL )dwEnabled;
  1520. }
  1521. /* -------------------------------------------------------------------------------
  1522. * SetSessionDirectoryState - sets SessionDirectoryActive regkey to bVal
  1523. * -------------------------------------------------------------------------------
  1524. */
  1525. DWORD CTSSessionDirectory::SetSessionDirectoryState( BOOL bVal )
  1526. {
  1527. LONG lRet;
  1528. HKEY hKey;
  1529. DWORD dwSize = sizeof( DWORD );
  1530. lRet = RegOpenKeyEx(
  1531. HKEY_LOCAL_MACHINE ,
  1532. REG_CONTROL_TSERVER ,
  1533. 0,
  1534. KEY_WRITE,
  1535. &hKey );
  1536. if (lRet == ERROR_SUCCESS)
  1537. {
  1538. lRet = RegSetValueEx( hKey ,
  1539. REG_TS_SESSDIRACTIVE,
  1540. 0,
  1541. REG_DWORD ,
  1542. ( LPBYTE )&bVal ,
  1543. dwSize );
  1544. RegCloseKey( hKey );
  1545. }
  1546. else
  1547. {
  1548. ErrorMessage( NULL , IDS_ERROR_TEXT3 , ( DWORD )lRet );
  1549. }
  1550. return ( DWORD )lRet;
  1551. }
  1552. /* -------------------------------------------------------------------------------
  1553. * ErrorMessage --
  1554. * -------------------------------------------------------------------------------
  1555. */
  1556. void CTSSessionDirectory::ErrorMessage( HWND hwnd , UINT res , DWORD dwStatus )
  1557. {
  1558. TCHAR tchTitle[ 64 ];
  1559. TCHAR tchText[ 64 ];
  1560. TCHAR tchErrorMessage[ 256 ];
  1561. LPTSTR pBuffer = NULL;
  1562. // report error
  1563. ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1564. FORMAT_MESSAGE_FROM_SYSTEM,
  1565. NULL, //ignored
  1566. ( DWORD )dwStatus, //message ID
  1567. MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ), //message language
  1568. (LPTSTR)&pBuffer, //address of buffer pointer
  1569. 0, //minimum buffer size
  1570. NULL);
  1571. LoadString(g_hInstance, IDS_ERROR_TITLE, tchTitle, sizeof(tchTitle) / sizeof(TCHAR));
  1572. LoadString(g_hInstance, res, tchText, sizeof(tchText) / sizeof(TCHAR));
  1573. wsprintf( tchErrorMessage , tchText , pBuffer );
  1574. ::MessageBox(hwnd, tchErrorMessage, tchTitle, MB_OK | MB_ICONINFORMATION);
  1575. }
  1576. /* -------------------------------------------------------------------------------
  1577. * Custom UI msg handler dealt with here
  1578. * -------------------------------------------------------------------------------
  1579. */
  1580. INT_PTR CALLBACK CustomUIDlg(HWND hwnd, UINT umsg, WPARAM wp, LPARAM lp)
  1581. {
  1582. static BOOL s_fServerNameChanged;
  1583. static BOOL s_fClusterNameChanged;
  1584. static BOOL s_fOpaqueStringChanged;
  1585. static BOOL s_fPreviousButtonState;
  1586. CTSSessionDirectory *pCTssd;
  1587. switch (umsg)
  1588. {
  1589. case WM_INITDIALOG:
  1590. {
  1591. pCTssd = ( CTSSessionDirectory * )lp;
  1592. SetWindowLongPtr( hwnd , DWLP_USER , ( LONG_PTR )pCTssd );
  1593. SendMessage( GetDlgItem( hwnd , IDC_EDIT_SERVERNAME ) ,
  1594. EM_LIMITTEXT ,
  1595. ( WPARAM )64 ,
  1596. 0 );
  1597. SendMessage( GetDlgItem( hwnd , IDC_EDIT_CLUSTERNAME ) ,
  1598. EM_LIMITTEXT ,
  1599. ( WPARAM )64 ,
  1600. 0 );
  1601. SendMessage( GetDlgItem( hwnd , IDC_EDIT_ACCOUNTNAME ) ,
  1602. EM_LIMITTEXT ,
  1603. ( WPARAM )64 ,
  1604. 0 );
  1605. SendMessage( GetDlgItem( hwnd , IDC_EDIT_PASSWORD ) ,
  1606. EM_LIMITTEXT ,
  1607. ( WPARAM )64 ,
  1608. 0 );
  1609. LONG lRet;
  1610. HKEY hKey;
  1611. TCHAR szString[ 256 ];
  1612. DWORD cbData = sizeof( szString );
  1613. lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE ,
  1614. REG_TS_CLUSTERSETTINGS ,
  1615. 0,
  1616. KEY_READ | KEY_WRITE ,
  1617. &hKey );
  1618. if( lRet == ERROR_SUCCESS )
  1619. {
  1620. lRet = RegQueryValueEx(hKey ,
  1621. REG_TS_CLUSTER_STORESERVERNAME,
  1622. NULL ,
  1623. NULL ,
  1624. ( LPBYTE )szString ,
  1625. &cbData );
  1626. if( lRet == ERROR_SUCCESS )
  1627. {
  1628. SetWindowText( GetDlgItem( hwnd , IDC_EDIT_SERVERNAME ) , szString );
  1629. }
  1630. cbData = sizeof( szString );
  1631. lRet = RegQueryValueEx(hKey,
  1632. REG_TS_CLUSTER_CLUSTERNAME,
  1633. NULL,
  1634. NULL,
  1635. (LPBYTE)szString,
  1636. &cbData);
  1637. if( lRet == ERROR_SUCCESS )
  1638. {
  1639. SetWindowText(GetDlgItem(hwnd, IDC_EDIT_CLUSTERNAME), szString);
  1640. }
  1641. cbData = 0;
  1642. lRet = RegQueryValueEx( hKey ,
  1643. REG_TS_CLUSTER_OPAQUESETTINGS,
  1644. NULL ,
  1645. NULL ,
  1646. (LPBYTE)NULL,
  1647. &cbData);
  1648. if( lRet == ERROR_SUCCESS )
  1649. {
  1650. pCTssd->m_pszOpaqueString = ( LPTSTR )LocalAlloc( LMEM_FIXED , cbData );
  1651. if( pCTssd->m_pszOpaqueString != NULL )
  1652. {
  1653. lRet = RegQueryValueEx( hKey ,
  1654. REG_TS_CLUSTER_OPAQUESETTINGS,
  1655. NULL ,
  1656. NULL ,
  1657. (LPBYTE)pCTssd->m_pszOpaqueString ,
  1658. &cbData );
  1659. }
  1660. else
  1661. {
  1662. lRet = ERROR_OUTOFMEMORY;
  1663. }
  1664. }
  1665. if( lRet == ERROR_SUCCESS )
  1666. {
  1667. // jump to user_id
  1668. TCHAR tchUserId[64] = { 0 };
  1669. TCHAR tchPassword[64] = { 0 };
  1670. LPTSTR pszUserId = tchUserId;
  1671. LPTSTR pszPassword = tchPassword;
  1672. FindSqlValue( pCTssd->m_pszOpaqueString , TEXT("User Id"), pszUserId );
  1673. strtrim( &pszUserId );
  1674. FindSqlValue( pCTssd->m_pszOpaqueString , TEXT("Password"), pszPassword );
  1675. strtrim( &pszPassword );
  1676. SetWindowText( GetDlgItem( hwnd , IDC_EDIT_ACCOUNTNAME ) , pszUserId );
  1677. SetWindowText( GetDlgItem( hwnd , IDC_EDIT_PASSWORD ) , pszPassword );
  1678. }
  1679. RegCloseKey(hKey);
  1680. }
  1681. else
  1682. {
  1683. if( pCTssd != NULL )
  1684. {
  1685. pCTssd->ErrorMessage( hwnd , IDS_ERROR_TEXT , ( DWORD )lRet );
  1686. }
  1687. EndDialog(hwnd, lRet);
  1688. }
  1689. if( pCTssd != NULL )
  1690. {
  1691. BOOL bEnable;
  1692. bEnable = pCTssd->IsSessionDirectoryEnabled();
  1693. CheckDlgButton( hwnd , IDC_CHECK_ENABLE , bEnable ? BST_CHECKED : BST_UNCHECKED );
  1694. s_fPreviousButtonState = bEnable;
  1695. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_SERVERNAME), bEnable);
  1696. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_CLUSTERNAME), bEnable);
  1697. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_ACCOUNTNAME), bEnable);
  1698. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_PASSWORD), bEnable);
  1699. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_SQLNAME), bEnable);
  1700. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_CLUSTERNAME), bEnable);
  1701. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_SQLACCOUNT), bEnable);
  1702. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_SQLPWD), bEnable);
  1703. }
  1704. s_fServerNameChanged = FALSE;
  1705. s_fClusterNameChanged = FALSE;
  1706. s_fOpaqueStringChanged = FALSE;
  1707. }
  1708. break;
  1709. case WM_COMMAND:
  1710. if( LOWORD( wp ) == IDCANCEL )
  1711. {
  1712. pCTssd = ( CTSSessionDirectory * )GetWindowLongPtr( hwnd , DWLP_USER );
  1713. if( pCTssd->m_pszOpaqueString != NULL )
  1714. {
  1715. LocalFree( pCTssd->m_pszOpaqueString );
  1716. }
  1717. EndDialog(hwnd , 0);
  1718. }
  1719. else if( LOWORD( wp ) == IDOK )
  1720. {
  1721. BOOL bEnabled;
  1722. DWORD dwRetStatus = 0;
  1723. pCTssd = ( CTSSessionDirectory * )GetWindowLongPtr(hwnd, DWLP_USER);
  1724. bEnabled = IsDlgButtonChecked( hwnd , IDC_CHECK_ENABLE ) == BST_CHECKED;
  1725. if( bEnabled != s_fPreviousButtonState )
  1726. {
  1727. DWORD dwStatus;
  1728. TRC1((TB,"EnableButtonChanged"));
  1729. dwStatus = pCTssd->SetSessionDirectoryState( bEnabled );
  1730. if( dwStatus != ERROR_SUCCESS )
  1731. {
  1732. return 0;
  1733. }
  1734. dwRetStatus = UPDATE_TERMSRV_SESSDIR;
  1735. }
  1736. if( s_fServerNameChanged || s_fClusterNameChanged || s_fOpaqueStringChanged )
  1737. {
  1738. HKEY hKey;
  1739. LONG lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE ,
  1740. REG_TS_CLUSTERSETTINGS ,
  1741. 0,
  1742. KEY_READ | KEY_WRITE ,
  1743. &hKey );
  1744. if( lRet == ERROR_SUCCESS )
  1745. {
  1746. TCHAR szName[ 64 ];
  1747. if( s_fServerNameChanged )
  1748. {
  1749. TRC1((TB,"SQLServerNameChanged" )) ;
  1750. GetWindowText( GetDlgItem( hwnd , IDC_EDIT_SERVERNAME ) , szName , sizeof( szName ) / sizeof( TCHAR ) );
  1751. RegSetValueEx( hKey ,
  1752. REG_TS_CLUSTER_STORESERVERNAME,
  1753. 0,
  1754. REG_SZ,
  1755. ( CONST LPBYTE )szName ,
  1756. sizeof( szName ) );
  1757. }
  1758. if( s_fClusterNameChanged )
  1759. {
  1760. TRC1((TB,"ClusterNameChanged"));
  1761. GetWindowText( GetDlgItem( hwnd , IDC_EDIT_CLUSTERNAME ) , szName , sizeof( szName ) / sizeof( TCHAR ) );
  1762. RegSetValueEx( hKey ,
  1763. REG_TS_CLUSTER_CLUSTERNAME,
  1764. 0,
  1765. REG_SZ,
  1766. ( CONST LPBYTE )szName ,
  1767. sizeof( szName ) );
  1768. }
  1769. if( s_fOpaqueStringChanged )
  1770. {
  1771. TRC1((TB,"OpaqueStringChanged" )) ;
  1772. LPTSTR pszNewOpaqueString = NULL;
  1773. LPTSTR pszName = NULL;
  1774. GetWindowText( GetDlgItem( hwnd , IDC_EDIT_ACCOUNTNAME ) , szName , sizeof( szName ) / sizeof( TCHAR ) );
  1775. pszName = szName;
  1776. strtrim( &pszName );
  1777. ModifySqlValue( &pCTssd->m_pszOpaqueString , L"User Id" , pszName );
  1778. GetWindowText( GetDlgItem( hwnd , IDC_EDIT_PASSWORD ) , szName , sizeof( szName ) / sizeof( TCHAR ) );
  1779. pszName = szName;
  1780. strtrim( &pszName );
  1781. if( ModifySqlValue( &pCTssd->m_pszOpaqueString , L"Password" , pszName ) != NULL )
  1782. {
  1783. RegSetValueEx( hKey ,
  1784. REG_TS_CLUSTER_OPAQUESETTINGS,
  1785. 0,
  1786. REG_SZ,
  1787. ( CONST LPBYTE )pCTssd->m_pszOpaqueString ,
  1788. lstrlen( pCTssd->m_pszOpaqueString ) * sizeof( TCHAR ) );
  1789. }
  1790. }
  1791. RegCloseKey(hKey);
  1792. dwRetStatus = UPDATE_TERMSRV_SESSDIR;
  1793. }
  1794. else
  1795. {
  1796. pCTssd->ErrorMessage(hwnd , IDS_ERROR_TEXT2 , (DWORD)lRet);
  1797. return 0;
  1798. }
  1799. }
  1800. if( pCTssd->m_pszOpaqueString != NULL )
  1801. {
  1802. LocalFree( pCTssd->m_pszOpaqueString );
  1803. }
  1804. EndDialog( hwnd , ( INT_PTR )dwRetStatus );
  1805. }
  1806. else
  1807. {
  1808. switch (HIWORD(wp))
  1809. {
  1810. case EN_CHANGE:
  1811. if( LOWORD( wp ) == IDC_EDIT_SERVERNAME )
  1812. {
  1813. s_fServerNameChanged = TRUE;
  1814. }
  1815. else if( LOWORD( wp ) == IDC_EDIT_CLUSTERNAME )
  1816. {
  1817. s_fClusterNameChanged = TRUE;
  1818. }
  1819. else if( LOWORD( wp ) == IDC_EDIT_ACCOUNTNAME || LOWORD( wp ) == IDC_EDIT_PASSWORD )
  1820. {
  1821. s_fOpaqueStringChanged = TRUE;
  1822. }
  1823. break;
  1824. case BN_CLICKED:
  1825. if( LOWORD( wp ) == IDC_CHECK_ENABLE)
  1826. {
  1827. BOOL bEnable;
  1828. if( IsDlgButtonChecked( hwnd , IDC_CHECK_ENABLE ) == BST_CHECKED )
  1829. {
  1830. // enabled all controls
  1831. bEnable = TRUE;
  1832. }
  1833. else
  1834. {
  1835. // disable all controls
  1836. bEnable = FALSE;
  1837. }
  1838. // set flags
  1839. s_fServerNameChanged = bEnable;
  1840. s_fClusterNameChanged = bEnable;
  1841. s_fOpaqueStringChanged = bEnable;
  1842. EnableWindow( GetDlgItem( hwnd , IDC_EDIT_SERVERNAME ) , bEnable );
  1843. EnableWindow( GetDlgItem( hwnd , IDC_EDIT_CLUSTERNAME ) , bEnable );
  1844. EnableWindow( GetDlgItem( hwnd , IDC_EDIT_ACCOUNTNAME ) , bEnable );
  1845. EnableWindow( GetDlgItem( hwnd , IDC_EDIT_PASSWORD ) , bEnable );
  1846. EnableWindow( GetDlgItem( hwnd , IDC_STATIC_SQLNAME ) , bEnable );
  1847. EnableWindow( GetDlgItem( hwnd , IDC_STATIC_CLUSTERNAME ) , bEnable );
  1848. EnableWindow( GetDlgItem( hwnd , IDC_STATIC_SQLACCOUNT ) , bEnable );
  1849. EnableWindow( GetDlgItem( hwnd , IDC_STATIC_SQLPWD ) , bEnable );
  1850. }
  1851. break;
  1852. }
  1853. }
  1854. break;
  1855. }
  1856. return 0;
  1857. }
  1858. /********************************************************************************************
  1859. [in ] lpString is the buffer containing the OpaqueSettings
  1860. [in ] lpKeyName is the field name within the OpaqueSettings string
  1861. [out] pszValue is a buffer that will contain the field name value
  1862. Ret: None
  1863. *******************************************************************************************/
  1864. void FindSqlValue(LPTSTR lpString, LPTSTR lpKeyName, LPTSTR pszValue)
  1865. {
  1866. int i;
  1867. LPTSTR lpszStart = lpString;
  1868. LPTSTR lpszTemp;
  1869. UINT nKeyName;
  1870. if( lpString != NULL && lpKeyName != NULL )
  1871. {
  1872. // find field name
  1873. lpString = FindField( lpString , lpKeyName );
  1874. if( *lpString != 0 )
  1875. {
  1876. i = 0;
  1877. while( *lpString != 0 && *lpString != ( TCHAR )';' )
  1878. {
  1879. pszValue[i] = *lpString;
  1880. i++;
  1881. lpString++;
  1882. }
  1883. pszValue[ i ] = 0;
  1884. }
  1885. }
  1886. }
  1887. /********************************************************************************************
  1888. [in/out ] lpszOpaqueSettings is the buffer containing the OpaqueSettings
  1889. [in ] lpKeyName is the field name within the OpaqueSettings string
  1890. [in ] lpszNewValue contains the value that will replace the original value in the field
  1891. Ret: A new OpaqueSetting string is constructed and must be freed with LocalFree
  1892. ********************************************************************************************/
  1893. LPTSTR ModifySqlValue( LPTSTR* lppszOpaqueSettings , LPTSTR lpszKeyName , LPTSTR lpszNewValue )
  1894. {
  1895. LPTSTR szEndPos = NULL;
  1896. LPTSTR szSecondPos = NULL;
  1897. LPTSTR pszNewSettings = NULL;
  1898. LPTSTR lpszOpaqueSettings = *lppszOpaqueSettings;
  1899. LPTSTR pszTempSettings = lpszOpaqueSettings;
  1900. UINT cbSize = 0;
  1901. //a ) find value
  1902. //b ) set pos2 after ';'
  1903. //c ) set endpos1 after '=' to null
  1904. //d ) create a buffer the length of first string + value + ; + second string
  1905. //e ) strcpy first string + value + ; + second string
  1906. //f ) return buffer
  1907. if( lpszKeyName != NULL && lpszOpaqueSettings != NULL )
  1908. {
  1909. szEndPos = FindField( lpszOpaqueSettings , lpszKeyName );
  1910. if( *szEndPos != 0 )
  1911. {
  1912. lpszOpaqueSettings = szEndPos;
  1913. while( *lpszOpaqueSettings != 0 )
  1914. {
  1915. if( *lpszOpaqueSettings == ( TCHAR )';' )
  1916. {
  1917. szSecondPos = lpszOpaqueSettings + 1;
  1918. break;
  1919. }
  1920. lpszOpaqueSettings++;
  1921. }
  1922. *szEndPos = 0;
  1923. cbSize = lstrlen( pszTempSettings );
  1924. cbSize += lstrlen( lpszNewValue );
  1925. cbSize += 2; // for the semicolon and null
  1926. if( szSecondPos != NULL && *szSecondPos != 0 )
  1927. {
  1928. cbSize += lstrlen( szSecondPos );
  1929. }
  1930. pszNewSettings = ( LPTSTR )LocalAlloc( LMEM_FIXED , cbSize * sizeof( TCHAR ) );
  1931. if( pszNewSettings != NULL )
  1932. {
  1933. lstrcpy( pszNewSettings , pszTempSettings );
  1934. lstrcat( pszNewSettings , lpszNewValue );
  1935. lstrcat( pszNewSettings , TEXT( ";" ) );
  1936. if( szSecondPos != NULL )
  1937. {
  1938. lstrcat( pszNewSettings , szSecondPos );
  1939. }
  1940. LocalFree( pszTempSettings );
  1941. *lppszOpaqueSettings = pszNewSettings;
  1942. }
  1943. }
  1944. else
  1945. {
  1946. // we're here because either the field name didnot exist or is unattainable
  1947. // so we're slapping the field name and value at the end.
  1948. cbSize = lstrlen( pszTempSettings );
  1949. // add the size of the keyname and = and ;
  1950. cbSize += lstrlen( lpszKeyName ) + 2;
  1951. // add the new value
  1952. cbSize += lstrlen( lpszNewValue ) + 1;
  1953. pszNewSettings = ( LPTSTR )LocalAlloc( LMEM_FIXED , cbSize * sizeof( TCHAR ) );
  1954. if( pszNewSettings != NULL )
  1955. {
  1956. lstrcpy( pszNewSettings , pszTempSettings );
  1957. lstrcat( pszNewSettings , lpszKeyName );
  1958. lstrcat( pszNewSettings , TEXT( "=" ) );
  1959. lstrcat( pszNewSettings , lpszNewValue );
  1960. lstrcat( pszNewSettings , TEXT( ";" ) );
  1961. LocalFree( pszTempSettings );
  1962. *lppszOpaqueSettings = pszNewSettings;
  1963. }
  1964. }
  1965. }
  1966. return pszNewSettings;
  1967. }
  1968. /********************************************************************************************
  1969. FindField -- greps the OpaqueString passed in
  1970. pszString and searches for field name in pszKeyName
  1971. [ in ] pszString - OpaqueString
  1972. [ in ] pszKeyName - field name
  1973. ret: the position of the field value ( after the " = " )
  1974. *******************************************************************************************/
  1975. LPTSTR FindField( LPTSTR pszString , LPTSTR pszKeyName )
  1976. {
  1977. LPTSTR lpszStart = pszString;
  1978. LPTSTR lpszTemp;
  1979. LPTSTR lpszFieldName;
  1980. UINT nKeyName;
  1981. // find field name
  1982. nKeyName = lstrlen( pszKeyName );
  1983. while( *pszString != 0 )
  1984. {
  1985. while( *pszString != 0 && *pszString != ( TCHAR )'=' )
  1986. {
  1987. pszString++;
  1988. }
  1989. // ok move backwards to check for name
  1990. if( *pszString != 0 )
  1991. {
  1992. lpszTemp = pszString - 1;
  1993. while( lpszStart <= lpszTemp )
  1994. {
  1995. if( IsCharAlphaNumeric( *lpszTemp ) )
  1996. {
  1997. break;
  1998. }
  1999. lpszTemp--;
  2000. }
  2001. lpszFieldName = ( lpszTemp - nKeyName + 1 );
  2002. if( lpszStart <= lpszFieldName && _tcsncicmp( lpszFieldName , pszKeyName , nKeyName ) == 0 )
  2003. {
  2004. // found the name skip '='
  2005. pszString++;
  2006. break;
  2007. }
  2008. }
  2009. pszString++;
  2010. }
  2011. return pszString;
  2012. }
  2013. /*********************************************************************************************
  2014. * borrowed from Ting Cai (tingcai) with slight modifications
  2015. * net\upnp\ssdp\common\ssdpparser\parser.cpp
  2016. *
  2017. ********************************************************************************************/
  2018. VOID strtrim( TCHAR **pszStr)
  2019. {
  2020. TCHAR *end;
  2021. TCHAR *begin;
  2022. begin = *pszStr;
  2023. end = begin + lstrlen( *pszStr ) - 1;
  2024. while (*begin == ( TCHAR )' ' || *begin == ( TCHAR )'\t')
  2025. {
  2026. begin++;
  2027. }
  2028. *pszStr = begin;
  2029. while (*end == ( TCHAR )' ' || *end == ( TCHAR )'\t')
  2030. {
  2031. end--;
  2032. }
  2033. *(end+1) = '\0';
  2034. }