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.

683 lines
18 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. /*++
  3. Copyright (C) Microsoft Corporation, 1997 - 1999
  4. Module Name:
  5. MMCUtility.cpp
  6. Abstract:
  7. Implementation file for functions doing various handy things
  8. that were getting written over and over again.
  9. Author:
  10. Michael A. Maguire 02/05/98
  11. Revision History:
  12. mmaguire 02/05/98 - created
  13. mmaguire 11/03/98 - moved GetSdo/PutSdo wrappers to sdohelperfuncs.cpp
  14. --*/
  15. //////////////////////////////////////////////////////////////////////
  16. //////////////////////////////////////////////////////////////////////////////
  17. // BEGIN INCLUDES
  18. //
  19. // standard includes:
  20. //
  21. #include "Precompiled.h"
  22. //
  23. // where we can find declaration for main class in this file:
  24. //
  25. #include "MMCUtility.h"
  26. #include "cnctdlg.h"
  27. //
  28. //
  29. // where we can find declarations needed in this file:
  30. //
  31. //
  32. // END INCLUDES
  33. //////////////////////////////////////////////////////////////////////////////
  34. //////////////////////////////////////////////////////////////////////////////
  35. /*++
  36. HRESULT BringUpPropertySheetForNode(
  37. CSnapInItem *pSnapInItem
  38. , IComponentData *pComponentData
  39. , IComponent *pComponent
  40. , IConsole *pConsole
  41. , BOOL bCreateSheetIfOneIsntAlreadyUp = FALSE
  42. , LPCTSTR lpszSheetTitle = NULL
  43. , BOOL bPropertyPage = TRUE // TRUE creates property page, FALSE wizard page.
  44. );
  45. Tries to bring up a property sheet on a given node. If the sheet for the
  46. node is already up, it will bring that sheet to the foreground.
  47. Parameters:
  48. pSnapInItem
  49. You must supply a pointer to the node you want the sheet for.
  50. pComponentData, pComponent
  51. Either you call with pComponentData != NULL and pComponent == NULL
  52. or pComponentData == NULL and pComponent != NULL.
  53. pConsole
  54. You must supply a pointer to an IConsole interface.
  55. bCreateSheetIfOneIsntAlreadyUp
  56. TRUE - if a sheet isn't already up, will try to create a property sheet
  57. for you -- in this case you _must_ specify a title for the
  58. sheet in lpszSheetTitle.
  59. FALSE - will try to bring already existing sheet to foreground, but
  60. will return immediately if there isn't one.
  61. bPropertyPage
  62. TRUE for property pages. (Note: MMC creates property sheet in new thread.)
  63. FALSE for wizard pages. (Note: Wizard pages run in same thread.)
  64. Return:
  65. S_OK if found property sheet already up.
  66. S_FALSE if didn't find sheet already up but successfully made new one appear.
  67. E_... if some error error occurred.
  68. Remarks:
  69. For this function's to work, you must have correctly implemented
  70. IComponentData::CompareObjects and IComponentData::CompareObjects.
  71. --*/
  72. //////////////////////////////////////////////////////////////////////////////
  73. HRESULT BringUpPropertySheetForNode(
  74. CSnapInItem *pSnapInItem
  75. , IComponentData *pComponentData
  76. , IComponent *pComponent
  77. , IConsole *pConsole
  78. , BOOL bCreateSheetIfOneIsntAlreadyUp
  79. , LPCTSTR lpszSheetTitle
  80. , BOOL bPropertyPage
  81. , DWORD dwPropertySheetOptions
  82. )
  83. {
  84. ATLTRACE(_T("# BringUpPropertySheetForNode\n"));
  85. // Check for preconditions:
  86. _ASSERTE( pSnapInItem != NULL );
  87. // We need one or the other to be non-NULL
  88. _ASSERTE( pComponentData != NULL || pComponent != NULL );
  89. _ASSERTE( pConsole != NULL );
  90. HRESULT hr;
  91. // Query IConsole for the needed interface.
  92. CComQIPtr<IPropertySheetProvider, &IID_IPropertySheetProvider> spPropertySheetProvider( pConsole );
  93. _ASSERTE( spPropertySheetProvider != NULL );
  94. CComPtr<IDataObject> spDataObject;
  95. hr = pSnapInItem->GetDataObject( &spDataObject, CCT_RESULT );
  96. if( FAILED( hr ) )
  97. {
  98. return hr;
  99. }
  100. // This returns S_OK if a property sheet for this object already exists
  101. // and brings that property sheet to the foreground.
  102. // It returns S_FALSE if the property sheet wasn't found.
  103. // If this is coming in through my IComponent object, I pass the pComponent pointer.
  104. // If this is coming in through my IComponentData object,
  105. // then pComponent is NULL, which is the appropriate value to pass in for
  106. // the call to FindPropertySheet when coming in through IComponentData.
  107. hr = spPropertySheetProvider->FindPropertySheet(
  108. (MMC_COOKIE) pSnapInItem // cookie
  109. , pComponent
  110. , spDataObject
  111. );
  112. if( FAILED( hr ) )
  113. {
  114. return hr;
  115. }
  116. if( S_OK == hr || FALSE == bCreateSheetIfOneIsntAlreadyUp )
  117. {
  118. // We found a property sheet already up for this node,
  119. // or we didn't find one but we weren't asked to create one.
  120. return hr;
  121. }
  122. // We didn't find a property sheet already up for this node.
  123. _ASSERTE( S_FALSE == hr );
  124. hr = spPropertySheetProvider->CreatePropertySheet(
  125. lpszSheetTitle
  126. , (BOOLEAN)bPropertyPage /* TRUE == prop page, FALSE == wizard */
  127. , (MMC_COOKIE) pSnapInItem // cookie
  128. , spDataObject
  129. , dwPropertySheetOptions
  130. );
  131. if( FAILED( hr ) )
  132. {
  133. return hr;
  134. }
  135. HWND hWndNotification;
  136. HWND hWndMain;
  137. hr = pConsole->GetMainWindow( & hWndMain );
  138. if( FAILED( hr ) )
  139. {
  140. return hr;
  141. }
  142. // Try to get the correct window that notifications should be sent to.
  143. hWndNotification = FindWindowEx( hWndMain, NULL, L"MDIClient", NULL );
  144. hWndNotification = FindWindowEx( hWndNotification, NULL, L"MMCChildFrm", NULL );
  145. hWndNotification = FindWindowEx( hWndNotification, NULL, L"MMCView", NULL );
  146. if( NULL == hWndNotification )
  147. {
  148. // It was a nice try, but it failed, so we should be able to get by by using the main HWND.
  149. hWndNotification = hWndMain;
  150. }
  151. hr = spPropertySheetProvider->AddPrimaryPages(
  152. (pComponent != NULL ? (LPUNKNOWN) pComponent : (LPUNKNOWN) pComponentData )
  153. , TRUE
  154. , hWndNotification
  155. , (pComponent != NULL ? FALSE : TRUE )
  156. );
  157. if( FAILED( hr ) )
  158. {
  159. // Release data allocated in CreatePropertySheet
  160. spPropertySheetProvider->Show( -1, 0);
  161. return hr;
  162. }
  163. hr = spPropertySheetProvider->AddExtensionPages();
  164. if( FAILED( hr ) )
  165. {
  166. // ISSUE: Should I care if this fails?
  167. // Release data allocated in CreatePropertySheet
  168. spPropertySheetProvider->Show( -1, 0);
  169. return hr;
  170. }
  171. hr = spPropertySheetProvider->Show( (LONG_PTR) hWndMain, 0);
  172. if( FAILED( hr ) )
  173. {
  174. return hr;
  175. }
  176. return hr;
  177. }
  178. int ShowErrorDialog(
  179. HWND hWnd
  180. , UINT uErrorID
  181. , BSTR bstrSupplementalErrorString
  182. , HRESULT hr
  183. , UINT uTitleID
  184. , IConsole *pConsole
  185. , UINT uType
  186. )
  187. //////////////////////////////////////////////////////////////////////////////
  188. /*++
  189. Puts up an error dialog with varying degrees of detail
  190. Parameters:
  191. All parameters are optional -- in the worst case, you can simply call
  192. ShowErrorDialog();
  193. to put up a very generic error message.
  194. uErrorID
  195. The resource ID of the string to be used for the error message.
  196. Passing in USE_DEFAULT gives causes the default error message to be displayed.
  197. Passing in USE_SUPPLEMENTAL_ERROR_STRING_ONLY causes no resource string text to be displayed.
  198. bstrSupplementalErrorString
  199. Pass in a string to print as the error message. Useful if you are
  200. receiving an error string from some other component you communicate with.
  201. hr
  202. If there is an HRESULT involved in the error, pass it in here so that
  203. a suitable error message based on the HRESULT can be put up.
  204. Pass in S_OK if the HRESULT doesn't matter to the error.
  205. uTitleID
  206. The resource ID of the string to be used for the error dialog title.
  207. Passing in USE_DEFAULT gives causes the default error dialog title to be displayed.
  208. pConsole
  209. If you are running within the main MMC context, pass in a valid IConsole pointer
  210. and ShowErrorDialog will use MMC's IConsole::MessageBox rather than the
  211. standard system MessageBox.
  212. hWnd
  213. Whatever you pass in here will be passed in as the HWND parameter
  214. to the MessageBox call.
  215. This is not used if you pass in an IConsole pointer.
  216. uType
  217. Whatever you pass in here will be passed in as the HWND parameter
  218. to the MessageBox call.
  219. Return:
  220. The standard int returned from MessageBox.
  221. --*/
  222. //////////////////////////////////////////////////////////////////////////////
  223. {
  224. ATLTRACE(_T("# ShowErrorDialog\n"));
  225. // Check for preconditions:
  226. // None.
  227. int iReturnValue;
  228. TCHAR szError[IAS_MAX_STRING*2];
  229. TCHAR szTitle[IAS_MAX_STRING*2];
  230. int iLoadStringResult;
  231. szError[0] = NULL;
  232. szTitle[0] = NULL;
  233. HINSTANCE hInstance = _Module.GetResourceInstance();
  234. if( USE_DEFAULT == uTitleID )
  235. {
  236. uTitleID = IDS_ERROR__GENERIC_TITLE;
  237. }
  238. iLoadStringResult = LoadString( hInstance, uTitleID, szTitle, IAS_MAX_STRING );
  239. _ASSERT( iLoadStringResult > 0 );
  240. if( USE_SUPPLEMENTAL_ERROR_STRING_ONLY == uErrorID )
  241. {
  242. // Special case. We have no text to load from the resources.
  243. }
  244. else
  245. {
  246. if( USE_DEFAULT == uErrorID )
  247. {
  248. uErrorID = IDS_ERROR__GENERIC;
  249. }
  250. iLoadStringResult = LoadString( hInstance, uErrorID, szError, IAS_MAX_STRING*2 );
  251. _ASSERT( iLoadStringResult > 0 );
  252. if( NULL != bstrSupplementalErrorString )
  253. {
  254. // Add some spacing.
  255. _tcscat( szError, _T(" ") );
  256. }
  257. }
  258. if( NULL != bstrSupplementalErrorString )
  259. {
  260. // We were passed a string with supplemental error info.
  261. _tcscat( szError, bstrSupplementalErrorString );
  262. }
  263. if( FAILED( hr ) )
  264. {
  265. #if 0 // change to display system wide error info
  266. // The HRESULT contains some information about the kind of failure.
  267. // We may want to change this later to provide more information
  268. // information based on the error that was returned.
  269. // We could have a map which defines relationships between error
  270. // ID's and the HRESULTS. That way we could provide the appropriate
  271. // error message for each HRESULT based on the context of which ID
  272. // was passed in.
  273. // For now, just print the error ID.
  274. TCHAR szErrorNumber[IAS_MAX_STRING];
  275. _stprintf( szErrorNumber, _T(" 0x%x"), hr );
  276. // Some spacing.
  277. _tcscat( szError, _T(" ") );
  278. _tcscat( szError, szErrorNumber );
  279. #endif
  280. PTSTR ptzSysMsg;
  281. int cch;
  282. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  283. NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  284. (PTSTR)&ptzSysMsg, 0, NULL);
  285. if (!cch) { //try ads errors
  286. HMODULE adsMod;
  287. adsMod = GetModuleHandle (L"odbc32.dll");
  288. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  289. adsMod, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  290. (PTSTR)&ptzSysMsg, 0, NULL);
  291. }
  292. if(cch) // found
  293. {
  294. _tcscat( szError, _T(" ") );
  295. _tcscat( szError, ptzSysMsg );
  296. LocalFree( ptzSysMsg );
  297. }
  298. else
  299. {
  300. TCHAR szErrorNumber[IAS_MAX_STRING];
  301. if(hr == DB_E_NOTABLE) // assume, the RPC connection has problem
  302. iLoadStringResult = LoadString( hInstance, IDS_ERROR__RESTART_SNAPIN, szErrorNumber, IAS_MAX_STRING );
  303. else
  304. {
  305. _stprintf( szErrorNumber, _T(" 0x%x"), hr );
  306. // Some spacing.
  307. _tcscat( szError, _T(" ") );
  308. _tcscat( szError, szErrorNumber );
  309. }
  310. }
  311. }
  312. // Put the error message up in the appropriate manner depending on our context.
  313. if( pConsole != NULL )
  314. {
  315. pConsole->MessageBox( szError, szTitle, uType, &iReturnValue );
  316. }
  317. else
  318. {
  319. // ISSUE: Do we want to do anything special if hWnd == NULL?
  320. // Or just pass the NULL right on to MessageBox?
  321. iReturnValue = ::MessageBox( hWnd, szError, szTitle, uType );
  322. }
  323. return iReturnValue;
  324. }
  325. BOOL GetUserAndDomainName( LPTSTR UserName
  326. , LPDWORD cchUserName
  327. , LPTSTR DomainName
  328. , LPDWORD cchDomainName
  329. )
  330. //////////////////////////////////////////////////////////////////////////////
  331. /*++
  332. Retrieves current user's username and domain.
  333. Stolen from Knowledge Base HOWTO article:
  334. HOWTO: Look Up Current User Name and Domain Name
  335. Rollup: WINPROG
  336. Database: win32sdk
  337. Article ID: Q155698
  338. Last modified: June 16, 1997
  339. Security: PUBLIC
  340. --*/
  341. //////////////////////////////////////////////////////////////////////////////
  342. {
  343. HANDLE hToken;
  344. #define MY_BUFSIZE 512 // highly unlikely to exceed 512 bytes
  345. UCHAR InfoBuffer[ MY_BUFSIZE ];
  346. DWORD cbInfoBuffer = MY_BUFSIZE;
  347. SID_NAME_USE snu;
  348. BOOL bSuccess;
  349. if( !OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken) )
  350. {
  351. if(GetLastError() == ERROR_NO_TOKEN)
  352. {
  353. //
  354. // attempt to open the process token, since no thread token
  355. // exists
  356. //
  357. if(!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ))
  358. return FALSE;
  359. }
  360. else
  361. {
  362. //
  363. // error trying to get thread token
  364. //
  365. return FALSE;
  366. }
  367. }
  368. bSuccess = GetTokenInformation( hToken, TokenUser, InfoBuffer, cbInfoBuffer, &cbInfoBuffer );
  369. if(!bSuccess)
  370. {
  371. if( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  372. {
  373. //
  374. // alloc buffer and try GetTokenInformation() again
  375. //
  376. CloseHandle(hToken);
  377. return FALSE;
  378. }
  379. else
  380. {
  381. //
  382. // error getting token info
  383. //
  384. CloseHandle(hToken);
  385. return FALSE;
  386. }
  387. }
  388. CloseHandle(hToken);
  389. return LookupAccountSid( NULL
  390. , ((PTOKEN_USER)InfoBuffer)->User.Sid
  391. , UserName
  392. , cchUserName
  393. , DomainName
  394. , cchDomainName
  395. , &snu
  396. );
  397. }
  398. // Tries to open the specified service with the desired access.
  399. DWORD TryOpenService(
  400. const wchar_t* machineName,
  401. const wchar_t* serviceName,
  402. DWORD desiredAccess
  403. ) throw ()
  404. {
  405. SC_HANDLE manager = OpenSCManager(
  406. machineName,
  407. SERVICES_ACTIVE_DATABASE,
  408. GENERIC_READ
  409. );
  410. if (manager == 0)
  411. {
  412. return GetLastError();
  413. }
  414. SC_HANDLE service = OpenService(
  415. manager,
  416. serviceName,
  417. desiredAccess
  418. );
  419. DWORD result;
  420. if (service != 0)
  421. {
  422. CloseServiceHandle(service);
  423. result = NO_ERROR;
  424. }
  425. else
  426. {
  427. result = GetLastError();
  428. }
  429. CloseServiceHandle(manager);
  430. return result;
  431. }
  432. HRESULT IfServiceInstalled(
  433. const wchar_t* machineName,
  434. const wchar_t* serviceName,
  435. BOOL* result
  436. )
  437. {
  438. if ((serviceName == 0) || (result == 0))
  439. {
  440. return E_INVALIDARG;
  441. }
  442. *result = FALSE;
  443. // We request GENERIC_EXECUTE access because this function is used both to
  444. // test if the service is installed and to check if we have permission to
  445. // administer the service.
  446. DWORD error = TryOpenService(machineName, serviceName, GENERIC_EXECUTE);
  447. // If the user doesn't have access, we'll give him a chance to specify
  448. // alternate credentials.
  449. while (error == ERROR_ACCESS_DENIED)
  450. {
  451. HRESULT hr = ConnectAsAdmin(machineName);
  452. if (hr == S_FALSE)
  453. {
  454. // User chose cancel.
  455. return E_ACCESSDENIED;
  456. }
  457. else if (SUCCEEDED(hr))
  458. {
  459. error = TryOpenService(machineName, serviceName, GENERIC_EXECUTE);
  460. }
  461. else
  462. {
  463. return hr;
  464. }
  465. }
  466. if (error == NO_ERROR)
  467. {
  468. *result = TRUE;
  469. }
  470. else if (error != ERROR_SERVICE_DOES_NOT_EXIST)
  471. {
  472. return HRESULT_FROM_WIN32(error);
  473. }
  474. return S_OK;
  475. }
  476. /*!--------------------------------------------------------------------------
  477. GetModuleFileNameOnly
  478. -
  479. Author: WeiJiang
  480. returns zero on errors
  481. ---------------------------------------------------------------------------*/
  482. DWORD GetModuleFileNameOnly(HINSTANCE hInst, LPTSTR lpFileName, DWORD nSize )
  483. {
  484. CString name;
  485. TCHAR FullName[MAX_PATH * 2];
  486. DWORD dwErr = ::GetModuleFileName(hInst, FullName, MAX_PATH * 2);
  487. if ((dwErr == 0) || (dwErr == (MAX_PATH * 2)))
  488. {
  489. // error or string truncated
  490. return 0;
  491. }
  492. else
  493. {
  494. name = FullName;
  495. DWORD FirstChar = name.ReverseFind(_T('\\')) + 1;
  496. name = name.Mid(FirstChar);
  497. DWORD len = name.GetLength();
  498. if( len < nSize )
  499. {
  500. _tcscpy(lpFileName, name);
  501. }
  502. else
  503. {
  504. len = 0;
  505. }
  506. return len;
  507. }
  508. }