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
944 lines
27 KiB
#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
|