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.

713 lines
20 KiB

  1. // SFUCommon.cpp : Implementation of CSFUCommon
  2. #include "stdafx.h"
  3. #include "sfucom.h"
  4. #include "SFUCommon.h"
  5. #include <winsock.h>
  6. #include <lm.h>
  7. #include <shlwapi.h>
  8. #include <commctrl.h>
  9. #include <OleAuto.h >
  10. #include <windns.h> //For DNS_MAX_NAME_BUFFER_LENGTH definition
  11. #include <string.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #define WINLOGONNT_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
  15. #define NETLOGONPARAMETERS_KEY TEXT("System\\CurrentControlSet\\Services\\Netlogon\\Parameters")
  16. #define TRUSTEDDOMAINLIST_VALUE TEXT("TrustedDomainList")
  17. #define CACHEPRIMARYDOMAIN_VALUE TEXT("CachePrimaryDomain")
  18. #define CACHETRUSTEDDOMAINS_VALUE TEXT("CacheTrustedDomains")
  19. #define DOMAINCACHE_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\DomainCache")
  20. #define DCACHE_VALUE TEXT("DCache")
  21. #define WINLOGONNT_DCACHE_KEY TEXT("DCache")
  22. /////////////////////////////////////////////////////////////////////////////
  23. // CSFUCommon
  24. BOOL Get_Inet_Address(struct sockaddr_in *addr, char *host)
  25. {
  26. register struct hostent *hp;
  27. WORD wVersionRequested; //INGR
  28. WSADATA wsaData; //INGR
  29. // Start up winsock
  30. wVersionRequested = MAKEWORD( 1, 1 ); //INGR
  31. if (WSAStartup(wVersionRequested, &wsaData) != 0) { //INGR
  32. return (FALSE);
  33. }
  34. // Get the address
  35. memset(addr, 0, sizeof(addr));
  36. //bzero((TCHAR *)addr, sizeof *addr);
  37. addr->sin_addr.s_addr = (u_long) inet_addr(host);
  38. if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
  39. if ((hp = gethostbyname(host)) == NULL) {
  40. return (FALSE);
  41. }
  42. memcpy(&addr->sin_addr,hp->h_addr, hp->h_length );
  43. //bcopy(hp->h_addr, (TCHAR *)&addr->sin_addr, hp->h_length);
  44. }
  45. addr->sin_family = AF_INET;
  46. WSACleanup(); //INGR
  47. return (TRUE);
  48. }
  49. STDMETHODIMP CSFUCommon::IsValidMachine(BSTR bstrMachine,BOOL *fValid)
  50. {
  51. // TODO: Add your implementation code here
  52. struct sockaddr_in addr;
  53. *fValid = false;
  54. char * nodeName = (char *) malloc(wcslen(bstrMachine)+1);
  55. if(!nodeName)
  56. return(E_OUTOFMEMORY);
  57. int cbMultiByte = WideCharToMultiByte( GetACP(),NULL,bstrMachine,-1,nodeName,
  58. 0,NULL,NULL);
  59. WideCharToMultiByte( GetACP(),NULL,bstrMachine,-1,nodeName,
  60. cbMultiByte,NULL,NULL);
  61. if (Get_Inet_Address (&addr, nodeName))
  62. *fValid = TRUE;
  63. if(nodeName)
  64. free(nodeName);
  65. return S_OK;
  66. }
  67. STDMETHODIMP CSFUCommon::IsTrustedDomain(BSTR bstrDomain, BOOL * fValid)
  68. {
  69. // TODO: Add your implementation code here
  70. return S_OK;
  71. }
  72. STDMETHODIMP CSFUCommon::ConvertUTCtoLocal(BSTR bUTCYear, BSTR bUTCMonth, BSTR bUTCDayOfWeek, BSTR bUTCDay, BSTR bUTCHour, BSTR bUTCMinute, BSTR bUTCSecond, BSTR * bLocalDate)
  73. {
  74. // TODO: Add your implementation code here
  75. SYSTEMTIME UniversalTime, LocalTime;
  76. DATE dtCurrent;
  77. DWORD dwFlags = VAR_VALIDDATE;
  78. UDATE uSysDate; //local time
  79. *bLocalDate = NULL;
  80. // The values can't be > MAXWORD, so cast away -- BaskarK
  81. UniversalTime.wYear = (WORD) _wtoi(bUTCYear);
  82. UniversalTime.wMonth = (WORD) _wtoi(bUTCMonth);
  83. UniversalTime.wDayOfWeek = (WORD) _wtoi(bUTCDayOfWeek);
  84. UniversalTime.wDay = (WORD) _wtoi(bUTCDay);
  85. UniversalTime.wDay = (WORD) _wtoi(bUTCDay);
  86. UniversalTime.wMinute = (WORD) _wtoi(bUTCMinute);
  87. UniversalTime.wHour = (WORD) _wtoi(bUTCHour);
  88. UniversalTime.wSecond = (WORD) _wtoi(bUTCSecond);
  89. UniversalTime.wMilliseconds = (WORD) 0;
  90. SystemTimeToTzSpecificLocalTime(NULL,&UniversalTime,&LocalTime);
  91. memcpy(&uSysDate.st,&LocalTime,sizeof(SYSTEMTIME));
  92. if( VarDateFromUdate( &uSysDate, dwFlags, &dtCurrent ) != S_OK )
  93. goto Error;
  94. VarBstrFromDate( dtCurrent,
  95. MAKELCID( MAKELANGID( LANG_NEUTRAL, SUBLANG_SYS_DEFAULT ), SORT_DEFAULT ),
  96. LOCALE_NOUSEROVERRIDE, bLocalDate);
  97. Error:
  98. return S_OK;
  99. }
  100. STDMETHODIMP CSFUCommon::get_mode(short * pVal)
  101. {
  102. // TODO: Add your implementation code here
  103. return S_OK;
  104. }
  105. STDMETHODIMP CSFUCommon::put_mode(short newVal)
  106. {
  107. // TODO: Add your implementation code here
  108. return S_OK;
  109. }
  110. STDMETHODIMP CSFUCommon::LoadNTDomainList()
  111. {
  112. // TODO: Add your implementation code here
  113. int dwSize=0, dwType=0;
  114. DWORD nIndex = 0;
  115. LPTSTR lpComputer = NULL, lpDomains = NULL, lpPrimary = NULL;
  116. LPBYTE lpBuffer = NULL;
  117. //MessageBoxW(NULL, (LPWSTR)L"LoadNTDomainList", L"LoadNTDomainList1", MB_OK);
  118. //
  119. // Add all trusted domains to the list
  120. //
  121. dwSize = GetTrustedDomainList(&lpDomains, &lpPrimary);
  122. //
  123. // free previous values
  124. //
  125. FreeStringList(&m_slNTDomains);
  126. //
  127. // initialize list again
  128. //
  129. m_slNTDomains.count = 0;
  130. //
  131. // two for primary domain
  132. // and this computer
  133. // one more in case dwSize is -1
  134. // hence total is 3
  135. //
  136. m_slNTDomains.strings = new LPTSTR[dwSize + 3];
  137. ATLASSERT(m_slNTDomains.strings != NULL);
  138. ZeroMemory(m_slNTDomains.strings, (dwSize + 3)*sizeof(LPTSTR));
  139. if((dwSize > 0) && lpDomains)
  140. {
  141. LPTSTR ptr = lpDomains;
  142. //
  143. // add domains to our list
  144. //
  145. while(*ptr)
  146. {
  147. ptr = _tcsupr(ptr);
  148. m_slNTDomains.strings[m_slNTDomains.count] = new TCHAR[_tcslen(ptr) + 1];
  149. ATLASSERT(m_slNTDomains.strings[m_slNTDomains.count] != NULL);
  150. ZeroMemory(m_slNTDomains.strings[m_slNTDomains.count], (_tcslen(ptr) + 1)*sizeof(TCHAR));
  151. _tcscpy(m_slNTDomains.strings[m_slNTDomains.count], ptr);
  152. ptr += _tcslen(ptr) + 1;
  153. m_slNTDomains.count++;
  154. }
  155. delete [] lpDomains;
  156. lpDomains = NULL;
  157. }
  158. if(lpPrimary && *lpPrimary)
  159. {
  160. lpPrimary = _tcsupr(lpPrimary);
  161. for(nIndex=0;nIndex<m_slNTDomains.count;nIndex++)
  162. {
  163. if(!_tcsicmp(lpPrimary, m_slNTDomains.strings[nIndex]))
  164. break;
  165. }
  166. if(nIndex == m_slNTDomains.count)
  167. {
  168. //
  169. // lpPrimary was not in the list of domains that we
  170. // got. add it.
  171. //
  172. m_slNTDomains.strings[m_slNTDomains.count] = new TCHAR[_tcslen(lpPrimary) + 1];
  173. ATLASSERT(m_slNTDomains.strings[m_slNTDomains.count] != NULL);
  174. ZeroMemory(m_slNTDomains.strings[m_slNTDomains.count], (_tcslen(lpPrimary) + 1)*sizeof(TCHAR));
  175. _tcscpy(m_slNTDomains.strings[m_slNTDomains.count], lpPrimary);
  176. m_slNTDomains.count++;
  177. }
  178. }
  179. //
  180. // Add our computer to be selected if this machine is not the
  181. // domain controler (which should already be in the list)
  182. //
  183. NetServerGetInfo(NULL, 101, &lpBuffer);
  184. if(((LPSERVER_INFO_101)lpBuffer)->sv101_type &
  185. ((DWORD)SV_TYPE_DOMAIN_CTRL | (DWORD)SV_TYPE_DOMAIN_BAKCTRL))
  186. {
  187. /*
  188. we got this computer as one of the domains. no need to add it to the
  189. list again. just do nothing.
  190. */
  191. ;
  192. }
  193. else
  194. {
  195. TCHAR szName[MAX_PATH + 2];
  196. ZeroMemory(szName, sizeof(szName));
  197. DWORD dwLen = sizeof(szName);
  198. if(GetComputerName(szName + 2, &dwLen))
  199. {
  200. szName[0] = TEXT('\\');
  201. szName[1] = TEXT('\\');
  202. //
  203. // add this also to our list of domains
  204. //
  205. m_slNTDomains.strings[m_slNTDomains.count] = new TCHAR[_tcslen(szName) + 1];
  206. ATLASSERT(m_slNTDomains.strings[m_slNTDomains.count] != NULL);
  207. ZeroMemory(m_slNTDomains.strings[m_slNTDomains.count], (_tcslen(szName) + 1)*sizeof(TCHAR));
  208. _tcscpy(m_slNTDomains.strings[m_slNTDomains.count], szName);
  209. m_slNTDomains.count++;
  210. }
  211. }
  212. if(lpBuffer)
  213. {
  214. NetApiBufferFree(lpBuffer);
  215. }
  216. if(lpPrimary)
  217. {
  218. delete [] lpPrimary;
  219. }
  220. return S_OK;
  221. }
  222. int CSFUCommon::GetTrustedDomainList(LPTSTR *list, LPTSTR *primary)
  223. {
  224. BOOL stat = TRUE;
  225. DWORD ret=0, size=0, type=0;
  226. LPTSTR cache = NULL, dcache = NULL, string = NULL, trusted = NULL;
  227. HKEY hKey=NULL;
  228. CRegKey key;
  229. DWORD dwIndex = 0;
  230. LPTSTR lpValueName = NULL;
  231. DWORD cbValueName = 0;
  232. STRING_LIST slValues = {0, NULL};
  233. *list = NULL;
  234. if(key.Open(HKEY_LOCAL_MACHINE, WINLOGONNT_KEY) == ERROR_SUCCESS)
  235. {
  236. size = 0;
  237. if(key.QueryValue(*primary, CACHEPRIMARYDOMAIN_VALUE, &size) == ERROR_SUCCESS)
  238. {
  239. *primary = new TCHAR[size+1];
  240. ATLASSERT(primary != NULL);
  241. if(*primary)
  242. {
  243. ZeroMemory(*primary, (size+1)*sizeof(TCHAR));
  244. if(key.QueryValue(*primary, CACHEPRIMARYDOMAIN_VALUE, &size) != ERROR_SUCCESS)
  245. {
  246. delete [] *primary;
  247. *primary = NULL;
  248. return FALSE;
  249. }
  250. else
  251. {
  252. key.Close();
  253. }
  254. }
  255. }
  256. else
  257. {
  258. key.Close();
  259. return -1;
  260. }
  261. }
  262. else
  263. {
  264. return -1;
  265. }
  266. //
  267. // Get trusted domains. In NT40 the CacheTrustedDomains
  268. // under winlogon doesn't exist. I did find that Netlogon has a field
  269. // called TrustedDomainList which seems to be there in both NT351 and NT40.
  270. // Winlogon has a field called DCache which seem to cache the trusted
  271. // domains. I'm going to check Netlogon:TrustedDomainList first. If it
  272. // fails: Check for Winlogon:CacheTrustedDomains then Winlogon:DCache.
  273. // Warning -- Winlogon:CacheTrustedDomains is a REG_SZ and
  274. // Netlogon:TrustedDomainList and Winlogon:DCache are REG_MULTI_SZ.
  275. // Note -- see 4.0 Resource Kit documentation regarding some of these
  276. // values
  277. //
  278. if(key.Open(HKEY_LOCAL_MACHINE, NETLOGONPARAMETERS_KEY) == ERROR_SUCCESS)
  279. {
  280. size = 0;
  281. if(key.QueryValue(trusted, TRUSTEDDOMAINLIST_VALUE, &size) == ERROR_SUCCESS)
  282. {
  283. trusted = new TCHAR[size + 1];
  284. ATLASSERT(trusted != NULL);
  285. if(trusted)
  286. {
  287. ZeroMemory(trusted, (size+1)*sizeof(TCHAR));
  288. if(key.QueryValue(trusted, TRUSTEDDOMAINLIST_VALUE, &size) != ERROR_SUCCESS)
  289. {
  290. key.Close();
  291. delete [] trusted;
  292. //trusted = NULL;
  293. *list = NULL;
  294. //goto ABORT;
  295. }
  296. else
  297. {
  298. *list = trusted;
  299. key.Close();
  300. }
  301. }
  302. else
  303. {
  304. key.Close();
  305. goto ABORT;
  306. }
  307. }
  308. else
  309. {
  310. key.Close();
  311. *list = NULL;
  312. }
  313. }
  314. if(!(*list) && (key.Open(HKEY_LOCAL_MACHINE, WINLOGONNT_KEY) == ERROR_SUCCESS))
  315. {
  316. size = 0;
  317. if(key.QueryValue(cache, CACHETRUSTEDDOMAINS_VALUE, &size) == ERROR_SUCCESS)
  318. {
  319. cache = new TCHAR[size + 1];
  320. ATLASSERT(cache != NULL);
  321. if(cache)
  322. {
  323. ZeroMemory(cache, size);
  324. if(key.QueryValue(cache, CACHETRUSTEDDOMAINS_VALUE, &size) == ERROR_SUCCESS)
  325. {
  326. //
  327. // comma separated list
  328. //
  329. LPTSTR lpComma = NULL;
  330. LPTSTR lpDelim = TEXT(",");
  331. lpComma = _tcstok(cache, lpDelim);
  332. while(lpComma)
  333. {
  334. lpComma = _tcstok(NULL, lpDelim);
  335. }
  336. *list = cache;
  337. }
  338. else
  339. {
  340. key.Close();
  341. delete [] cache;
  342. *list = NULL;
  343. }
  344. }
  345. else
  346. {
  347. key.Close();
  348. goto ABORT;
  349. }
  350. }
  351. else
  352. {
  353. *list = NULL;
  354. key.Close();
  355. }
  356. }
  357. if(!(*list) && (key.Open(HKEY_LOCAL_MACHINE, WINLOGONNT_KEY) == ERROR_SUCCESS))
  358. {
  359. size = 0;
  360. if(key.QueryValue(trusted, DCACHE_VALUE, &size) == ERROR_SUCCESS)
  361. {
  362. trusted = new TCHAR[size + 1];
  363. ATLASSERT(trusted != NULL);
  364. if(trusted)
  365. {
  366. if(key.QueryValue(trusted, DCACHE_VALUE, &size) == ERROR_SUCCESS)
  367. {
  368. *list = trusted;
  369. }
  370. else
  371. {
  372. key.Close();
  373. delete [] trusted;
  374. *list = NULL;
  375. }
  376. }
  377. else
  378. {
  379. key.Close();
  380. goto ABORT;
  381. }
  382. }
  383. else
  384. {
  385. key.Close();
  386. *list = NULL;
  387. }
  388. }
  389. if(!(*list) && (key.Open(HKEY_LOCAL_MACHINE, DOMAINCACHE_KEY) == ERROR_SUCCESS))
  390. {
  391. size = 0;
  392. TCHAR * pszTemp = NULL;
  393. TCHAR szTemp[MAX_PATH];
  394. DWORD dwNumberOfValues = 0;
  395. DWORD dwIndex = 0;
  396. DWORD dwCharCount = MAX_PATH;
  397. HRESULT hrResult = ERROR_SUCCESS;
  398. hKey = HKEY(key);
  399. //
  400. // first find out how many values are present
  401. //
  402. hrResult = RegQueryInfoKey(
  403. hKey, //handle of key to query
  404. NULL, // address of buffer for class string
  405. NULL, // address of size of class string buffer
  406. NULL, // reserved
  407. NULL, // address of buffer for number of subkeys
  408. NULL, // address of buffer for longest subkey name length
  409. NULL, // address of buffer for longest class string length
  410. &dwNumberOfValues, // address of buffer for number of value entries
  411. NULL, // address of buffer for longest value name length
  412. NULL, // address of buffer for longest value data length
  413. NULL, // address of buffer for security descriptor length
  414. NULL // address of buffer for last write time
  415. );
  416. if(hrResult != ERROR_SUCCESS)
  417. goto ABORT;
  418. slValues.count = dwNumberOfValues;
  419. slValues.strings = new LPTSTR[slValues.count];
  420. ATLASSERT(slValues.strings != NULL);
  421. if(slValues.strings == NULL)
  422. goto ABORT;
  423. ZeroMemory(slValues.strings, slValues.count * sizeof(LPTSTR));
  424. for(dwIndex = 0;dwIndex<dwNumberOfValues;dwIndex++)
  425. {
  426. dwCharCount = MAX_PATH;
  427. if(RegEnumValue(hKey, dwIndex, szTemp, &dwCharCount, NULL, NULL, NULL, NULL) == ERROR_NO_MORE_ITEMS)
  428. break;
  429. slValues.strings[dwIndex] = new TCHAR[dwCharCount+1];
  430. ATLASSERT(slValues.strings[dwIndex] != NULL);
  431. if(slValues.strings[dwIndex] == NULL)
  432. goto ABORT;
  433. ZeroMemory(slValues.strings[dwIndex], (dwCharCount+1) * sizeof(TCHAR));
  434. _tcscpy(slValues.strings[dwIndex], szTemp);
  435. // add up the return buffer size
  436. size += dwCharCount+1;
  437. }
  438. if(dwNumberOfValues > 0)
  439. {
  440. trusted = new TCHAR[size + 1];
  441. ATLASSERT(trusted != NULL);
  442. if(trusted == NULL)
  443. {
  444. goto ABORT;
  445. }
  446. ZeroMemory(trusted, (size+1)*sizeof(TCHAR));
  447. pszTemp = trusted;
  448. for(dwIndex = 0;dwIndex<slValues.count;dwIndex++)
  449. {
  450. _tcscpy(pszTemp, slValues.strings[dwIndex]);
  451. pszTemp += _tcslen(slValues.strings[dwIndex]) + 1;
  452. }
  453. }
  454. *list = trusted;
  455. size = dwNumberOfValues;
  456. }
  457. goto Done;
  458. ABORT:
  459. if(*primary != NULL)
  460. {
  461. delete [] *primary;
  462. *primary = NULL;
  463. }
  464. if(trusted != NULL)
  465. {
  466. delete [] trusted;
  467. trusted = NULL;
  468. }
  469. if(cache != NULL)
  470. {
  471. delete [] cache;
  472. cache = NULL;
  473. }
  474. return -1;
  475. Done:
  476. if(hKey != NULL)
  477. {
  478. RegCloseKey(hKey);
  479. hKey = NULL;
  480. key.m_hKey = NULL;
  481. }
  482. FreeStringList(&slValues);
  483. return size;
  484. }
  485. void CSFUCommon::FreeStringList(PSTRING_LIST pList)
  486. {
  487. if(pList && pList->count && pList->strings)
  488. {
  489. DWORD i;
  490. for(i=0; i < pList->count; ++i)
  491. {
  492. if(pList->strings[i])
  493. delete [] pList->strings[i];
  494. }
  495. delete pList->strings;
  496. pList->count = 0;
  497. pList->strings = NULL;
  498. }
  499. }
  500. STDMETHODIMP CSFUCommon::get_NTDomain(BSTR * pVal)
  501. {
  502. // TODO: Add your implementation code here
  503. *pVal = SysAllocString(m_slNTDomains.strings[m_dwEnumNTDomainIndex]);
  504. return S_OK;
  505. }
  506. STDMETHODIMP CSFUCommon::get_NTDomainCount(DWORD * pVal)
  507. {
  508. // TODO: Add your implementation code here
  509. *pVal = m_slNTDomains.count;
  510. return S_OK;
  511. }
  512. STDMETHODIMP CSFUCommon::moveFirst()
  513. {
  514. // TODO: Add your implementation code here
  515. switch(mode)
  516. {
  517. case NTDOMAIN :
  518. {
  519. m_dwEnumNTDomainIndex = 0;
  520. m_bstrNTDomain = m_slNTDomains.strings[0];
  521. break;
  522. }
  523. }
  524. return S_OK;
  525. }
  526. STDMETHODIMP CSFUCommon::moveNext()
  527. {
  528. // TODO: Add your implementation code here
  529. switch(mode)
  530. {
  531. case NTDOMAIN :
  532. {
  533. m_dwEnumNTDomainIndex++;
  534. break;
  535. }
  536. }
  537. return S_OK;
  538. }
  539. STDMETHODIMP CSFUCommon::get_machine(BSTR *pVal)
  540. {
  541. *pVal = SysAllocString(m_szMachine);
  542. return S_OK;
  543. }
  544. STDMETHODIMP CSFUCommon::put_machine(BSTR newVal)
  545. {
  546. m_szMachine = (LPWSTR)malloc (sizeof(WCHAR) * wcslen(newVal) );
  547. wcscpy(m_szMachine,newVal);
  548. return S_OK;
  549. }
  550. /*----------------------------------------------------------------
  551. [Comments]: This Function returns the hostname.
  552. Added By: [shyamah]
  553. ----------------------------------------------------------------*/
  554. STDMETHODIMP CSFUCommon::get_hostName(BSTR *pbstrhostName)
  555. {
  556. WORD wVersionRequested;
  557. WSADATA wsaData;
  558. CHAR szHostName[DNS_MAX_NAME_BUFFER_LENGTH];
  559. WCHAR *wzStr=NULL;
  560. DWORD nLen=0;
  561. // Start up winsock
  562. wVersionRequested = MAKEWORD( 1, 1 );
  563. if (0==WSAStartup(wVersionRequested, &wsaData))
  564. {
  565. if(SOCKET_ERROR!=(gethostname(szHostName,DNS_MAX_NAME_BUFFER_LENGTH)))
  566. {
  567. nLen=MultiByteToWideChar(GetConsoleCP(),0,szHostName,-1,NULL,NULL);
  568. wzStr=(wchar_t *) malloc(nLen*sizeof(wchar_t));
  569. if(wzStr==NULL)
  570. return E_OUTOFMEMORY;
  571. MultiByteToWideChar(GetConsoleCP(), 0, szHostName, -1, wzStr, nLen );
  572. if(NULL==(*pbstrhostName=SysAllocString(wzStr)))
  573. {
  574. free(wzStr);
  575. return E_OUTOFMEMORY;
  576. }
  577. free(wzStr);
  578. }
  579. WSACleanup();
  580. }
  581. return S_OK;
  582. }
  583. /*-------------------------------------------------------------------
  584. [Comments]: This finction returns true if a service is installed and a false if a service
  585. is not installed.
  586. Added By: [Shyamah]
  587. ------------------------------------------------------------------*/
  588. STDMETHODIMP CSFUCommon::IsServiceInstalled(BSTR bMachine,BSTR bServiceName,BOOL *fValid)
  589. {
  590. *fValid = false;
  591. HRESULT error=S_OK;
  592. SC_HANDLE scManager=NULL;
  593. SC_HANDLE serviceHandle= NULL;
  594. if ((scManager = OpenSCManager(bMachine,SERVICES_ACTIVE_DATABASE,SC_MANAGER_ENUMERATE_SERVICE))==NULL)
  595. {
  596. error = GetLastError();
  597. goto Error;
  598. }
  599. if ((serviceHandle = OpenService(scManager,bServiceName,SERVICE_USER_DEFINED_CONTROL))==NULL)
  600. {
  601. error = GetLastError();
  602. goto Error;
  603. }
  604. *fValid = TRUE;
  605. Error :
  606. if(scManager)
  607. CloseServiceHandle(scManager);
  608. if(serviceHandle)
  609. CloseServiceHandle(serviceHandle);
  610. return(error);
  611. }