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.

1235 lines
32 KiB

  1. //==============================================================;
  2. //
  3. // This source code is only intended as a supplement to
  4. // existing Microsoft documentation.
  5. //
  6. //
  7. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  8. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  9. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  10. // PURPOSE.
  11. //
  12. // Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  13. //
  14. //
  15. //==============================================================;
  16. #include <stdio.h>
  17. #include "People.h"
  18. #include <commctrl.h>
  19. #include <comdef.h>
  20. #include <windowsx.h>
  21. const GUID CPeoplePoweredVehicle::thisGuid = { 0x2974380d, 0x4c4b, 0x11d2, { 0x89, 0xd8, 0x0, 0x0, 0x21, 0x47, 0x31, 0x28 } };
  22. const GUID CBicycleFolder::thisGuid = { 0xef163732, 0x9353, 0x11d2, { 0x99, 0x67, 0x0, 0x80, 0xc7, 0xdc, 0xb3, 0xdc } };
  23. const GUID CSkateboardFolder::thisGuid = { 0xef163733, 0x9353, 0x11d2, { 0x99, 0x67, 0x0, 0x80, 0xc7, 0xdc, 0xb3, 0xdc } };
  24. const GUID CIceSkateFolder::thisGuid = { 0xf6c660b0, 0x9353, 0x11d2, { 0x99, 0x67, 0x0, 0x80, 0xc7, 0xdc, 0xb3, 0xdc } };
  25. const GUID CBicycle::thisGuid = { 0xef163734, 0x9353, 0x11d2, { 0x99, 0x67, 0x0, 0x80, 0xc7, 0xdc, 0xb3, 0xdc } };
  26. const GUID CSkateboard::thisGuid = { 0xef163735, 0x9353, 0x11d2, { 0x99, 0x67, 0x0, 0x80, 0xc7, 0xdc, 0xb3, 0xdc } };
  27. const GUID CIceSkate::thisGuid = { 0xf6c660b1, 0x9353, 0x11d2, { 0x99, 0x67, 0x0, 0x80, 0xc7, 0xdc, 0xb3, 0xdc } };
  28. #define WM_WMI_CONNECTED WM_APP // only sent to CBicycleFolder::m_connectHwnd
  29. #define WM_REFRESH_EVENT WM_APP+1 // only sent to CBicycleFolder::m_connectHwnd
  30. //==============================================================
  31. //
  32. // CEventSink implementation
  33. //
  34. class CEventSink : public IWbemObjectSink
  35. {
  36. public:
  37. CEventSink(HWND hwnd) : m_hwnd(hwnd){}
  38. ~CEventSink(){};
  39. STDMETHOD_(SCODE, Indicate)(long lObjectCount,
  40. IWbemClassObject **pObjArray)
  41. {
  42. // Not actually using the pObjArray. Just need a trigger for the
  43. // refresh.
  44. ::SendMessage(m_hwnd, WM_REFRESH_EVENT, 0, 0);
  45. return S_OK;
  46. }
  47. STDMETHOD_(SCODE, SetStatus)(long lFlags,
  48. HRESULT hResult,
  49. BSTR strParam,
  50. IWbemClassObject *pObjParam)
  51. {
  52. // SetStatus() may be called to indicate that your query becomes
  53. // invalid or valid again ussually caused by multithreading 'situations'.
  54. return S_OK;
  55. }
  56. // IUnknown members
  57. STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv)
  58. {
  59. if(riid == IID_IUnknown || riid == IID_IWbemObjectSink)
  60. {
  61. *ppv = this;
  62. // you're handing out a copy of yourself so account for it.
  63. AddRef();
  64. return S_OK;
  65. }
  66. else
  67. {
  68. return E_NOINTERFACE;
  69. }
  70. }
  71. STDMETHODIMP_(ULONG) AddRef(void)
  72. {
  73. return InterlockedIncrement(&m_lRef);
  74. }
  75. STDMETHODIMP_(ULONG) Release(void)
  76. {
  77. // InterlockedDecrement() helps with thread safety.
  78. int lNewRef = InterlockedDecrement(&m_lRef);
  79. // when all the copies are released...
  80. if(lNewRef == 0)
  81. {
  82. // kill thyself.
  83. delete this;
  84. }
  85. return lNewRef;
  86. }
  87. private:
  88. long m_lRef;
  89. HWND m_hwnd;
  90. };
  91. //==============================================================
  92. //
  93. // CPeoplePoweredVehicle implementation
  94. //
  95. //
  96. //----------------------------------------------------------
  97. #define TEMP_BUF 255
  98. bool CBicycleFolder::ErrorString(HRESULT hr,
  99. TCHAR *errMsg, UINT errSize)
  100. {
  101. TCHAR szError[TEMP_BUF] = {0};
  102. TCHAR szFacility[TEMP_BUF] = {0};
  103. IWbemStatusCodeText * pStatus = NULL;
  104. // initialize buffers.
  105. memset(errMsg, 0, errSize * sizeof(TCHAR));
  106. HRESULT hr1 = CoInitialize(NULL);
  107. SCODE sc1 = CoCreateInstance(CLSID_WbemStatusCodeText,
  108. 0, CLSCTX_INPROC_SERVER,
  109. IID_IWbemStatusCodeText,
  110. (LPVOID *) &pStatus);
  111. // loaded OK?
  112. if(sc1 == S_OK)
  113. {
  114. BSTR bstr;
  115. sc1 = pStatus->GetErrorCodeText(hr, 0, 0, &bstr);
  116. if(sc1 == S_OK)
  117. {
  118. #ifdef UNICODE
  119. wcsncpy(szError, bstr, TEMP_BUF-1);
  120. #else
  121. wcstombs(szError, bstr, TEMP_BUF-1);
  122. #endif UNICODE
  123. SysFreeString(bstr);
  124. bstr = 0;
  125. }
  126. sc1 = pStatus->GetFacilityCodeText(hr, 0, 0, &bstr);
  127. if(sc1 == S_OK)
  128. {
  129. #ifdef UNICODE
  130. wcsncpy(szFacility, bstr, TEMP_BUF-1);
  131. #else
  132. wcstombs(szFacility, bstr, TEMP_BUF-1);
  133. #endif UNICODE
  134. SysFreeString(bstr);
  135. bstr = 0;
  136. }
  137. // RELEASE
  138. pStatus->Release();
  139. pStatus = NULL;
  140. }
  141. else
  142. {
  143. ::MessageBox(NULL, _T("WBEM error features not available. Upgrade WMI to a newer build."),
  144. _T("Internal Error"), MB_ICONSTOP|MB_OK);
  145. }
  146. // if not msgs returned....
  147. if(_tcslen(szFacility) == 0 || _tcslen(szError) == 0)
  148. {
  149. // format the error nbr as a reasonable default.
  150. _stprintf(errMsg, _T("Error code: 0x%08X"), hr);
  151. }
  152. else
  153. {
  154. // format a readable msg.
  155. _stprintf(errMsg, _T("%s: %s"), szFacility, szError);
  156. }
  157. if(hr1 == S_OK)
  158. CoUninitialize();
  159. return (SUCCEEDED(sc1) && SUCCEEDED(hr1));
  160. }
  161. CPeoplePoweredVehicle::CPeoplePoweredVehicle()
  162. {
  163. children[0] = new CBicycleFolder;
  164. children[1] = new CSkateboardFolder;
  165. children[2] = new CIceSkateFolder;
  166. }
  167. CPeoplePoweredVehicle::~CPeoplePoweredVehicle()
  168. {
  169. for (int n = 0; n < NUMBER_OF_CHILDREN; n++)
  170. delete children[n];
  171. }
  172. HRESULT CPeoplePoweredVehicle::OnExpand(IConsoleNameSpace *pConsoleNameSpace, IConsole *pConsole, HSCOPEITEM parent)
  173. {
  174. SCOPEDATAITEM sdi;
  175. if (!bExpanded) {
  176. // create the child nodes, then expand them
  177. for (int n = 0; n < NUMBER_OF_CHILDREN; n++) {
  178. ZeroMemory(&sdi, sizeof(SCOPEDATAITEM) );
  179. sdi.mask = SDI_STR | // Displayname is valid
  180. SDI_PARAM | // lParam is valid
  181. SDI_IMAGE | // nImage is valid
  182. SDI_OPENIMAGE | // nOpenImage is valid
  183. SDI_PARENT | // relativeID is valid
  184. SDI_CHILDREN; // cChildren is valid
  185. sdi.relativeID = (HSCOPEITEM)parent;
  186. sdi.nImage = children[n]->GetBitmapIndex();
  187. sdi.nOpenImage = INDEX_OPENFOLDER;
  188. sdi.displayname = MMC_CALLBACK;
  189. sdi.lParam = (LPARAM)children[n]; // The cookie
  190. sdi.cChildren = 0;
  191. HRESULT hr = pConsoleNameSpace->InsertItem( &sdi );
  192. _ASSERT( SUCCEEDED(hr) );
  193. }
  194. }
  195. return S_OK;
  196. }
  197. CBicycleFolder::CBicycleFolder() :
  198. m_connectHwnd(0),
  199. m_threadId(0), m_thread(0),
  200. m_doWork(0), m_threadCmd(CT_CONNECT),
  201. m_running(false), m_ptrReady(0),
  202. m_pStream(0), m_realWMI(0),
  203. m_pResultData(0), m_pStubSink(0),
  204. m_pUnsecApp(0)
  205. {
  206. WNDCLASS wndClass;
  207. ZeroMemory(&wndClass, sizeof(WNDCLASS));
  208. wndClass.lpfnWndProc = WindowProc;
  209. wndClass.lpszClassName = _T("connectthreadwindow");
  210. wndClass.hInstance = g_hinst;
  211. ATOM atom = RegisterClass(&wndClass);
  212. m_connectHwnd = CreateWindow(
  213. _T("connectthreadwindow"), // pointer to registered class name
  214. NULL, // pointer to window name
  215. 0, // window style
  216. 0, // horizontal position of window
  217. 0, // vertical position of window
  218. 0, // window width
  219. 0, // window height
  220. NULL, // handle to parent or owner window
  221. NULL, // handle to menu or child-window identifier
  222. g_hinst, // handle to application instance
  223. (void *)this); // pointer to window-creation data
  224. if (m_connectHwnd)
  225. SetWindowLong(m_connectHwnd, GWL_USERDATA, (LONG)this);
  226. InitializeCriticalSection(&m_critSect);
  227. m_doWork = CreateEvent(NULL, FALSE, FALSE, NULL);
  228. m_ptrReady = CreateEvent(NULL, FALSE, FALSE, NULL);
  229. EnterCriticalSection(&m_critSect);
  230. // NOTE: I'm connecting real early. You may want to connect from some other place.
  231. m_threadCmd = CT_CONNECT;
  232. SetEvent(m_doWork);
  233. m_thread = CreateThread(NULL, 0, ThreadProc, (void *)this, 0, &m_threadId);
  234. LeaveCriticalSection(&m_critSect);
  235. }
  236. CBicycleFolder::~CBicycleFolder()
  237. {
  238. EmptyChildren();
  239. if(m_pResultData)
  240. {
  241. m_pResultData->Release();
  242. m_pResultData = 0;
  243. }
  244. if(m_pStubSink)
  245. {
  246. IWbemServices *service = 0;
  247. HRESULT hr = GetPtr(&service);
  248. if(SUCCEEDED(hr))
  249. {
  250. service->CancelAsyncCall(m_pStubSink);
  251. service->Release();
  252. service = 0;
  253. }
  254. m_pStubSink->Release();
  255. m_pStubSink = NULL;
  256. }
  257. if(m_pUnsecApp)
  258. {
  259. m_pUnsecApp->Release();
  260. m_pUnsecApp = 0;
  261. }
  262. StopThread();
  263. if(m_connectHwnd != NULL)
  264. DestroyWindow(m_connectHwnd);
  265. UnregisterClass(_T("connectthreadwindow"), NULL);
  266. DeleteCriticalSection(&m_critSect);
  267. }
  268. void CBicycleFolder::StopThread()
  269. {
  270. EnterCriticalSection(&m_critSect);
  271. m_running = false;
  272. if (m_thread != NULL)
  273. {
  274. m_threadCmd = CT_EXIT;
  275. SetEvent(m_doWork);
  276. WaitForSingleObject(m_ptrReady, 10000);
  277. CloseHandle(m_thread);
  278. m_thread = NULL;
  279. }
  280. LeaveCriticalSection(&m_critSect);
  281. }
  282. LRESULT CALLBACK CBicycleFolder::WindowProc(
  283. HWND hwnd, // handle to window
  284. UINT uMsg, // message identifier
  285. WPARAM wParam, // first message parameter
  286. LPARAM lParam) // second message parameter
  287. {
  288. CBicycleFolder *pThis = (CBicycleFolder *)GetWindowLong(hwnd, GWL_USERDATA);
  289. switch (uMsg)
  290. {
  291. case WM_WMI_CONNECTED:
  292. if(pThis != NULL)
  293. {
  294. IWbemServices *service = 0;
  295. HRESULT hr = pThis->GetPtr(&service);
  296. if(SUCCEEDED(hr))
  297. {
  298. pThis->RegisterEventSink(service);
  299. pThis->EnumChildren(service);
  300. // m_pResultData gets set when an onShow has happened. If set, the user already wants
  301. // to see equipment but the connection was slower than the UI. Catchup now.
  302. if(pThis->m_pResultData)
  303. pThis->DisplayChildren();
  304. // done with the marshaled service ptr.
  305. service->Release();
  306. service = 0;
  307. }
  308. }
  309. else
  310. {
  311. TCHAR errMsg[255] = {0};
  312. pThis->ErrorString((HRESULT)wParam, errMsg, 255);
  313. MessageBox(hwnd, errMsg, _T("WMI Snapin Sample"), MB_OK|MB_ICONSTOP);
  314. }
  315. break;
  316. case WM_REFRESH_EVENT:
  317. if(pThis != NULL)
  318. {
  319. IWbemServices *service = 0;
  320. HRESULT hr = pThis->GetPtr(&service);
  321. if(SUCCEEDED(hr))
  322. {
  323. pThis->EmptyChildren();
  324. pThis->EnumChildren(service);
  325. pThis->DisplayChildren();
  326. // done with the marshaled service ptr.
  327. service->Release();
  328. service = 0;
  329. }
  330. }
  331. break;
  332. } //endswitch
  333. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  334. }
  335. void CBicycleFolder::RegisterEventSink(IWbemServices *service)
  336. {
  337. //NOTE: this logic is from the Wmi documentation,
  338. // "Security Considerations with Asynchronous Calls" so you can
  339. // follow along.
  340. // allocate the sink if its not already allocated.
  341. if(m_pStubSink == 0)
  342. {
  343. CEventSink *pEventSink = 0;
  344. IUnknown* pStubUnk = 0;
  345. // create the 'real' sink.
  346. pEventSink = new CEventSink(m_connectHwnd);
  347. pEventSink->AddRef();
  348. // create an unsecapp object.
  349. CoCreateInstance(CLSID_UnsecuredApartment, NULL,
  350. CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment,
  351. (void**)&m_pUnsecApp);
  352. // give the 'real' sink to the unsecapp to manage. Get a 'pStubUnk' in return.
  353. m_pUnsecApp->CreateObjectStub(pEventSink, &pStubUnk);
  354. // from that pUnk, get a wrapper to your original sink.
  355. pStubUnk->QueryInterface(IID_IWbemObjectSink, (void **)&m_pStubSink);
  356. pStubUnk->Release();
  357. // release the 'real' sink cuz m_pStubSink "owns" it now.
  358. long ref = pEventSink->Release();
  359. }
  360. HRESULT hRes = S_OK;
  361. BSTR qLang = SysAllocString(L"WQL");
  362. BSTR query = SysAllocString(L"select * from __InstanceCreationEvent where TargetInstance isa \"Bicycle\"");
  363. // execute the query. For *Async, the last parm is a sink object
  364. // that will be sent the resultset instead of returning the normal
  365. // enumerator object.
  366. if(SUCCEEDED(hRes = service->ExecNotificationQueryAsync(qLang, query,
  367. 0L, NULL,
  368. m_pStubSink)))
  369. {
  370. OutputDebugString(_T("Executed filter query\n"));
  371. }
  372. else
  373. {
  374. OutputDebugString(_T("ExecQuery() failed\n"));
  375. } //endif ExecQuery()
  376. SysFreeString(qLang);
  377. SysFreeString(query);
  378. }
  379. void CBicycleFolder::EmptyChildren(void)
  380. {
  381. if(m_pResultData)
  382. {
  383. HRESULT hr = m_pResultData->DeleteAllRsltItems();
  384. int last = m_children.GetSize();
  385. for (int n = 0; n < last; n++)
  386. {
  387. if (m_children[n] != NULL)
  388. delete m_children[n];
  389. }
  390. m_children.RemoveAll();
  391. }
  392. }
  393. bool CBicycleFolder::EnumChildren(IWbemServices *service)
  394. {
  395. IEnumWbemClassObject *pEnumBikes = NULL;
  396. HRESULT hr = S_OK;
  397. // get the list of bicycles...
  398. if(SUCCEEDED(hr = service->CreateInstanceEnum((bstr_t)L"Bicycle",
  399. WBEM_FLAG_SHALLOW,
  400. NULL, &pEnumBikes)))
  401. {
  402. // NOTE: pBike MUST be set to NULL for Next().
  403. IWbemClassObject *pBike = NULL;
  404. CBicycle *pBikeInst = 0;
  405. ULONG uReturned = 1;
  406. while((SUCCEEDED(hr = pEnumBikes->Next(-1, 1, &pBike, &uReturned))) &&
  407. (uReturned != 0))
  408. {
  409. // Add the bike...
  410. pBikeInst = new CBicycle(this, pBike);
  411. m_children.Add(pBikeInst);
  412. // Done with this object. pBikeInst "owns" it now.
  413. if(pBike)
  414. {
  415. pBike->Release();
  416. // NOTE: pBike MUST be reset to NULL for Next().
  417. pBike = NULL;
  418. }
  419. } // endwhile
  420. // Done with this enumerator.
  421. if (pEnumBikes)
  422. {
  423. pEnumBikes->Release();
  424. pEnumBikes = NULL;
  425. }
  426. } // endif CreateInstanceEnum()
  427. return SUCCEEDED(hr);
  428. }
  429. HRESULT CBicycleFolder::GetPtr(IWbemServices **ptr)
  430. {
  431. HRESULT hr = E_FAIL;
  432. m_threadCmd = CT_GET_PTR;
  433. SetEvent(m_doWork);
  434. WaitForSingleObject(m_ptrReady, 10000);
  435. if(ptr && m_pStream)
  436. {
  437. *ptr = 0;
  438. hr = CoGetInterfaceAndReleaseStream(m_pStream,
  439. IID_IWbemServices,
  440. (void**)ptr);
  441. }
  442. return hr;
  443. }
  444. DWORD WINAPI CBicycleFolder::ThreadProc(LPVOID lpParameter)
  445. {
  446. CBicycleFolder *pThis = (CBicycleFolder *)lpParameter;
  447. HRESULT hr = S_OK;
  448. CoInitialize(NULL);
  449. while(true)
  450. {
  451. WaitForSingleObject(pThis->m_doWork, -1);
  452. switch(pThis->m_threadCmd)
  453. {
  454. case CT_CONNECT:
  455. {
  456. IWbemLocator *pLocator = 0;
  457. HRESULT hr;
  458. // Create an instance of the WbemLocator interface.
  459. hr = CoCreateInstance(CLSID_WbemLocator,
  460. NULL, CLSCTX_INPROC_SERVER,
  461. IID_IWbemLocator, (LPVOID *)&pLocator);
  462. if(SUCCEEDED(hr))
  463. {
  464. hr = pLocator->ConnectServer(L"root\\Vehicles",// Network
  465. NULL, // User
  466. NULL, // Password
  467. NULL, // Locale
  468. 0, // Security Flags
  469. NULL, // Authority
  470. NULL, // Context
  471. &pThis->m_realWMI); // Namespace
  472. // tell the callback the result of the connection.
  473. if(pThis->m_connectHwnd)
  474. PostMessage(pThis->m_connectHwnd, WM_WMI_CONNECTED, hr, 0);
  475. }
  476. }
  477. break;
  478. case CT_GET_PTR:
  479. if(pThis->m_realWMI != NULL)
  480. {
  481. hr = CoMarshalInterThreadInterfaceInStream(IID_IWbemServices,
  482. pThis->m_realWMI,
  483. &(pThis->m_pStream));
  484. }
  485. SetEvent(pThis->m_ptrReady);
  486. break;
  487. case CT_EXIT:
  488. if(pThis->m_realWMI != NULL)
  489. {
  490. pThis->m_realWMI->Release();
  491. pThis->m_realWMI = 0;
  492. }
  493. SetEvent(pThis->m_ptrReady);
  494. return 0;
  495. break;
  496. } //endswitch
  497. } //endwhile(true)
  498. return 0;
  499. }
  500. HRESULT CBicycleFolder::DisplayChildren(void)
  501. {
  502. // insert items here
  503. RESULTDATAITEM rdi;
  504. HRESULT hr = S_OK;
  505. int last = m_children.GetSize();
  506. CBicycle *pBike = 0;
  507. // create the child nodes, then expand them
  508. for (int n = 0; n < last; n++)
  509. {
  510. pBike = (CBicycle *)m_children[n];
  511. ZeroMemory(&rdi, sizeof(RESULTDATAITEM) );
  512. rdi.mask = RDI_STR | // Displayname is valid
  513. RDI_IMAGE | // nImage is valid
  514. RDI_PARAM;
  515. rdi.nImage = pBike->GetBitmapIndex();
  516. rdi.str = MMC_CALLBACK;
  517. rdi.nCol = 0;
  518. rdi.lParam = (LPARAM)pBike;
  519. if(m_pResultData)
  520. hr = m_pResultData->InsertItem( &rdi );
  521. _ASSERT( SUCCEEDED(hr) );
  522. }
  523. return hr;
  524. }
  525. HRESULT CBicycleFolder::OnShow(IConsole *pConsole, BOOL bShow, HSCOPEITEM scopeitem)
  526. {
  527. HRESULT hr = S_OK;
  528. IHeaderCtrl *pHeaderCtrl = NULL;
  529. if (bShow)
  530. {
  531. hr = pConsole->QueryInterface(IID_IHeaderCtrl, (void **)&pHeaderCtrl);
  532. _ASSERT( SUCCEEDED(hr) );
  533. hr = pConsole->QueryInterface(IID_IResultData, (void **)&m_pResultData);
  534. _ASSERT( SUCCEEDED(hr) );
  535. // Set the column headers in the results pane
  536. hr = pHeaderCtrl->InsertColumn(0, L"Name", LVCFMT_LEFT, 150);
  537. _ASSERT( S_OK == hr );
  538. hr = pHeaderCtrl->InsertColumn(1, L"Owner", LVCFMT_LEFT, 200);
  539. _ASSERT( S_OK == hr );
  540. if(m_pResultData)
  541. {
  542. hr = m_pResultData->DeleteAllRsltItems();
  543. _ASSERT( SUCCEEDED(hr) );
  544. if(!bExpanded)
  545. {
  546. hr = DisplayChildren();
  547. }
  548. pHeaderCtrl->Release();
  549. }
  550. }
  551. return hr;
  552. }
  553. CIceSkateFolder::CIceSkateFolder()
  554. {
  555. for (int n = 0; n < NUMBER_OF_CHILDREN; n++) {
  556. children[n] = new CIceSkate(n + 1);
  557. }
  558. }
  559. CIceSkateFolder::~CIceSkateFolder()
  560. {
  561. for (int n = 0; n < NUMBER_OF_CHILDREN; n++)
  562. if (children[n]) {
  563. delete children[n];
  564. }
  565. }
  566. HRESULT CIceSkateFolder::OnShow(IConsole *pConsole, BOOL bShow, HSCOPEITEM scopeitem)
  567. {
  568. HRESULT hr = S_OK;
  569. IHeaderCtrl *pHeaderCtrl = NULL;
  570. IResultData *pResultData = NULL;
  571. if (bShow) {
  572. hr = pConsole->QueryInterface(IID_IHeaderCtrl, (void **)&pHeaderCtrl);
  573. _ASSERT( SUCCEEDED(hr) );
  574. hr = pConsole->QueryInterface(IID_IResultData, (void **)&pResultData);
  575. _ASSERT( SUCCEEDED(hr) );
  576. // Set the column headers in the results pane
  577. hr = pHeaderCtrl->InsertColumn( 0, L"Name ", 0, MMCLV_AUTO );
  578. _ASSERT( S_OK == hr );
  579. // insert items here
  580. RESULTDATAITEM rdi;
  581. hr = pResultData->DeleteAllRsltItems();
  582. _ASSERT( SUCCEEDED(hr) );
  583. if (!bExpanded)
  584. {
  585. // create the child nodes, then expand them
  586. for (int n = 0; n < NUMBER_OF_CHILDREN; n++)
  587. {
  588. ZeroMemory(&rdi, sizeof(RESULTDATAITEM) );
  589. rdi.mask = RDI_STR | // Displayname is valid
  590. RDI_IMAGE | // nImage is valid
  591. RDI_PARAM;
  592. rdi.nImage = children[n]->GetBitmapIndex();
  593. rdi.str = MMC_CALLBACK;
  594. rdi.nCol = 0;
  595. rdi.lParam = (LPARAM)children[n];
  596. hr = pResultData->InsertItem( &rdi );
  597. _ASSERT( SUCCEEDED(hr) );
  598. }
  599. }
  600. pHeaderCtrl->Release();
  601. pResultData->Release();
  602. }
  603. return hr;
  604. }
  605. //================================================
  606. CSkateboardFolder::CSkateboardFolder()
  607. {
  608. for (int n = 0; n < NUMBER_OF_CHILDREN; n++) {
  609. children[n] = new CSkateboard(n + 1);
  610. }
  611. }
  612. CSkateboardFolder::~CSkateboardFolder()
  613. {
  614. for (int n = 0; n < NUMBER_OF_CHILDREN; n++)
  615. if (children[n]) {
  616. delete children[n];
  617. }
  618. }
  619. HRESULT CSkateboardFolder::OnShow(IConsole *pConsole, BOOL bShow, HSCOPEITEM scopeitem)
  620. {
  621. HRESULT hr = S_OK;
  622. IHeaderCtrl *pHeaderCtrl = NULL;
  623. IResultData *pResultData = NULL;
  624. if (bShow) {
  625. hr = pConsole->QueryInterface(IID_IHeaderCtrl, (void **)&pHeaderCtrl);
  626. _ASSERT( SUCCEEDED(hr) );
  627. hr = pConsole->QueryInterface(IID_IResultData, (void **)&pResultData);
  628. _ASSERT( SUCCEEDED(hr) );
  629. // Set the column headers in the results pane
  630. hr = pHeaderCtrl->InsertColumn( 0, L"Name ", 0, MMCLV_AUTO );
  631. _ASSERT( S_OK == hr );
  632. // insert items here
  633. RESULTDATAITEM rdi;
  634. hr = pResultData->DeleteAllRsltItems();
  635. _ASSERT( SUCCEEDED(hr) );
  636. if (!bExpanded) {
  637. // create the child nodes, then expand them
  638. for (int n = 0; n < NUMBER_OF_CHILDREN; n++) {
  639. ZeroMemory(&rdi, sizeof(RESULTDATAITEM) );
  640. rdi.mask = RDI_STR | // Displayname is valid
  641. RDI_IMAGE | // nImage is valid
  642. RDI_PARAM;
  643. rdi.nImage = children[n]->GetBitmapIndex();
  644. rdi.str = MMC_CALLBACK;
  645. rdi.nCol = 0;
  646. rdi.lParam = (LPARAM)children[n];
  647. hr = pResultData->InsertItem( &rdi );
  648. _ASSERT( SUCCEEDED(hr) );
  649. }
  650. }
  651. pHeaderCtrl->Release();
  652. pResultData->Release();
  653. }
  654. return hr;
  655. }
  656. //=====================================================
  657. const _TCHAR *CSkateboard::GetDisplayName(int nCol)
  658. {
  659. static _TCHAR buf[128];
  660. _stprintf(buf, _T("Skateboard #%d"), id);
  661. return buf;
  662. }
  663. //=====================================================
  664. const _TCHAR *CIceSkate::GetDisplayName(int nCol)
  665. {
  666. static _TCHAR buf[128];
  667. _stprintf(buf, _T("Ice Skate #%d"), id);
  668. return buf;
  669. }
  670. //========================================
  671. CBicycle::CBicycle(CBicycleFolder *parent, IWbemClassObject *inst) :
  672. m_parent(parent),
  673. m_inst(inst)
  674. {
  675. if(m_inst)
  676. m_inst->AddRef();
  677. }
  678. // helper values for calling GetDisplayName().
  679. #define NAME_COL 0
  680. #define OWNER_COL 1
  681. #define COLOR_COL 2
  682. #define MATERIAL_COL 3
  683. const _TCHAR *CBicycle::GetDisplayName(int nCol)
  684. {
  685. static _TCHAR buf[128];
  686. // Get the corresponding property for nCol. This is in-proc local copy
  687. // so its pretty fast even if IWbemServices is a remote connection.
  688. if(m_inst)
  689. {
  690. VARIANT pVal;
  691. WCHAR propName[10] = {0};
  692. VariantInit(&pVal);
  693. switch(nCol)
  694. {
  695. case 0:
  696. wcscpy(propName, L"Name");
  697. break;
  698. case 1:
  699. wcscpy(propName, L"Owner");
  700. break;
  701. // these wont be needed by MMC but its makes this routine more useful
  702. // internal to the class.
  703. case 2:
  704. wcscpy(propName, L"Color");
  705. break;
  706. case 3:
  707. wcscpy(propName, L"Material");
  708. break;
  709. } //endswitch
  710. if(m_inst->Get(propName, 0L, &pVal, NULL, NULL) == S_OK)
  711. {
  712. bstr_t temp(pVal);
  713. _tcscpy(buf, (LPTSTR)temp);
  714. }
  715. VariantClear(&pVal);
  716. } //endif (m_inst)
  717. return buf;
  718. }
  719. bool CBicycle::GetGirls(void)
  720. {
  721. VARIANT_BOOL retval = VARIANT_FALSE;
  722. // Here's how to get/interpret a VT_BOOL property.
  723. if(m_inst)
  724. {
  725. VARIANT pVal;
  726. if(m_inst->Get(L"Girls", 0L, &pVal, NULL, NULL) == S_OK)
  727. {
  728. retval = V_BOOL(&pVal);
  729. }
  730. VariantClear(&pVal);
  731. } //endif (m_inst)
  732. return (retval == VARIANT_TRUE);
  733. }
  734. void CBicycle::LoadSurfaces(HWND hwndDlg, BYTE iSurface)
  735. {
  736. HWND hCombo = GetDlgItem(hwndDlg, IDC_PEOPLE_SURFACE);
  737. HRESULT hr = E_FAIL;
  738. IWbemQualifierSet *qualSet = 0;
  739. int selected = 0;
  740. // qualifiers only exist on the class definition. m_inst is a instance.
  741. IWbemClassObject *pClass = 0;
  742. IWbemServices *service = 0;
  743. if(SUCCEEDED(m_parent->GetPtr(&service)))
  744. {
  745. hr = service->GetObject((bstr_t)L"Bicycle", 0,0, &pClass, 0);
  746. if(SUCCEEDED(hr = pClass->GetPropertyQualifierSet((bstr_t)L"Surface",
  747. &qualSet)))
  748. {
  749. VARIANT vList;
  750. VariantInit(&vList);
  751. if(SUCCEEDED(hr = qualSet->Get((bstr_t)L"Values", 0, &vList, 0)))
  752. {
  753. SAFEARRAY *pma = V_ARRAY(&vList);
  754. long lLowerBound = 0, lUpperBound = 0 ;
  755. UINT idx = 0;
  756. SafeArrayGetLBound(pma, 1, &lLowerBound);
  757. SafeArrayGetUBound(pma, 1, &lUpperBound);
  758. for(long x = lLowerBound; x <= lUpperBound; x++)
  759. {
  760. BSTR vSurface;
  761. SafeArrayGetElement(pma, &x, &vSurface);
  762. // NOTE: taking advantage of the bstr_t's conversion operators.
  763. // really cleans up the code.
  764. bstr_t temp(vSurface);
  765. UINT idx = ComboBox_AddString(hCombo, (LPTSTR)temp);
  766. ComboBox_SetItemData(hCombo, idx, x);
  767. // is this the one we want to select?
  768. if(iSurface == x)
  769. {
  770. selected = x;
  771. }
  772. } //endfor
  773. VariantClear(&vList);
  774. ComboBox_SetCurSel(hCombo, selected);
  775. }
  776. qualSet->Release();
  777. qualSet = 0;
  778. } //endif GetPropertyQualifierSet()
  779. service->Release();
  780. } //endif GetPtr()
  781. }
  782. const TCHAR *CBicycle::ConvertSurfaceValue(BYTE val)
  783. {
  784. // Convert a enum to a string using the Value{} array.
  785. static TCHAR temp[128] = {0};
  786. return temp;
  787. }
  788. HRESULT CBicycle::PutProperty(LPWSTR propName, LPTSTR str)
  789. {
  790. HRESULT hr = E_FAIL;
  791. if(m_inst)
  792. {
  793. VARIANT pVal;
  794. bstr_t temp(str);
  795. VariantInit(&pVal);
  796. V_BSTR(&pVal) = temp;
  797. V_VT(&pVal) = VT_BSTR;
  798. hr = m_inst->Put(propName, 0L, &pVal, 0);
  799. VariantClear(&pVal);
  800. } //endif (m_inst)
  801. return hr;
  802. }
  803. HRESULT CBicycle::PutProperty(LPWSTR propName, BYTE val)
  804. {
  805. HRESULT hr = E_FAIL;
  806. if(m_inst)
  807. {
  808. VARIANT pVal;
  809. VariantInit(&pVal);
  810. V_UI1(&pVal) = val;
  811. V_VT(&pVal) = VT_UI1;
  812. hr = m_inst->Put(propName, 0L, &pVal, 0);
  813. VariantClear(&pVal);
  814. } //endif (m_inst)
  815. return hr;
  816. }
  817. HRESULT CBicycle::PutProperty(LPWSTR propName, bool val)
  818. {
  819. HRESULT hr = E_FAIL;
  820. if(m_inst)
  821. {
  822. VARIANT pVal;
  823. VariantInit(&pVal);
  824. V_BOOL(&pVal) = (val?VARIANT_TRUE: VARIANT_FALSE);
  825. V_VT(&pVal) = VT_BOOL;
  826. hr = m_inst->Put(propName, 0L, &pVal, 0);
  827. VariantClear(&pVal);
  828. } //endif (m_inst)
  829. return hr;
  830. }
  831. // handle anything special when the user clicks Apply or Ok
  832. // on the property sheet. This sample directly accesses the
  833. // operated-on object, so there's nothing special do to...
  834. HRESULT CBicycle::OnPropertyChange()
  835. {
  836. return S_OK;
  837. }
  838. HRESULT CBicycle::OnSelect(IConsole *pConsole, BOOL bScope, BOOL bSelect)
  839. {
  840. IConsoleVerb *pConsoleVerb;
  841. HRESULT hr = pConsole->QueryConsoleVerb(&pConsoleVerb);
  842. _ASSERT(SUCCEEDED(hr));
  843. // can't get to properties (via the standard methods) unless
  844. // we tell MMC to display the Properties menu item and
  845. // toolbar button, this wil give the user a visual cue that
  846. // there's "something" to do
  847. hr = pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);
  848. pConsoleVerb->Release();
  849. return S_OK;
  850. }
  851. // Implement the dialog proc
  852. BOOL CALLBACK CBicycle::DialogProc(
  853. HWND hwndDlg, // handle to dialog box
  854. UINT uMsg, // message
  855. WPARAM wParam, // first message parameter
  856. LPARAM lParam // second message parameter
  857. )
  858. {
  859. static CBicycle *pBike = NULL;
  860. switch (uMsg)
  861. {
  862. case WM_INITDIALOG:
  863. {
  864. // catch the "this" pointer so we can actually operate on the object
  865. pBike = reinterpret_cast<CBicycle *>(reinterpret_cast<PROPSHEETPAGE *>(lParam)->lParam);
  866. SetDlgItemText(hwndDlg, IDC_PEOPLE_NAME, pBike->GetDisplayName(NAME_COL));
  867. SetDlgItemText(hwndDlg, IDC_PEOPLE_COLOR, pBike->GetDisplayName(COLOR_COL));
  868. SetDlgItemText(hwndDlg, IDC_PEOPLE_MATERIAL, pBike->GetDisplayName(MATERIAL_COL));
  869. SetDlgItemText(hwndDlg, IDC_PEOPLE_OWNER, pBike->GetDisplayName(OWNER_COL));
  870. Button_SetCheck(GetDlgItem(hwndDlg, IDC_PEOPLE_GIRLS),
  871. (pBike->GetGirls()? BST_CHECKED: BST_UNCHECKED));
  872. VARIANT pVal;
  873. VariantInit(&pVal);
  874. if(SUCCEEDED(pBike->m_inst->Get((bstr_t)L"Surface", 0L, &pVal, NULL, NULL)))
  875. {
  876. pBike->m_iSurface = V_UI1(&pVal);
  877. pBike->LoadSurfaces(hwndDlg, pBike->m_iSurface);
  878. VariantClear(&pVal);
  879. }
  880. }
  881. break;
  882. case WM_COMMAND:
  883. // turn the Apply button on
  884. if (HIWORD(wParam) == EN_CHANGE ||
  885. HIWORD(wParam) == CBN_SELCHANGE)
  886. SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
  887. break;
  888. case WM_DESTROY:
  889. // tell MMC that we're done with the property sheet (we got this
  890. // handle in CreatePropertyPages
  891. MMCFreeNotifyHandle(pBike->m_ppHandle);
  892. break;
  893. case WM_NOTIFY:
  894. switch(((NMHDR *)lParam)->code)
  895. {
  896. case PSN_APPLY:
  897. {
  898. bool changed = false;
  899. TCHAR temp[50] = {0};
  900. HRESULT hr = S_OK;
  901. HWND hWnd = GetDlgItem(hwndDlg, IDC_PEOPLE_NAME);
  902. if(hWnd && Edit_GetModify(hWnd))
  903. {
  904. GetWindowText(hWnd, temp, 50);
  905. changed |= SUCCEEDED(pBike->PutProperty(L"Name", temp));
  906. }
  907. hWnd = GetDlgItem(hwndDlg, IDC_PEOPLE_COLOR);
  908. if(hWnd && Edit_GetModify(hWnd))
  909. {
  910. GetWindowText(hWnd, temp, 50);
  911. changed |= SUCCEEDED(pBike->PutProperty(L"Color", temp));
  912. }
  913. hWnd = GetDlgItem(hwndDlg, IDC_PEOPLE_MATERIAL);
  914. if(hWnd && Edit_GetModify(hWnd))
  915. {
  916. GetWindowText(hWnd, temp, 50);
  917. changed |= SUCCEEDED(pBike->PutProperty(L"Material", temp));
  918. }
  919. hWnd = GetDlgItem(hwndDlg, IDC_PEOPLE_OWNER);
  920. if(hWnd && Edit_GetModify(hWnd))
  921. {
  922. GetWindowText(hWnd, temp, 50);
  923. changed |= SUCCEEDED(hr = pBike->PutProperty(L"Owner", temp));
  924. }
  925. hWnd = GetDlgItem(hwndDlg, IDC_PEOPLE_SURFACE);
  926. if(hWnd)
  927. {
  928. BYTE newValue = ComboBox_GetCurSel(hWnd);
  929. if(newValue != pBike->m_iSurface)
  930. {
  931. changed |= SUCCEEDED(pBike->PutProperty(L"Surface", newValue));
  932. }
  933. }
  934. hWnd = GetDlgItem(hwndDlg, IDC_PEOPLE_GIRLS);
  935. if(hWnd)
  936. {
  937. bool checked = (Button_GetState(hWnd) & BST_CHECKED);
  938. bool wasChecked = pBike->GetGirls();
  939. // did it change?
  940. if(checked != wasChecked)
  941. {
  942. changed |= SUCCEEDED(pBike->PutProperty(L"Girls", checked));
  943. }
  944. }
  945. // if any property changed, write it back to WMI.
  946. if(changed)
  947. {
  948. IWbemServices *service = 0;
  949. // dialogs run in their own thread so use the marshaling helper
  950. // get a useable IWbemServices ptr.
  951. // NOTE: IWbemClassObjects are in-proc so they DONT need to be
  952. // marshaled.
  953. if(SUCCEEDED(pBike->m_parent->GetPtr(&service)))
  954. {
  955. service->PutInstance(pBike->m_inst, WBEM_FLAG_CREATE_OR_UPDATE, 0, 0);
  956. service->Release();
  957. HRESULT hr = MMCPropertyChangeNotify(pBike->m_ppHandle, (long)pBike);
  958. }
  959. }
  960. }
  961. break;
  962. } // endswitch (((NMHDR *)lParam)->code)
  963. break;
  964. } // endswitch (uMsg)
  965. return DefWindowProc(hwndDlg, uMsg, wParam, lParam);
  966. }
  967. HRESULT CBicycle::HasPropertySheets()
  968. {
  969. // say "yes" when MMC asks if we have pages
  970. return S_OK;
  971. }
  972. HRESULT CBicycle::CreatePropertyPages(IPropertySheetCallback *lpProvider, LONG_PTR handle)
  973. {
  974. PROPSHEETPAGE psp;
  975. HPROPSHEETPAGE hPage = NULL;
  976. // cache this handle so we can call MMCPropertyChangeNotify
  977. m_ppHandle = handle;
  978. // create the property page for this node.
  979. // NOTE: if your node has multiple pages, put the following
  980. // in a loop and create multiple pages calling
  981. // lpProvider->AddPage() for each page.
  982. psp.dwSize = sizeof(PROPSHEETPAGE);
  983. psp.dwFlags = PSP_DEFAULT | PSP_USETITLE;
  984. psp.hInstance = g_hinst;
  985. psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPPAGE_PEOPLE);
  986. psp.pfnDlgProc = DialogProc;
  987. psp.lParam = reinterpret_cast<LPARAM>(this);
  988. psp.pszTitle = MAKEINTRESOURCE(IDS_BIKE_TITLE);
  989. hPage = CreatePropertySheetPage(&psp);
  990. _ASSERT(hPage);
  991. return lpProvider->AddPage(hPage);
  992. }
  993. HRESULT CBicycle::GetWatermarks(HBITMAP *lphWatermark,
  994. HBITMAP *lphHeader,
  995. HPALETTE *lphPalette,
  996. BOOL *bStretch)
  997. {
  998. return S_FALSE;
  999. }