|
|
#include "pch.hxx"
#include <notify.h>
#include "oenotify.h"
#include <BadStrFunctions.h>
//+-------------------------------------------------------------------------
// Prototypes
//--------------------------------------------------------------------------
HRESULT WriteStructInfo(LPSTREAM pStream, LPCSTRUCTINFO pStruct); HRESULT ReadBuildStructInfoParam(LPSTREAM pStream, LPSTRUCTINFO pStruct);
#ifdef DEBUG
BOOL ByteCompare(LPBYTE pb1, LPBYTE pb2, ULONG cb); void DebugValidateStructInfo(LPCSTRUCTINFO pStruct); #endif
static const char c_szMutex[] = "mutex"; static const char c_szMappedFile[] = "mappedfile";
OESTDAPI_(HRESULT) CreateNotify(INotify **ppNotify) { CNotify *pNotify;
Assert(ppNotify != NULL);
pNotify = new CNotify;
*ppNotify = (INotify *)pNotify;
return(pNotify == NULL ? E_OUTOFMEMORY : S_OK); }
//+-------------------------------------------------------------------------
// CNotify::CNotify
//--------------------------------------------------------------------------
CNotify::CNotify(void) { TraceCall("CNotify::CNotify"); m_cRef = 1; m_hMutex = NULL; m_hFileMap = NULL; m_pTable = NULL; m_fLocked = FALSE; m_hwndLock = NULL; }
//+-------------------------------------------------------------------------
// CNotify::~CNotify
//--------------------------------------------------------------------------
CNotify::~CNotify(void) { TraceCall("CNotify::~CNotify"); Assert(!m_fLocked); if (m_pTable) UnmapViewOfFile(m_pTable); SafeCloseHandle(m_hFileMap); SafeCloseHandle(m_hMutex); }
//+-------------------------------------------------------------------------
// CNotify::AddRef
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CNotify::AddRef(void) { TraceCall("CNotify::AddRef"); return InterlockedIncrement(&m_cRef); }
//+-------------------------------------------------------------------------
// CNotify::Release
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CNotify::Release(void) { TraceCall("CNotify::Release"); LONG cRef = InterlockedDecrement(&m_cRef); if (0 == cRef) delete this; return (ULONG)cRef; }
//+-------------------------------------------------------------------------
// CNotify::QueryInterface
//--------------------------------------------------------------------------
STDMETHODIMP CNotify::QueryInterface(REFIID riid, LPVOID *ppv) { // Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CNotify::QueryInterface");
// Find IID
if (IID_IUnknown == riid) *ppv = (IUnknown *)this; else { *ppv = NULL; hr = TraceResult(E_NOINTERFACE); goto exit; }
// AddRef It
((IUnknown *)*ppv)->AddRef();
exit: // Done
return hr; }
//+-------------------------------------------------------------------------
// CNotify::Initialize
//--------------------------------------------------------------------------
HRESULT CNotify::Initialize(LPCSTR pszName) { // Locals
HRESULT hr=S_OK; LPSTR pszObject=NULL; LPSTR pszT; DWORD dwReturn; BOOL fReleaseMutex=FALSE;
// Stack
TraceCall("CNotify::Initialize");
// Invalid Arg
Assert(pszName);
// Already Initialized...
Assert(NULL == m_hMutex && NULL == m_hFileMap && NULL == m_pTable);
// Allocate pszObject
DWORD cchSize = (lstrlen(pszName) + lstrlen(c_szMutex) + 1); IF_NULLEXIT(pszObject = PszAllocA(sizeof(pszObject[0]) * cchSize));
// Make pszObject
wnsprintf(pszObject, cchSize, "%s%s", pszName, c_szMutex);
// Create the mutex
ReplaceChars(pszObject, '\\', '_'); IF_NULLEXIT(m_hMutex = CreateMutex(NULL, FALSE, pszObject));
// Lets grab the mutex so we can party with the memory-mapped file
dwReturn = WaitForSingleObject(m_hMutex, MSEC_WAIT_NOTIFY); if (WAIT_OBJECT_0 != dwReturn) { hr = TraceResult(E_FAIL); goto exit; }
// Release mutex on exit
fReleaseMutex = TRUE;
// Free pszObject
g_pMalloc->Free(pszObject);
// Allocate pszObject
cchSize = (lstrlen(pszName) + lstrlen(c_szMappedFile) + 1); IF_NULLEXIT(pszObject = PszAllocA(sizeof(pszObject[0]) * cchSize));
// Make pszObject
wnsprintf(pszObject, cchSize, "%s%s", pszName, c_szMappedFile);
// Create the memory mapped file using the system swapfile
ReplaceChars(pszObject, '\\', '_'); IF_NULLEXIT(m_hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(NOTIFYWINDOWTABLE), pszObject));
// Map a view of the memory mapped file
IF_NULLEXIT(m_pTable = (LPNOTIFYWINDOWTABLE)MapViewOfFile(m_hFileMap, FILE_MAP_WRITE, 0, 0, sizeof(NOTIFYWINDOWTABLE)));
exit: // Release ?
if (fReleaseMutex) ReleaseMutex(m_hMutex);
// Cleanup
SafeMemFree(pszObject);
// Done
return hr; }
//+-------------------------------------------------------------------------
// CNotify::Lock
//--------------------------------------------------------------------------
HRESULT CNotify::Lock(HWND hwnd) { // Locals
HRESULT hr=S_OK; DWORD dwReturn;
// Stack
TraceCall("CNotify::Lock");
// We should not be locked right now
Assert(FALSE == m_fLocked && NULL != m_hMutex);
// Grap the Mutex
dwReturn = WaitForSingleObject(m_hMutex, MSEC_WAIT_NOTIFY); if (WAIT_OBJECT_0 != dwReturn) { hr = TraceResult(E_FAIL); goto exit; }
// Save the window and set new state
m_hwndLock = hwnd; m_fLocked = TRUE;
exit: // Done
return hr; }
//+-------------------------------------------------------------------------
// CNotify::Unlock
//--------------------------------------------------------------------------
HRESULT CNotify::Unlock(void) { // Stack
TraceCall("CNotify::Unlock");
// We should be locked
Assert(m_fLocked);
// Release the mutex
ReleaseMutex(m_hMutex);
// Reset state
m_hwndLock = NULL; m_fLocked = FALSE;
// Done
return S_OK; }
//+-------------------------------------------------------------------------
// CNotify::NotificationNeeded - Must have called ::Lock(hwndLock)
//--------------------------------------------------------------------------
HRESULT CNotify::NotificationNeeded(void) { // Locals
HRESULT hr=S_FALSE;
// Stack
TraceCall("CNotify::NotificationNeeded");
// We should be locked
Assert(m_fLocked);
// If there are no windows...
if (0 == m_pTable->cWindows) goto exit;
// If there is only one registered window and its m_hwndLock...
if (1 == m_pTable->cWindows && m_pTable->rgWindow[0].hwndNotify && m_hwndLock == m_pTable->rgWindow[0].hwndNotify) goto exit;
// Otherwise, we need to do a notification
hr = S_OK;
exit: // Done
return hr; }
//+-------------------------------------------------------------------------
// CNotify::Register
//--------------------------------------------------------------------------
HRESULT CNotify::Register(HWND hwndNotify, HWND hwndThunk, BOOL fExternal) { // Locals
HRESULT hr=S_OK; DWORD dwReturn; ULONG i; LPNOTIFYWINDOW pEntry=NULL; LPNOTIFYWINDOW pRow; BOOL fReleaseMutex=FALSE;
// Stack
TraceCall("CNotify::Register");
// Invalid Arg
Assert(hwndThunk && IsWindow(hwndThunk) && hwndNotify && IsWindow(hwndNotify)); // FIX by having hwndNotify created on an HTML that won't be destroyed when one of the windows goes away.
// Validate the state
Assert(m_pTable && m_hMutex && m_hFileMap && FALSE == m_fLocked);
// Grap the mutex
dwReturn = WaitForSingleObject(m_hMutex, MSEC_WAIT_NOTIFY); if (WAIT_OBJECT_0 != dwReturn) { hr = TraceResult(E_FAIL); goto exit; }
// Release the mutex
fReleaseMutex = TRUE;
// Lets try to use an empty entry in the table first
for (i=0; i<m_pTable->cWindows; i++) { // Readability
pRow = &m_pTable->rgWindow[i];
// Is this not empty ?
if (NULL == pRow->hwndThunk || NULL == pRow->hwndNotify || !IsWindow(pRow->hwndThunk) || !IsWindow(pRow->hwndNotify)) { pEntry = pRow; break; } } // If we didn't find an entry yet, lets add into the end
if (NULL == pEntry) { // If we still have room
if (m_pTable->cWindows >= CMAX_HWND_NOTIFY) { hr = TraceResult(E_FAIL); goto exit; }
// Append
pEntry = &m_pTable->rgWindow[m_pTable->cWindows]; m_pTable->cWindows++; }
// Set pEntry
Assert(pEntry); pEntry->hwndThunk = hwndThunk; pEntry->hwndNotify = hwndNotify; pEntry->fExternal = fExternal;
exit: // Release Mutex ?
if (fReleaseMutex) ReleaseMutex(m_hMutex);
// Done
return hr; }
//+-------------------------------------------------------------------------
// CNotify::Unregister
//--------------------------------------------------------------------------
HRESULT CNotify::Unregister(HWND hwndNotify) { // Locals
HRESULT hr=S_OK; DWORD dwReturn; ULONG i; LPNOTIFYWINDOW pEntry=NULL; LPNOTIFYWINDOW pRow; BOOL fReleaseMutex=FALSE;
// Stack
TraceCall("CNotify::Unregister");
// Invalid Arg
Assert(hwndNotify && IsWindow(hwndNotify));
// Validate the state
Assert(m_pTable && m_hMutex && m_hFileMap && FALSE == m_fLocked);
// Grap the mutex
dwReturn = WaitForSingleObject(m_hMutex, MSEC_WAIT_NOTIFY); if (WAIT_OBJECT_0 != dwReturn) { hr = TraceResult(E_FAIL); goto exit; }
// Release the mutex
fReleaseMutex = TRUE;
// Lets try to use an empty entry in the table first
for (i=0; i<m_pTable->cWindows; i++) { // Readability
pRow = &m_pTable->rgWindow[i];
// Is this the row
// HWNDs are unique so only need to check notify window for match
if (hwndNotify == pRow->hwndNotify) { pRow->hwndThunk = NULL; pRow->hwndNotify = NULL; break; } } exit: // Release Mutex ?
if (fReleaseMutex) ReleaseMutex(m_hMutex);
// Done
return hr; }
//+-------------------------------------------------------------------------
// CNotify::DoNotification
//--------------------------------------------------------------------------
HRESULT CNotify::DoNotification(UINT uWndMsg, WPARAM wParam, LPARAM lParam, DWORD dwFlags) { // Locals
HRESULT hr=S_OK; DWORD dwThisProcess; DWORD dwNotifyProcess; DWORD dwResult; LPNOTIFYWINDOW pRow; ULONG i; DWORD_PTR dw; NOTIFYDATA rNotify;
// Stack
TraceCall("CNotify::DoNotify");
// State
Assert(m_fLocked);
// Get this process Id
dwThisProcess = GetCurrentProcessId();
// Lets try to use an empty entry in the table first
for (i=0; i<m_pTable->cWindows; i++) { // Readability
pRow = &m_pTable->rgWindow[i];
// If the notify window is valid
if (NULL == pRow->hwndNotify || !IsWindow(pRow->hwndNotify)) continue;
// Skip the window that locked this notify
if (m_hwndLock == pRow->hwndNotify) continue;
// Get the process in which the destination window resides
GetWindowThreadProcessId(pRow->hwndNotify, &dwNotifyProcess);
// Initialize Notify Info
ZeroMemory(&rNotify, sizeof(NOTIFYDATA));
// Set notification window
rNotify.hwndNotify = pRow->hwndNotify;
// Allow for callback to remap wParam and lParam
if (ISFLAGSET(dwFlags, SNF_CALLBACK)) { // Call callback function
IF_FAILEXIT(hr = ((PFNNOTIFYCALLBACK)wParam)(lParam, &rNotify, (BOOL)(dwThisProcess != dwNotifyProcess), pRow->fExternal)); }
// Otherwise, setup rNotifyInfo myself
else { // Setup NOtification
rNotify.msg = uWndMsg; rNotify.wParam = wParam; rNotify.lParam = lParam; }
// Set the current Flags
rNotify.dwFlags |= dwFlags;
// No Cross-Process
if (dwThisProcess != dwNotifyProcess && !ISFLAGSET(rNotify.dwFlags, SNF_CROSSPROCESS)) continue;
// If the notify window is out of process
if (dwThisProcess != dwNotifyProcess && ISFLAGSET(rNotify.dwFlags, SNF_HASTHUNKINFO)) { // Thunk the notification to another process
Assert(rNotify.rCopyData.lpData); SendMessageTimeout(pRow->hwndThunk, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&rNotify.rCopyData, SMTO_ABORTIFHUNG, 1500, &dw);
// Un-register
if (dw == SNR_UNREGISTER) { pRow->hwndNotify = NULL; pRow->hwndThunk = NULL; }
// Cleanup
SafeMemFree(rNotify.rCopyData.lpData); }
// Otherwise, its within this process...
else if (ISFLAGSET(dwFlags, SNF_SENDMSG)) { // Do in-process send message
if (SendMessage(pRow->hwndNotify, rNotify.msg, rNotify.wParam, rNotify.lParam) == SNR_UNREGISTER) { pRow->hwndNotify = NULL; pRow->hwndThunk = NULL; } }
// Otherwise, just do a PostMessage
else PostMessage(pRow->hwndNotify, rNotify.msg, rNotify.wParam, rNotify.lParam); }
exit: // Done
return hr; }
// ------------------------------------------------------------
// HWND pRow->hwndNotify
// ------------------------------------------------------------
// UINT uWndMsg
// ------------------------------------------------------------
// DWORD dwFlags (SNF_xxx)
// ------------------------------------------------------------
// DWORD pParam1->dwFlags
// ------------------------------------------------------------
// DWORD pParam1->cbStruct
// ------------------------------------------------------------
// DWORD pParam1->cMembers
// ------------------------------------------------------------
// Param1 Members (DWORD dwFlags, DWORD cbData, BYTE prgData)
// ------------------------------------------------------------
// DWORD pParam2->dwFlags
// ------------------------------------------------------------
// DWORD pParam2->cbStruct
// ------------------------------------------------------------
// DWORD pParam2->cMembers
// ------------------------------------------------------------
// Param2 Members (DWORD cbType, DWORD cbData, BYTE prgData)
// ------------------------------------------------------------
//+-------------------------------------------------------------------------
// BuildNotificationPackage
//--------------------------------------------------------------------------
OESTDAPI_(HRESULT) BuildNotificationPackage(LPNOTIFYDATA pNotify, PCOPYDATASTRUCT pCopyData) { // Locals
HRESULT hr=S_OK; CByteStream cStream;
// Trace
TraceCall("BuildNotificationPackage");
// Args
Assert(pNotify && IsWindow(pNotify->hwndNotify) && pCopyData);
// Zero the copy data struct
ZeroMemory(pCopyData, sizeof(COPYDATASTRUCT));
// Set dwData
pCopyData->dwData = MSOEAPI_ACDM_NOTIFY;
// Write hwndNotify
IF_FAILEXIT(hr = cStream.Write(&pNotify->hwndNotify, sizeof(pNotify->hwndNotify), NULL));
// Write uWndMsg
IF_FAILEXIT(hr = cStream.Write(&pNotify->msg, sizeof(pNotify->msg), NULL));
// Write dwFlags
IF_FAILEXIT(hr = cStream.Write(&pNotify->dwFlags, sizeof(pNotify->dwFlags), NULL));
// Write pParam1
if (ISFLAGSET(pNotify->dwFlags, SNF_VALIDPARAM1)) { IF_FAILEXIT(hr = WriteStructInfo(&cStream, &pNotify->rParam1)); }
// Write pParam2
if (ISFLAGSET(pNotify->dwFlags, SNF_VALIDPARAM2)) { IF_FAILEXIT(hr = WriteStructInfo(&cStream, &pNotify->rParam2)); }
// Take the bytes out of the byte stream
cStream.AcquireBytes(&pCopyData->cbData, (LPBYTE *)&pCopyData->lpData, ACQ_DISPLACE);
exit: // Done
return hr; }
//+-------------------------------------------------------------------------
// CrackNotificationPackage
//--------------------------------------------------------------------------
OESTDAPI_(HRESULT) CrackNotificationPackage(PCOPYDATASTRUCT pCopyData, LPNOTIFYDATA pNotify) { // Locals
HRESULT hr=S_OK; DWORD dwParam; DWORD cb; LPBYTE pb; CByteStream cStream((LPBYTE)pCopyData->lpData, pCopyData->cbData);
// Trace
TraceCall("CrackNotificationPackage");
// Args
Assert(pCopyData && pNotify); Assert(pCopyData->dwData == MSOEAPI_ACDM_NOTIFY);
// Init
ZeroMemory(pNotify, sizeof(NOTIFYDATA));
// Read hwndNotify
IF_FAILEXIT(hr = cStream.Read(&pNotify->hwndNotify, sizeof(pNotify->hwndNotify), NULL));
// Read uWndMsg
IF_FAILEXIT(hr = cStream.Read(&pNotify->msg, sizeof(pNotify->msg), NULL));
// Read dwFlags
IF_FAILEXIT(hr = cStream.Read(&pNotify->dwFlags, sizeof(pNotify->dwFlags), NULL));
// Read pwParam
if (ISFLAGSET(pNotify->dwFlags, SNF_VALIDPARAM1)) { // Read It
IF_FAILEXIT(hr = ReadBuildStructInfoParam(&cStream, &pNotify->rParam1));
// Set wParam
pNotify->wParam = (WPARAM)pNotify->rParam1.pbStruct; }
// Read pParam2
if (ISFLAGSET(pNotify->dwFlags, SNF_VALIDPARAM2)) { // Read It
IF_FAILEXIT(hr = ReadBuildStructInfoParam(&cStream, &pNotify->rParam2));
// Set lParam
pNotify->lParam = (WPARAM)pNotify->rParam2.pbStruct; }
exit: // pull the bytes back out of cStream so it doesn't try to free it
cStream.AcquireBytes(&cb, &pb, ACQ_DISPLACE);
// Done
return hr; }
//+-------------------------------------------------------------------------
// WriteStructInfo
//--------------------------------------------------------------------------
HRESULT WriteStructInfo(LPSTREAM pStream, LPCSTRUCTINFO pStruct) { // Locals
HRESULT hr=S_OK; LPMEMBERINFO pMember; ULONG i;
// Trace
TraceCall("WriteStructInfo");
// Args
Assert(pStream && pStruct && pStruct->pbStruct);
// Make sure the structinfo is good
#ifdef DEBUG
DebugValidateStructInfo(pStruct); #endif
// Write dwFlags
IF_FAILEXIT(hr = pStream->Write(&pStruct->dwFlags, sizeof(pStruct->dwFlags), NULL));
// Write cbStruct
IF_FAILEXIT(hr = pStream->Write(&pStruct->cbStruct, sizeof(pStruct->cbStruct), NULL));
// Write cMembers
IF_FAILEXIT(hr = pStream->Write(&pStruct->cMembers, sizeof(pStruct->cMembers), NULL));
// Validate cMembers
Assert(pStruct->cMembers <= CMAX_STRUCT_MEMBERS);
// If there are no members
if (0 == pStruct->cMembers) { // Better have this flag set
Assert(ISFLAGSET(pStruct->dwFlags, STRUCTINFO_VALUEONLY));
// If pointer
if (ISFLAGSET(pStruct->dwFlags, STRUCTINFO_POINTER)) { IF_FAILEXIT(hr = pStream->Write(pStruct->pbStruct, pStruct->cbStruct, NULL)); }
// pStruct->pbStruct contains DWORD sized value
else { // Size should be equal to sizeof pbStruct
Assert(pStruct->cbStruct == sizeof(pStruct->pbStruct));
// Write It
IF_FAILEXIT(hr = pStream->Write(&pStruct->pbStruct, sizeof(pStruct->pbStruct), NULL)); }
// Done
goto exit; }
// WriteStructInfoMembers
for (i=0; i<pStruct->cMembers; i++) { // Readability
pMember = (LPMEMBERINFO)&pStruct->rgMember[i];
// Write pMember->dwFlags
IF_FAILEXIT(hr = pStream->Write(&pMember->dwFlags, sizeof(pMember->dwFlags), NULL));
// Validate
Assert(!ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER) ? pMember->cbData <= pMember->cbSize : sizeof(LPBYTE) == pMember->cbSize);
// Write pMember->cbSize
IF_FAILEXIT(hr = pStream->Write(&pMember->cbSize, sizeof(pMember->cbSize), NULL));
// Write pMember->cbData
IF_FAILEXIT(hr = pStream->Write(&pMember->cbData, sizeof(pMember->cbData), NULL));
// Write pMember->pbData
if (pMember->cbData) { IF_FAILEXIT(hr = pStream->Write(pMember->pbData, pMember->cbData, NULL)); } }
exit: // Done
return hr; }
//+-------------------------------------------------------------------------
// ReadBuildStructInfoParam
//--------------------------------------------------------------------------
HRESULT ReadBuildStructInfoParam(LPSTREAM pStream, LPSTRUCTINFO pStruct) { // Locals
HRESULT hr=S_OK; DWORD dwOffset=0; LPMEMBERINFO pMember; ULONG i;
// Trace
TraceCall("ReadBuildStructInfoParam");
// Args
Assert(pStream && pStruct);
// Init
ZeroMemory(pStruct, sizeof(STRUCTINFO));
// Read dwFlags
IF_FAILEXIT(hr = pStream->Read(&pStruct->dwFlags, sizeof(pStruct->dwFlags), NULL));
// Read cbStruct
IF_FAILEXIT(hr = pStream->Read(&pStruct->cbStruct, sizeof(pStruct->cbStruct), NULL));
// Read cMembers
IF_FAILEXIT(hr = pStream->Read(&pStruct->cMembers, sizeof(pStruct->cMembers), NULL));
// If there are no members
if (0 == pStruct->cMembers) { // Better have this flag set
Assert(ISFLAGSET(pStruct->dwFlags, STRUCTINFO_VALUEONLY));
// If pointer
if (ISFLAGSET(pStruct->dwFlags, STRUCTINFO_POINTER)) { // Allocate pbStruct
IF_NULLEXIT(pStruct->pbStruct = (LPBYTE)g_pMalloc->Alloc(pStruct->cbStruct));
// Read It
IF_FAILEXIT(hr = pStream->Read(pStruct->pbStruct, pStruct->cbStruct, NULL)); }
// pStruct->pbStruct contains DWORD sized value
else { // Size should be less than or equal to pbStruct
Assert(pStruct->cbStruct == sizeof(pStruct->pbStruct));
// Read the Data
IF_FAILEXIT(hr = pStream->Read(&pStruct->pbStruct, sizeof(pStruct->pbStruct), NULL)); }
// Done
goto exit; }
// Allocate pbStruct
IF_NULLEXIT(pStruct->pbStruct = (LPBYTE)g_pMalloc->Alloc(pStruct->cbStruct));
// Validate cMembers
Assert(pStruct->cMembers <= CMAX_STRUCT_MEMBERS);
// ReadStructInfoMembers
for (i=0; i<pStruct->cMembers; i++) { // Readability
pMember = &pStruct->rgMember[i];
// Write pMember->dwFlags
IF_FAILEXIT(hr = pStream->Read(&pMember->dwFlags, sizeof(pMember->dwFlags), NULL));
// Write pMember->cbSize
IF_FAILEXIT(hr = pStream->Read(&pMember->cbSize, sizeof(pMember->cbSize), NULL));
// Write pMember->cbData
IF_FAILEXIT(hr = pStream->Read(&pMember->cbData, sizeof(pMember->cbData), NULL));
// Validate
Assert(!ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER) ? pMember->cbData <= pMember->cbSize : sizeof(LPBYTE) == pMember->cbSize);
// Write pMember->pbData
if (pMember->cbData) { // Allocate
IF_NULLEXIT(pMember->pbData = (LPBYTE)g_pMalloc->Alloc(max(pMember->cbSize, pMember->cbData)));
// Read It
IF_FAILEXIT(hr = pStream->Read(pMember->pbData, pMember->cbData, NULL)); } }
// Build pbStruct
for (i=0; i<pStruct->cMembers; i++) { // Readability
pMember = &pStruct->rgMember[i];
// If not a pointer...
if (ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER)) { // Validate
Assert(pMember->cbSize == sizeof(LPBYTE));
// Copy the pointer
CopyMemory((LPBYTE)(pStruct->pbStruct + dwOffset), &pMember->pbData, sizeof(LPBYTE)); }
// Otherwise, its just a value
else { // Copy the pointer
CopyMemory((LPBYTE)(pStruct->pbStruct + dwOffset), pMember->pbData, pMember->cbData); }
// Increment dwOffset
dwOffset += pMember->cbSize; }
// Validate the structure
#ifdef DEBUG
DebugValidateStructInfo(pStruct); #endif
// Free things that were not referenced by pointer
for (i=0; i<pStruct->cMembers; i++) { // Readability
pMember = &pStruct->rgMember[i];
// If not a pointer...
if (!ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER)) { // This was copied into pbStruct
SafeMemFree(pMember->pbData); } }
exit: // Done
return hr; }
#ifdef DEBUG
BOOL ByteCompare(LPBYTE pb1, LPBYTE pb2, ULONG cb) { for (ULONG i=0; i<cb; i++) { if (pb1[i] != pb2[i]) { Assert(FALSE); return FALSE; } } return TRUE; }
//+-------------------------------------------------------------------------
// DebugValidateStructInfo
//--------------------------------------------------------------------------
void DebugValidateStructInfo(LPCSTRUCTINFO pStruct) { // Locals
LPMEMBERINFO pMember; LPBYTE pb; DWORD dwOffset=0; ULONG i;
// WriteStructInfoMembers
for (i=0; i<pStruct->cMembers; i++) { // Readability
pMember = (LPMEMBERINFO)&pStruct->rgMember[i];
// If not a pointer...
if (ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER)) { // If null pointer
if (ISFLAGSET(pMember->dwFlags, MEMBERINFO_POINTER_NULL)) { Assert(pMember->cbData == 0 && pMember->pbData == NULL); CopyMemory(&pb, (LPBYTE)(pStruct->pbStruct + dwOffset), sizeof(LPBYTE)); Assert(pb == NULL); }
// Otherwise
else { // Copy the pointer
CopyMemory(&pb, (LPBYTE)(pStruct->pbStruct + dwOffset), sizeof(LPBYTE));
// Compare the memory
ByteCompare(pb, pMember->pbData, pMember->cbData); } }
// Otherwise, its a pointer
else { // Compare
ByteCompare((LPBYTE)(pStruct->pbStruct + dwOffset), pMember->pbData, pMember->cbData); }
// Increment offset
dwOffset += pMember->cbSize; } } #endif
|