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.

944 lines
27 KiB

  1. #include "pch.hxx"
  2. #include <notify.h>
  3. #include "oenotify.h"
  4. #include <BadStrFunctions.h>
  5. //+-------------------------------------------------------------------------
  6. // Prototypes
  7. //--------------------------------------------------------------------------
  8. HRESULT WriteStructInfo(LPSTREAM pStream, LPCSTRUCTINFO pStruct);
  9. HRESULT ReadBuildStructInfoParam(LPSTREAM pStream, LPSTRUCTINFO pStruct);
  10. #ifdef DEBUG
  11. BOOL ByteCompare(LPBYTE pb1, LPBYTE pb2, ULONG cb);
  12. void DebugValidateStructInfo(LPCSTRUCTINFO pStruct);
  13. #endif
  14. static const char c_szMutex[] = "mutex";
  15. static const char c_szMappedFile[] = "mappedfile";
  16. OESTDAPI_(HRESULT) CreateNotify(INotify **ppNotify)
  17. {
  18. CNotify *pNotify;
  19. Assert(ppNotify != NULL);
  20. pNotify = new CNotify;
  21. *ppNotify = (INotify *)pNotify;
  22. return(pNotify == NULL ? E_OUTOFMEMORY : S_OK);
  23. }
  24. //+-------------------------------------------------------------------------
  25. // CNotify::CNotify
  26. //--------------------------------------------------------------------------
  27. CNotify::CNotify(void)
  28. {
  29. TraceCall("CNotify::CNotify");
  30. m_cRef = 1;
  31. m_hMutex = NULL;
  32. m_hFileMap = NULL;
  33. m_pTable = NULL;
  34. m_fLocked = FALSE;
  35. m_hwndLock = NULL;
  36. }
  37. //+-------------------------------------------------------------------------
  38. // CNotify::~CNotify
  39. //--------------------------------------------------------------------------
  40. CNotify::~CNotify(void)
  41. {
  42. TraceCall("CNotify::~CNotify");
  43. Assert(!m_fLocked);
  44. if (m_pTable)
  45. UnmapViewOfFile(m_pTable);
  46. SafeCloseHandle(m_hFileMap);
  47. SafeCloseHandle(m_hMutex);
  48. }
  49. //+-------------------------------------------------------------------------
  50. // CNotify::AddRef
  51. //--------------------------------------------------------------------------
  52. STDMETHODIMP_(ULONG) CNotify::AddRef(void)
  53. {
  54. TraceCall("CNotify::AddRef");
  55. return InterlockedIncrement(&m_cRef);
  56. }
  57. //+-------------------------------------------------------------------------
  58. // CNotify::Release
  59. //--------------------------------------------------------------------------
  60. STDMETHODIMP_(ULONG) CNotify::Release(void)
  61. {
  62. TraceCall("CNotify::Release");
  63. LONG cRef = InterlockedDecrement(&m_cRef);
  64. if (0 == cRef)
  65. delete this;
  66. return (ULONG)cRef;
  67. }
  68. //+-------------------------------------------------------------------------
  69. // CNotify::QueryInterface
  70. //--------------------------------------------------------------------------
  71. STDMETHODIMP CNotify::QueryInterface(REFIID riid, LPVOID *ppv)
  72. {
  73. // Locals
  74. HRESULT hr=S_OK;
  75. // Stack
  76. TraceCall("CNotify::QueryInterface");
  77. // Find IID
  78. if (IID_IUnknown == riid)
  79. *ppv = (IUnknown *)this;
  80. else
  81. {
  82. *ppv = NULL;
  83. hr = TraceResult(E_NOINTERFACE);
  84. goto exit;
  85. }
  86. // AddRef It
  87. ((IUnknown *)*ppv)->AddRef();
  88. exit:
  89. // Done
  90. return hr;
  91. }
  92. //+-------------------------------------------------------------------------
  93. // CNotify::Initialize
  94. //--------------------------------------------------------------------------
  95. HRESULT CNotify::Initialize(LPCSTR pszName)
  96. {
  97. // Locals
  98. HRESULT hr=S_OK;
  99. LPSTR pszObject=NULL;
  100. LPSTR pszT;
  101. DWORD dwReturn;
  102. BOOL fReleaseMutex=FALSE;
  103. // Stack
  104. TraceCall("CNotify::Initialize");
  105. // Invalid Arg
  106. Assert(pszName);
  107. // Already Initialized...
  108. Assert(NULL == m_hMutex && NULL == m_hFileMap && NULL == m_pTable);
  109. // Allocate pszObject
  110. DWORD cchSize = (lstrlen(pszName) + lstrlen(c_szMutex) + 1);
  111. IF_NULLEXIT(pszObject = PszAllocA(sizeof(pszObject[0]) * cchSize));
  112. // Make pszObject
  113. wnsprintf(pszObject, cchSize, "%s%s", pszName, c_szMutex);
  114. // Create the mutex
  115. ReplaceChars(pszObject, '\\', '_');
  116. IF_NULLEXIT(m_hMutex = CreateMutex(NULL, FALSE, pszObject));
  117. // Lets grab the mutex so we can party with the memory-mapped file
  118. dwReturn = WaitForSingleObject(m_hMutex, MSEC_WAIT_NOTIFY);
  119. if (WAIT_OBJECT_0 != dwReturn)
  120. {
  121. hr = TraceResult(E_FAIL);
  122. goto exit;
  123. }
  124. // Release mutex on exit
  125. fReleaseMutex = TRUE;
  126. // Free pszObject
  127. g_pMalloc->Free(pszObject);
  128. // Allocate pszObject
  129. cchSize = (lstrlen(pszName) + lstrlen(c_szMappedFile) + 1);
  130. IF_NULLEXIT(pszObject = PszAllocA(sizeof(pszObject[0]) * cchSize));
  131. // Make pszObject
  132. wnsprintf(pszObject, cchSize, "%s%s", pszName, c_szMappedFile);
  133. // Create the memory mapped file using the system swapfile
  134. ReplaceChars(pszObject, '\\', '_');
  135. IF_NULLEXIT(m_hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(NOTIFYWINDOWTABLE), pszObject));
  136. // Map a view of the memory mapped file
  137. IF_NULLEXIT(m_pTable = (LPNOTIFYWINDOWTABLE)MapViewOfFile(m_hFileMap, FILE_MAP_WRITE, 0, 0, sizeof(NOTIFYWINDOWTABLE)));
  138. exit:
  139. // Release ?
  140. if (fReleaseMutex)
  141. ReleaseMutex(m_hMutex);
  142. // Cleanup
  143. SafeMemFree(pszObject);
  144. // Done
  145. return hr;
  146. }
  147. //+-------------------------------------------------------------------------
  148. // CNotify::Lock
  149. //--------------------------------------------------------------------------
  150. HRESULT CNotify::Lock(HWND hwnd)
  151. {
  152. // Locals
  153. HRESULT hr=S_OK;
  154. DWORD dwReturn;
  155. // Stack
  156. TraceCall("CNotify::Lock");
  157. // We should not be locked right now
  158. Assert(FALSE == m_fLocked && NULL != m_hMutex);
  159. // Grap the Mutex
  160. dwReturn = WaitForSingleObject(m_hMutex, MSEC_WAIT_NOTIFY);
  161. if (WAIT_OBJECT_0 != dwReturn)
  162. {
  163. hr = TraceResult(E_FAIL);
  164. goto exit;
  165. }
  166. // Save the window and set new state
  167. m_hwndLock = hwnd;
  168. m_fLocked = TRUE;
  169. exit:
  170. // Done
  171. return hr;
  172. }
  173. //+-------------------------------------------------------------------------
  174. // CNotify::Unlock
  175. //--------------------------------------------------------------------------
  176. HRESULT CNotify::Unlock(void)
  177. {
  178. // Stack
  179. TraceCall("CNotify::Unlock");
  180. // We should be locked
  181. Assert(m_fLocked);
  182. // Release the mutex
  183. ReleaseMutex(m_hMutex);
  184. // Reset state
  185. m_hwndLock = NULL;
  186. m_fLocked = FALSE;
  187. // Done
  188. return S_OK;
  189. }
  190. //+-------------------------------------------------------------------------
  191. // CNotify::NotificationNeeded - Must have called ::Lock(hwndLock)
  192. //--------------------------------------------------------------------------
  193. HRESULT CNotify::NotificationNeeded(void)
  194. {
  195. // Locals
  196. HRESULT hr=S_FALSE;
  197. // Stack
  198. TraceCall("CNotify::NotificationNeeded");
  199. // We should be locked
  200. Assert(m_fLocked);
  201. // If there are no windows...
  202. if (0 == m_pTable->cWindows)
  203. goto exit;
  204. // If there is only one registered window and its m_hwndLock...
  205. if (1 == m_pTable->cWindows && m_pTable->rgWindow[0].hwndNotify && m_hwndLock == m_pTable->rgWindow[0].hwndNotify)
  206. goto exit;
  207. // Otherwise, we need to do a notification
  208. hr = S_OK;
  209. exit:
  210. // Done
  211. return hr;
  212. }
  213. //+-------------------------------------------------------------------------
  214. // CNotify::Register
  215. //--------------------------------------------------------------------------
  216. HRESULT CNotify::Register(HWND hwndNotify, HWND hwndThunk, BOOL fExternal)
  217. {
  218. // Locals
  219. HRESULT hr=S_OK;
  220. DWORD dwReturn;
  221. ULONG i;
  222. LPNOTIFYWINDOW pEntry=NULL;
  223. LPNOTIFYWINDOW pRow;
  224. BOOL fReleaseMutex=FALSE;
  225. // Stack
  226. TraceCall("CNotify::Register");
  227. // Invalid Arg
  228. Assert(hwndThunk && IsWindow(hwndThunk) && hwndNotify && IsWindow(hwndNotify));
  229. // FIX by having hwndNotify created on an HTML that won't be destroyed when one of the windows goes away.
  230. // Validate the state
  231. Assert(m_pTable && m_hMutex && m_hFileMap && FALSE == m_fLocked);
  232. // Grap the mutex
  233. dwReturn = WaitForSingleObject(m_hMutex, MSEC_WAIT_NOTIFY);
  234. if (WAIT_OBJECT_0 != dwReturn)
  235. {
  236. hr = TraceResult(E_FAIL);
  237. goto exit;
  238. }
  239. // Release the mutex
  240. fReleaseMutex = TRUE;
  241. // Lets try to use an empty entry in the table first
  242. for (i=0; i<m_pTable->cWindows; i++)
  243. {
  244. // Readability
  245. pRow = &m_pTable->rgWindow[i];
  246. // Is this not empty ?
  247. if (NULL == pRow->hwndThunk || NULL == pRow->hwndNotify || !IsWindow(pRow->hwndThunk) || !IsWindow(pRow->hwndNotify))
  248. {
  249. pEntry = pRow;
  250. break;
  251. }
  252. }
  253. // If we didn't find an entry yet, lets add into the end
  254. if (NULL == pEntry)
  255. {
  256. // If we still have room
  257. if (m_pTable->cWindows >= CMAX_HWND_NOTIFY)
  258. {
  259. hr = TraceResult(E_FAIL);
  260. goto exit;
  261. }
  262. // Append
  263. pEntry = &m_pTable->rgWindow[m_pTable->cWindows];
  264. m_pTable->cWindows++;
  265. }
  266. // Set pEntry
  267. Assert(pEntry);
  268. pEntry->hwndThunk = hwndThunk;
  269. pEntry->hwndNotify = hwndNotify;
  270. pEntry->fExternal = fExternal;
  271. exit:
  272. // Release Mutex ?
  273. if (fReleaseMutex)
  274. ReleaseMutex(m_hMutex);
  275. // Done
  276. return hr;
  277. }
  278. //+-------------------------------------------------------------------------
  279. // CNotify::Unregister
  280. //--------------------------------------------------------------------------
  281. HRESULT CNotify::Unregister(HWND hwndNotify)
  282. {
  283. // Locals
  284. HRESULT hr=S_OK;
  285. DWORD dwReturn;
  286. ULONG i;
  287. LPNOTIFYWINDOW pEntry=NULL;
  288. LPNOTIFYWINDOW pRow;
  289. BOOL fReleaseMutex=FALSE;
  290. // Stack
  291. TraceCall("CNotify::Unregister");
  292. // Invalid Arg
  293. Assert(hwndNotify && IsWindow(hwndNotify));
  294. // Validate the state
  295. Assert(m_pTable && m_hMutex && m_hFileMap && FALSE == m_fLocked);
  296. // Grap the mutex
  297. dwReturn = WaitForSingleObject(m_hMutex, MSEC_WAIT_NOTIFY);
  298. if (WAIT_OBJECT_0 != dwReturn)
  299. {
  300. hr = TraceResult(E_FAIL);
  301. goto exit;
  302. }
  303. // Release the mutex
  304. fReleaseMutex = TRUE;
  305. // Lets try to use an empty entry in the table first
  306. for (i=0; i<m_pTable->cWindows; i++)
  307. {
  308. // Readability
  309. pRow = &m_pTable->rgWindow[i];
  310. // Is this the row
  311. // HWNDs are unique so only need to check notify window for match
  312. if (hwndNotify == pRow->hwndNotify)
  313. {
  314. pRow->hwndThunk = NULL;
  315. pRow->hwndNotify = NULL;
  316. break;
  317. }
  318. }
  319. exit:
  320. // Release Mutex ?
  321. if (fReleaseMutex)
  322. ReleaseMutex(m_hMutex);
  323. // Done
  324. return hr;
  325. }
  326. //+-------------------------------------------------------------------------
  327. // CNotify::DoNotification
  328. //--------------------------------------------------------------------------
  329. HRESULT CNotify::DoNotification(UINT uWndMsg, WPARAM wParam, LPARAM lParam, DWORD dwFlags)
  330. {
  331. // Locals
  332. HRESULT hr=S_OK;
  333. DWORD dwThisProcess;
  334. DWORD dwNotifyProcess;
  335. DWORD dwResult;
  336. LPNOTIFYWINDOW pRow;
  337. ULONG i;
  338. DWORD_PTR dw;
  339. NOTIFYDATA rNotify;
  340. // Stack
  341. TraceCall("CNotify::DoNotify");
  342. // State
  343. Assert(m_fLocked);
  344. // Get this process Id
  345. dwThisProcess = GetCurrentProcessId();
  346. // Lets try to use an empty entry in the table first
  347. for (i=0; i<m_pTable->cWindows; i++)
  348. {
  349. // Readability
  350. pRow = &m_pTable->rgWindow[i];
  351. // If the notify window is valid
  352. if (NULL == pRow->hwndNotify || !IsWindow(pRow->hwndNotify))
  353. continue;
  354. // Skip the window that locked this notify
  355. if (m_hwndLock == pRow->hwndNotify)
  356. continue;
  357. // Get the process in which the destination window resides
  358. GetWindowThreadProcessId(pRow->hwndNotify, &dwNotifyProcess);
  359. // Initialize Notify Info
  360. ZeroMemory(&rNotify, sizeof(NOTIFYDATA));
  361. // Set notification window
  362. rNotify.hwndNotify = pRow->hwndNotify;
  363. // Allow for callback to remap wParam and lParam
  364. if (ISFLAGSET(dwFlags, SNF_CALLBACK))
  365. {
  366. // Call callback function
  367. IF_FAILEXIT(hr = ((PFNNOTIFYCALLBACK)wParam)(lParam, &rNotify, (BOOL)(dwThisProcess != dwNotifyProcess), pRow->fExternal));
  368. }
  369. // Otherwise, setup rNotifyInfo myself
  370. else
  371. {
  372. // Setup NOtification
  373. rNotify.msg = uWndMsg;
  374. rNotify.wParam = wParam;
  375. rNotify.lParam = lParam;
  376. }
  377. // Set the current Flags
  378. rNotify.dwFlags |= dwFlags;
  379. // No Cross-Process
  380. if (dwThisProcess != dwNotifyProcess && !ISFLAGSET(rNotify.dwFlags, SNF_CROSSPROCESS))
  381. continue;
  382. // If the notify window is out of process
  383. if (dwThisProcess != dwNotifyProcess && ISFLAGSET(rNotify.dwFlags, SNF_HASTHUNKINFO))
  384. {
  385. // Thunk the notification to another process
  386. Assert(rNotify.rCopyData.lpData);
  387. SendMessageTimeout(pRow->hwndThunk, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&rNotify.rCopyData, SMTO_ABORTIFHUNG, 1500, &dw);
  388. // Un-register
  389. if (dw == SNR_UNREGISTER)
  390. {
  391. pRow->hwndNotify = NULL;
  392. pRow->hwndThunk = NULL;
  393. }
  394. // Cleanup
  395. SafeMemFree(rNotify.rCopyData.lpData);
  396. }
  397. // Otherwise, its within this process...
  398. else if (ISFLAGSET(dwFlags, SNF_SENDMSG))
  399. {
  400. // Do in-process send message
  401. if (SendMessage(pRow->hwndNotify, rNotify.msg, rNotify.wParam, rNotify.lParam) == SNR_UNREGISTER)
  402. {
  403. pRow->hwndNotify = NULL;
  404. pRow->hwndThunk = NULL;
  405. }
  406. }
  407. // Otherwise, just do a PostMessage
  408. else
  409. PostMessage(pRow->hwndNotify, rNotify.msg, rNotify.wParam, rNotify.lParam);
  410. }
  411. exit:
  412. // Done
  413. return hr;
  414. }
  415. // ------------------------------------------------------------
  416. // HWND pRow->hwndNotify
  417. // ------------------------------------------------------------
  418. // UINT uWndMsg
  419. // ------------------------------------------------------------
  420. // DWORD dwFlags (SNF_xxx)
  421. // ------------------------------------------------------------
  422. // DWORD pParam1->dwFlags
  423. // ------------------------------------------------------------
  424. // DWORD pParam1->cbStruct
  425. // ------------------------------------------------------------
  426. // DWORD pParam1->cMembers
  427. // ------------------------------------------------------------
  428. // Param1 Members (DWORD dwFlags, DWORD cbData, BYTE prgData)
  429. // ------------------------------------------------------------
  430. // DWORD pParam2->dwFlags
  431. // ------------------------------------------------------------
  432. // DWORD pParam2->cbStruct
  433. // ------------------------------------------------------------
  434. // DWORD pParam2->cMembers
  435. // ------------------------------------------------------------
  436. // Param2 Members (DWORD cbType, DWORD cbData, BYTE prgData)
  437. // ------------------------------------------------------------
  438. //+-------------------------------------------------------------------------
  439. // BuildNotificationPackage
  440. //--------------------------------------------------------------------------
  441. OESTDAPI_(HRESULT) BuildNotificationPackage(LPNOTIFYDATA pNotify, PCOPYDATASTRUCT pCopyData)
  442. {
  443. // Locals
  444. HRESULT hr=S_OK;
  445. CByteStream cStream;
  446. // Trace
  447. TraceCall("BuildNotificationPackage");
  448. // Args
  449. Assert(pNotify && IsWindow(pNotify->hwndNotify) && pCopyData);
  450. // Zero the copy data struct
  451. ZeroMemory(pCopyData, sizeof(COPYDATASTRUCT));
  452. // Set dwData
  453. pCopyData->dwData = MSOEAPI_ACDM_NOTIFY;
  454. // Write hwndNotify
  455. IF_FAILEXIT(hr = cStream.Write(&pNotify->hwndNotify, sizeof(pNotify->hwndNotify), NULL));
  456. // Write uWndMsg
  457. IF_FAILEXIT(hr = cStream.Write(&pNotify->msg, sizeof(pNotify->msg), NULL));
  458. // Write dwFlags
  459. IF_FAILEXIT(hr = cStream.Write(&pNotify->dwFlags, sizeof(pNotify->dwFlags), NULL));
  460. // Write pParam1
  461. if (ISFLAGSET(pNotify->dwFlags, SNF_VALIDPARAM1))
  462. {
  463. IF_FAILEXIT(hr = WriteStructInfo(&cStream, &pNotify->rParam1));
  464. }
  465. // Write pParam2
  466. if (ISFLAGSET(pNotify->dwFlags, SNF_VALIDPARAM2))
  467. {
  468. IF_FAILEXIT(hr = WriteStructInfo(&cStream, &pNotify->rParam2));
  469. }
  470. // Take the bytes out of the byte stream
  471. cStream.AcquireBytes(&pCopyData->cbData, (LPBYTE *)&pCopyData->lpData, ACQ_DISPLACE);
  472. exit:
  473. // Done
  474. return hr;
  475. }
  476. //+-------------------------------------------------------------------------
  477. // CrackNotificationPackage
  478. //--------------------------------------------------------------------------
  479. OESTDAPI_(HRESULT) CrackNotificationPackage(PCOPYDATASTRUCT pCopyData, LPNOTIFYDATA pNotify)
  480. {
  481. // Locals
  482. HRESULT hr=S_OK;
  483. DWORD dwParam;
  484. DWORD cb;
  485. LPBYTE pb;
  486. CByteStream cStream((LPBYTE)pCopyData->lpData, pCopyData->cbData);
  487. // Trace
  488. TraceCall("CrackNotificationPackage");
  489. // Args
  490. Assert(pCopyData && pNotify);
  491. Assert(pCopyData->dwData == MSOEAPI_ACDM_NOTIFY);
  492. // Init
  493. ZeroMemory(pNotify, sizeof(NOTIFYDATA));
  494. // Read hwndNotify
  495. IF_FAILEXIT(hr = cStream.Read(&pNotify->hwndNotify, sizeof(pNotify->hwndNotify), NULL));
  496. // Read uWndMsg
  497. IF_FAILEXIT(hr = cStream.Read(&pNotify->msg, sizeof(pNotify->msg), NULL));
  498. // Read dwFlags
  499. IF_FAILEXIT(hr = cStream.Read(&pNotify->dwFlags, sizeof(pNotify->dwFlags), NULL));
  500. // Read pwParam
  501. if (ISFLAGSET(pNotify->dwFlags, SNF_VALIDPARAM1))
  502. {
  503. // Read It
  504. IF_FAILEXIT(hr = ReadBuildStructInfoParam(&cStream, &pNotify->rParam1));
  505. // Set wParam
  506. pNotify->wParam = (WPARAM)pNotify->rParam1.pbStruct;
  507. }
  508. // Read pParam2
  509. if (ISFLAGSET(pNotify->dwFlags, SNF_VALIDPARAM2))
  510. {
  511. // Read It
  512. IF_FAILEXIT(hr = ReadBuildStructInfoParam(&cStream, &pNotify->rParam2));
  513. // Set lParam
  514. pNotify->lParam = (WPARAM)pNotify->rParam2.pbStruct;
  515. }
  516. exit:
  517. // pull the bytes back out of cStream so it doesn't try to free it
  518. cStream.AcquireBytes(&cb, &pb, ACQ_DISPLACE);
  519. // Done
  520. return hr;
  521. }
  522. //+-------------------------------------------------------------------------
  523. // WriteStructInfo
  524. //--------------------------------------------------------------------------
  525. HRESULT WriteStructInfo(LPSTREAM pStream, LPCSTRUCTINFO pStruct)
  526. {
  527. // Locals
  528. HRESULT hr=S_OK;
  529. LPMEMBERINFO pMember;
  530. ULONG i;
  531. // Trace
  532. TraceCall("WriteStructInfo");
  533. // Args
  534. Assert(pStream && pStruct && pStruct->pbStruct);
  535. // Make sure the structinfo is good
  536. #ifdef DEBUG
  537. DebugValidateStructInfo(pStruct);
  538. #endif
  539. // Write dwFlags
  540. IF_FAILEXIT(hr = pStream->Write(&pStruct->dwFlags, sizeof(pStruct->dwFlags), NULL));
  541. // Write cbStruct
  542. IF_FAILEXIT(hr = pStream->Write(&pStruct->cbStruct, sizeof(pStruct->cbStruct), NULL));
  543. // Write cMembers
  544. IF_FAILEXIT(hr = pStream->Write(&pStruct->cMembers, sizeof(pStruct->cMembers), NULL));
  545. // Validate cMembers
  546. Assert(pStruct->cMembers <= CMAX_STRUCT_MEMBERS);
  547. // If there are no members
  548. if (0 == pStruct->cMembers)
  549. {
  550. // Better have this flag set
  551. Assert(ISFLAGSET(pStruct->dwFlags, STRUCTINFO_VALUEONLY));
  552. // If pointer
  553. if (ISFLAGSET(pStruct->dwFlags, STRUCTINFO_POINTER))
  554. {
  555. IF_FAILEXIT(hr = pStream->Write(pStruct->pbStruct, pStruct->cbStruct, NULL));
  556. }
  557. // pStruct->pbStruct contains DWORD sized value
  558. else
  559. {
  560. // Size should be equal to sizeof pbStruct
  561. Assert(pStruct->cbStruct == sizeof(pStruct->pbStruct));
  562. // Write It
  563. IF_FAILEXIT(hr = pStream->Write(&pStruct->pbStruct, sizeof(pStruct->pbStruct), NULL));
  564. }
  565. // Done
  566. goto exit;
  567. }
  568. // WriteStructInfoMembers
  569. for (i=0; i<pStruct->cMembers; i++)
  570. {
  571. // Readability
  572. pMember = (LPMEMBERINFO)&pStruct->rgMember[i];
  573. // Write pMember->dwFlags
  574. IF_FAILEXIT(hr = pStream->Write(&pMember->dwFlags, sizeof(pMember->dwFlags), NULL));
  575. // Validate
  576. Assert(!ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER) ? pMember->cbData <= pMember->cbSize : sizeof(LPBYTE) == pMember->cbSize);
  577. // Write pMember->cbSize
  578. IF_FAILEXIT(hr = pStream->Write(&pMember->cbSize, sizeof(pMember->cbSize), NULL));
  579. // Write pMember->cbData
  580. IF_FAILEXIT(hr = pStream->Write(&pMember->cbData, sizeof(pMember->cbData), NULL));
  581. // Write pMember->pbData
  582. if (pMember->cbData)
  583. {
  584. IF_FAILEXIT(hr = pStream->Write(pMember->pbData, pMember->cbData, NULL));
  585. }
  586. }
  587. exit:
  588. // Done
  589. return hr;
  590. }
  591. //+-------------------------------------------------------------------------
  592. // ReadBuildStructInfoParam
  593. //--------------------------------------------------------------------------
  594. HRESULT ReadBuildStructInfoParam(LPSTREAM pStream, LPSTRUCTINFO pStruct)
  595. {
  596. // Locals
  597. HRESULT hr=S_OK;
  598. DWORD dwOffset=0;
  599. LPMEMBERINFO pMember;
  600. ULONG i;
  601. // Trace
  602. TraceCall("ReadBuildStructInfoParam");
  603. // Args
  604. Assert(pStream && pStruct);
  605. // Init
  606. ZeroMemory(pStruct, sizeof(STRUCTINFO));
  607. // Read dwFlags
  608. IF_FAILEXIT(hr = pStream->Read(&pStruct->dwFlags, sizeof(pStruct->dwFlags), NULL));
  609. // Read cbStruct
  610. IF_FAILEXIT(hr = pStream->Read(&pStruct->cbStruct, sizeof(pStruct->cbStruct), NULL));
  611. // Read cMembers
  612. IF_FAILEXIT(hr = pStream->Read(&pStruct->cMembers, sizeof(pStruct->cMembers), NULL));
  613. // If there are no members
  614. if (0 == pStruct->cMembers)
  615. {
  616. // Better have this flag set
  617. Assert(ISFLAGSET(pStruct->dwFlags, STRUCTINFO_VALUEONLY));
  618. // If pointer
  619. if (ISFLAGSET(pStruct->dwFlags, STRUCTINFO_POINTER))
  620. {
  621. // Allocate pbStruct
  622. IF_NULLEXIT(pStruct->pbStruct = (LPBYTE)g_pMalloc->Alloc(pStruct->cbStruct));
  623. // Read It
  624. IF_FAILEXIT(hr = pStream->Read(pStruct->pbStruct, pStruct->cbStruct, NULL));
  625. }
  626. // pStruct->pbStruct contains DWORD sized value
  627. else
  628. {
  629. // Size should be less than or equal to pbStruct
  630. Assert(pStruct->cbStruct == sizeof(pStruct->pbStruct));
  631. // Read the Data
  632. IF_FAILEXIT(hr = pStream->Read(&pStruct->pbStruct, sizeof(pStruct->pbStruct), NULL));
  633. }
  634. // Done
  635. goto exit;
  636. }
  637. // Allocate pbStruct
  638. IF_NULLEXIT(pStruct->pbStruct = (LPBYTE)g_pMalloc->Alloc(pStruct->cbStruct));
  639. // Validate cMembers
  640. Assert(pStruct->cMembers <= CMAX_STRUCT_MEMBERS);
  641. // ReadStructInfoMembers
  642. for (i=0; i<pStruct->cMembers; i++)
  643. {
  644. // Readability
  645. pMember = &pStruct->rgMember[i];
  646. // Write pMember->dwFlags
  647. IF_FAILEXIT(hr = pStream->Read(&pMember->dwFlags, sizeof(pMember->dwFlags), NULL));
  648. // Write pMember->cbSize
  649. IF_FAILEXIT(hr = pStream->Read(&pMember->cbSize, sizeof(pMember->cbSize), NULL));
  650. // Write pMember->cbData
  651. IF_FAILEXIT(hr = pStream->Read(&pMember->cbData, sizeof(pMember->cbData), NULL));
  652. // Validate
  653. Assert(!ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER) ? pMember->cbData <= pMember->cbSize : sizeof(LPBYTE) == pMember->cbSize);
  654. // Write pMember->pbData
  655. if (pMember->cbData)
  656. {
  657. // Allocate
  658. IF_NULLEXIT(pMember->pbData = (LPBYTE)g_pMalloc->Alloc(max(pMember->cbSize, pMember->cbData)));
  659. // Read It
  660. IF_FAILEXIT(hr = pStream->Read(pMember->pbData, pMember->cbData, NULL));
  661. }
  662. }
  663. // Build pbStruct
  664. for (i=0; i<pStruct->cMembers; i++)
  665. {
  666. // Readability
  667. pMember = &pStruct->rgMember[i];
  668. // If not a pointer...
  669. if (ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER))
  670. {
  671. // Validate
  672. Assert(pMember->cbSize == sizeof(LPBYTE));
  673. // Copy the pointer
  674. CopyMemory((LPBYTE)(pStruct->pbStruct + dwOffset), &pMember->pbData, sizeof(LPBYTE));
  675. }
  676. // Otherwise, its just a value
  677. else
  678. {
  679. // Copy the pointer
  680. CopyMemory((LPBYTE)(pStruct->pbStruct + dwOffset), pMember->pbData, pMember->cbData);
  681. }
  682. // Increment dwOffset
  683. dwOffset += pMember->cbSize;
  684. }
  685. // Validate the structure
  686. #ifdef DEBUG
  687. DebugValidateStructInfo(pStruct);
  688. #endif
  689. // Free things that were not referenced by pointer
  690. for (i=0; i<pStruct->cMembers; i++)
  691. {
  692. // Readability
  693. pMember = &pStruct->rgMember[i];
  694. // If not a pointer...
  695. if (!ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER))
  696. {
  697. // This was copied into pbStruct
  698. SafeMemFree(pMember->pbData);
  699. }
  700. }
  701. exit:
  702. // Done
  703. return hr;
  704. }
  705. #ifdef DEBUG
  706. BOOL ByteCompare(LPBYTE pb1, LPBYTE pb2, ULONG cb)
  707. {
  708. for (ULONG i=0; i<cb; i++)
  709. {
  710. if (pb1[i] != pb2[i])
  711. {
  712. Assert(FALSE);
  713. return FALSE;
  714. }
  715. }
  716. return TRUE;
  717. }
  718. //+-------------------------------------------------------------------------
  719. // DebugValidateStructInfo
  720. //--------------------------------------------------------------------------
  721. void DebugValidateStructInfo(LPCSTRUCTINFO pStruct)
  722. {
  723. // Locals
  724. LPMEMBERINFO pMember;
  725. LPBYTE pb;
  726. DWORD dwOffset=0;
  727. ULONG i;
  728. // WriteStructInfoMembers
  729. for (i=0; i<pStruct->cMembers; i++)
  730. {
  731. // Readability
  732. pMember = (LPMEMBERINFO)&pStruct->rgMember[i];
  733. // If not a pointer...
  734. if (ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER))
  735. {
  736. // If null pointer
  737. if (ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER_NULL))
  738. {
  739. Assert(pMember->cbData == 0 && pMember->pbData == NULL);
  740. CopyMemory(&pb, (LPBYTE)(pStruct->pbStruct + dwOffset), sizeof(LPBYTE));
  741. Assert(pb == NULL);
  742. }
  743. // Otherwise
  744. else
  745. {
  746. // Copy the pointer
  747. CopyMemory(&pb, (LPBYTE)(pStruct->pbStruct + dwOffset), sizeof(LPBYTE));
  748. // Compare the memory
  749. ByteCompare(pb, pMember->pbData, pMember->cbData);
  750. }
  751. }
  752. // Otherwise, its a pointer
  753. else
  754. {
  755. // Compare
  756. ByteCompare((LPBYTE)(pStruct->pbStruct + dwOffset), pMember->pbData, pMember->cbData);
  757. }
  758. // Increment offset
  759. dwOffset += pMember->cbSize;
  760. }
  761. }
  762. #endif