863 lines
21 KiB
C++
863 lines
21 KiB
C++
//+-------------------------------------------------------------------
|
|
//
|
|
// File: smarshal.cxx
|
|
//
|
|
// Synopsis: Source code for Interface Marshaling stress test main
|
|
// driver functions. Source for individual tests is in
|
|
// testvar.cxx
|
|
//
|
|
// History: 21-Aug-95 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
#include <smarshal.hxx>
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Globals:
|
|
//
|
|
//--------------------------------------------------------------------
|
|
BOOL gfVerbose = FALSE; // print execution messages
|
|
BOOL gfDebug = FALSE; // print debug messages
|
|
|
|
DWORD giThreadModel = OPF_INITAPARTMENT; // threading model to use
|
|
int giTestVar = 0; // test variation to run
|
|
int giHighestTestVar = 2; // highest test var supported
|
|
|
|
int gicReps = 5; // number of repetitions of each test
|
|
int gicThreads = 1; // number of threads to use on each test
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Private Function ProtoTypes:
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT DoIfOperation(DWORD dwFlags, INTERFACEPARAMS *pIFD);
|
|
void DisplayHelp(void);
|
|
BOOL GetSwitch(CHAR *pCmdParam, CHAR *pszSwitch);
|
|
BOOL GetSwitchInt(CHAR *pCmdParam, CHAR *pszSwitch, int *pInt);
|
|
BOOL ParseCmdLine(int argc, char **argv);
|
|
int _cdecl main(int argc, char **argv);
|
|
|
|
BOOL FreeWaitForEvent(HANDLE hEvent);
|
|
BOOL AptWaitForEvent(HANDLE hEvent);
|
|
|
|
STDAPI_(LPSTREAM) CreateMemStm(DWORD cb, LPHANDLE phdl);
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Misc:
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
#ifndef _CAIRO_
|
|
// COM initialization flags; passed to CoInitialize.
|
|
typedef enum tagCOINIT
|
|
{
|
|
COINIT_MULTITHREADED = 0, // OLE calls objects on any thread.
|
|
COINIT_SINGLETHREADED = 1, // OLE calls objects on single thread.
|
|
COINIT_APARTMENTTHREADED = 2 // Apartment model
|
|
} COINIT;
|
|
|
|
WINOLEAPI CoInitializeEx(LPVOID pvReserved, DWORD);
|
|
#endif
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: main
|
|
//
|
|
// Synopsis: Entry point to EXE. Parse the command line, then run
|
|
// whatever test variations were selected.
|
|
//
|
|
// Notes: The test variation code is in testvars.cxx.
|
|
// The rest of this file is helper routines.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
int _cdecl main(int argc, char **argv)
|
|
{
|
|
// parse the command line
|
|
BOOL fRes = ParseCmdLine(argc, argv);
|
|
|
|
if (fRes)
|
|
{
|
|
// run the selected test variations
|
|
switch (giTestVar)
|
|
{
|
|
case 1: fRes = TestVar1();
|
|
break;
|
|
case 2: fRes = TestVar2();
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
// check the results
|
|
CHKTESTRESULT(fRes, "Marshal Stress Tests");
|
|
return 0;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: ParseCmdLine
|
|
//
|
|
// Synopsis: parses the execution parameters
|
|
//
|
|
//--------------------------------------------------------------------
|
|
BOOL ParseCmdLine(int argc, char **argv)
|
|
{
|
|
BOOL fDontRun = (argc == 1) ? TRUE : FALSE;
|
|
|
|
// the first parameter is the EXE name, skip it.
|
|
argc--;
|
|
argv++;
|
|
|
|
for (int i=0; i<argc; i++, argv++)
|
|
{
|
|
if (GetSwitch(*argv, "v"))
|
|
{
|
|
// run verbose
|
|
gfVerbose = TRUE;
|
|
}
|
|
else if (GetSwitch(*argv, "d"))
|
|
{
|
|
// run debug mode
|
|
gfVerbose = TRUE;
|
|
gfDebug = TRUE;
|
|
}
|
|
else if (GetSwitch(*argv, "h") || GetSwitch(*argv, "?"))
|
|
{
|
|
// help wanted
|
|
fDontRun = TRUE;
|
|
}
|
|
else if (GetSwitchInt(*argv, "var:", &giTestVar))
|
|
{
|
|
// selected test variation, ensure the variation is valid
|
|
if (giTestVar > giHighestTestVar)
|
|
{
|
|
ERROUT("Unknown Test Variation:%x\n", giTestVar);
|
|
fDontRun = TRUE;
|
|
}
|
|
}
|
|
else if (GetSwitchInt(*argv, "reps:", &gicReps))
|
|
{
|
|
; // selected repetition count
|
|
}
|
|
else if (GetSwitchInt(*argv, "threads:", &gicThreads))
|
|
{
|
|
; // selected thread count
|
|
}
|
|
else if (GetSwitch(*argv, "model:apt"))
|
|
{
|
|
// run apartment model
|
|
giThreadModel = OPF_INITAPARTMENT;
|
|
}
|
|
else if (GetSwitch(*argv, "model:free"))
|
|
{
|
|
// run freethreaded model
|
|
giThreadModel = OPF_INITFREE;
|
|
}
|
|
else
|
|
{
|
|
// unknown switch, show help
|
|
ERROUT("Unknown command line switch:<%s>\n", *argv);
|
|
fDontRun = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fDontRun)
|
|
{
|
|
// help is wanted
|
|
DisplayHelp();
|
|
return FALSE;
|
|
}
|
|
|
|
// success, run the test
|
|
return TRUE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: DisplayHelp
|
|
//
|
|
// Synopsis: displays a command line help message
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void DisplayHelp(void)
|
|
{
|
|
printf("\nCommand Line Switches for Marshal Stress Test:\n\n");
|
|
|
|
printf("-d - debug mode\n");
|
|
printf("-v - verbose mode\n");
|
|
printf("-h | -? - display this help message\n\n");
|
|
|
|
printf("-model:[apt|free] - threading model to use for test\n");
|
|
printf("-var:# - test variation to execute 1-%x\n", giHighestTestVar);
|
|
printf("-threads:# - number of threads per variation\n");
|
|
printf("-reps:# - number of repetitions of the test\n");
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: GetSwitch
|
|
//
|
|
// Synopsis: returns TRUE if the specified cmd line switch is set.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
BOOL GetSwitch(CHAR *pCmdParam, CHAR *pszSwitch)
|
|
{
|
|
if (*pCmdParam == '-' || *pCmdParam == '/')
|
|
{
|
|
pCmdParam++;
|
|
return (!stricmp(pCmdParam, pszSwitch));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: GetSwitchInt
|
|
//
|
|
// Synopsis: returns TRUE if the specified cmd line switch is set,
|
|
// and sets the value of that switch.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
BOOL GetSwitchInt(CHAR *pCmdParam, CHAR *pszSwitch, int *pInt)
|
|
{
|
|
if (*pCmdParam == '-' || *pCmdParam == '/')
|
|
{
|
|
pCmdParam++;
|
|
int len = strlen(pszSwitch);
|
|
if (!strnicmp(pCmdParam, pszSwitch, len))
|
|
{
|
|
pCmdParam += len;
|
|
*pInt = atoi(pCmdParam);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: CHKRESULT
|
|
//
|
|
// Synopsis: prints a failure message if the result code indicates
|
|
// failure., and success message only in verbose mode.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CHKRESULT(HRESULT hr, CHAR *pszOperation)
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED hr:%x Op:%s\n", hr, pszOperation);
|
|
}
|
|
else if (gfVerbose)
|
|
{
|
|
printf("PASSED hr:%x Op:%s\n", hr, pszOperation);
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: CHKOP
|
|
//
|
|
// Synopsis: prints a failure message if the result code indicates
|
|
// failure, and success message only in debug mode.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CHKOP(HRESULT hr, CHAR *pszOperation)
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED hr:%x Op:%s\n", hr, pszOperation);
|
|
}
|
|
else if (gfDebug)
|
|
{
|
|
printf("PASSED hr:%x Op:%s\n", hr, pszOperation);
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: CHKTESTRESULT
|
|
//
|
|
// Synopsis: prints a pass or fail message
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CHKTESTRESULT(BOOL fRes, CHAR *pszMsg)
|
|
{
|
|
if (fRes)
|
|
printf("%s PASSED\n", pszMsg);
|
|
else
|
|
printf("%s FAILED\n", pszMsg);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: GetEvent / ReleaseEvent
|
|
//
|
|
// Synopsis: allocates or releases an event
|
|
//
|
|
// CODEWORK: cache these for frequent use
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HANDLE GetEvent()
|
|
{
|
|
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (hEvent == NULL)
|
|
{
|
|
ERROUT("GetEvent FAILED\n");
|
|
}
|
|
DBGOUT("CreateEvent hEvent:%x\n", hEvent);
|
|
return hEvent;
|
|
}
|
|
|
|
void ReleaseEvent(HANDLE hEvent)
|
|
{
|
|
if (hEvent)
|
|
{
|
|
DBGOUT("ReleaseEvent hEvent:%x\n", hEvent);
|
|
CloseHandle(hEvent);
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: WaitForEvent
|
|
//
|
|
// Synopsis: waits on the given event (if there is one) for a
|
|
// certain amount of time, returns FALSE if timedout.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
BOOL WaitForEvent(HANDLE hEvent)
|
|
{
|
|
if (hEvent)
|
|
{
|
|
// CODEWORK: base off the Threading Model
|
|
|
|
return (TRUE) ? AptWaitForEvent(hEvent) :
|
|
FreeWaitForEvent(hEvent);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: FreeWaitForEvent
|
|
//
|
|
// Synopsis: FreeThreaded version of WaitForEvent. Waits on the
|
|
// given event.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
BOOL FreeWaitForEvent(HANDLE hEvent)
|
|
{
|
|
DBGOUT("FreeWaitForEvent hEvent:%x\n", hEvent);
|
|
if (WaitForSingleObject(hEvent, 30000) == WAIT_TIMEOUT)
|
|
{
|
|
ERROUT("WaitForSingleObject TimedOut");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: AptWaitForEvent
|
|
//
|
|
// Synopsis: Apartment model version of WaitForEvent. Waits on the
|
|
// given event. Dispatches all incoming windows messages
|
|
// while waiting.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
BOOL AptWaitForEvent(HANDLE hEvent)
|
|
{
|
|
DBGOUT("AptWaitForEvent hEvent:%x\n", hEvent);
|
|
|
|
while (1)
|
|
{
|
|
HANDLE arEvent[] = {hEvent};
|
|
DWORD dwWakeReason = MsgWaitForMultipleObjects(1, arEvent, FALSE,
|
|
1000, QS_ALLINPUT);
|
|
|
|
if (dwWakeReason == WAIT_OBJECT_0)
|
|
{
|
|
// event was signalled. exit.
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// check for and dispatch any messages that have arrived
|
|
MSG msg;
|
|
while (PeekMessage(&msg, 0, WM_NULL, WM_NULL, PM_REMOVE))
|
|
{
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: SignalEvent
|
|
//
|
|
// Synopsis: signals an event (if there is one)
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void SignalEvent(HANDLE hEvent)
|
|
{
|
|
if (hEvent)
|
|
{
|
|
DBGOUT("SignalEvent hEvent:%x\n", hEvent);
|
|
SetEvent(hEvent);
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: GetStream / ReleaseStream
|
|
//
|
|
// Synopsis: allocates or releases a Stream
|
|
//
|
|
// CODEWORK: cache these for frequent use
|
|
// CODEWORK: use CStreamOnFile for cross process/machine marshaling.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
IStream * GetStream(void)
|
|
{
|
|
IStream *pStm = CreateMemStm(600, NULL);
|
|
if (pStm == NULL)
|
|
{
|
|
ERROUT("ERROR: GetStream FAILED\n");
|
|
}
|
|
DBGOUT("GetStream pStm:%x\n", pStm);
|
|
return pStm;
|
|
}
|
|
|
|
void ReleaseStream(IStream *pStm)
|
|
{
|
|
if (pStm)
|
|
{
|
|
DBGOUT("ReleaseStream pStm:%x\n", pStm);
|
|
pStm->Release();
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: ResetStream
|
|
//
|
|
// Synopsis: resets a steam back to the start
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT ResetStream(IStream *pStm)
|
|
{
|
|
DBGOUT("ResetStream pStm:%x\n", pStm);
|
|
|
|
LARGE_INTEGER libMove;
|
|
libMove.LowPart = 0;
|
|
libMove.HighPart = 0;
|
|
|
|
HRESULT hr = pStm->Seek(libMove, STREAM_SEEK_SET, 0);
|
|
if (FAILED(hr))
|
|
{
|
|
ERROUT("ERROR: ResetStream FAILED hr:%x\n",hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: GetInterface / ReleaseInterface
|
|
//
|
|
// Synopsis: allocates or releases an object interface
|
|
//
|
|
//--------------------------------------------------------------------
|
|
IUnknown *GetInterface(void)
|
|
{
|
|
IUnknown *punk = (IUnknown *) new CTestUnk();
|
|
if (punk == NULL)
|
|
{
|
|
ERROUT("ERROR: GetInterface FAILED\n");
|
|
}
|
|
DBGOUT("GetInterface punk:%x\n", punk);
|
|
return punk;
|
|
}
|
|
|
|
void ReleaseInterface(IUnknown *punk)
|
|
{
|
|
if (punk)
|
|
{
|
|
DBGOUT("ReleaseInterface punk:%x\n", punk);
|
|
punk->Release();
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: GenericExecute
|
|
//
|
|
// Synopsis: run all the parameter blocks on different threads
|
|
// simultaneously.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
BOOL GenericExecute(ULONG cEPs, EXECPARAMS *pEP[])
|
|
{
|
|
BOOL fRes = TRUE;
|
|
DBGOUT("Start GenericExecute cEPs:%x\n", cEPs);
|
|
|
|
HANDLE hThread[50];
|
|
|
|
// launch a thread to run each command block
|
|
for (ULONG i=0; i<cEPs; i++)
|
|
{
|
|
// launch a thread to execute the parameter block
|
|
DWORD dwThreadId;
|
|
hThread[i] = CreateThread(NULL, 0,
|
|
WorkerThread,
|
|
pEP[i],
|
|
0,
|
|
&dwThreadId);
|
|
}
|
|
|
|
// signal all the threads to start their work
|
|
for (i=0; i<cEPs; i++)
|
|
{
|
|
SignalEvent(pEP[i]->hEventThreadStart);
|
|
}
|
|
|
|
// wait for all the threads to complete their work
|
|
for (i=0; i<cEPs; i++)
|
|
{
|
|
if (pEP[i]->hEventThreadDone)
|
|
{
|
|
WaitForSingleObject(pEP[i]->hEventThreadDone, 60000);
|
|
}
|
|
}
|
|
|
|
// signal all the threads to exit
|
|
for (i=0; i<cEPs; i++)
|
|
{
|
|
HANDLE hEventThreadExit = pEP[i]->hEventThreadExit;
|
|
pEP[i]->hEventThreadExit = NULL;// set to NULL so only the thread will
|
|
// release it, genericcleanup wont.
|
|
SignalEvent(hEventThreadExit);
|
|
}
|
|
|
|
// wait for all the threads to exit
|
|
for (i=0; i<cEPs; i++)
|
|
{
|
|
WaitForSingleObject(hThread[i], 5000);
|
|
CloseHandle(hThread[i]);
|
|
}
|
|
|
|
DBGOUT("Done GenericExecute fRes:%x\n", fRes);
|
|
return fRes;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: GenericCleanup
|
|
//
|
|
// Synopsis: clean all the parameter blocks
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void GenericCleanup(ULONG cEPs, EXECPARAMS *pEP[])
|
|
{
|
|
DBGOUT("GenericCleanup\n");
|
|
|
|
// delete the execution parameter blocks
|
|
for (ULONG i=0; i<cEPs; i++)
|
|
{
|
|
ReleaseExecParam(pEP[i]);
|
|
// CODEWORK: get results from the parameter block?
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: WorkerThread
|
|
//
|
|
// Synopsis: entry point for thread that executes a series of
|
|
// interface commands
|
|
//
|
|
//--------------------------------------------------------------------
|
|
DWORD _stdcall WorkerThread(void *params)
|
|
{
|
|
DBGOUT("StartWorkerThread TID:%x pEP:%x\n", GetCurrentThreadId(), params);
|
|
|
|
EXECPARAMS *pEP = (EXECPARAMS *)params;
|
|
if (pEP == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// Initialize OLE for this thread.
|
|
if (pEP->dwFlags & OPF_INITAPARTMENT)
|
|
{
|
|
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
}
|
|
else
|
|
{
|
|
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ERROUT("ERROR: CoInitializeEx FAILED\n");
|
|
return hr;
|
|
}
|
|
|
|
// wait for signal to start the test
|
|
if (!WaitForEvent(pEP->hEventThreadStart))
|
|
{
|
|
return E_OUTOFMEMORY; // BUGBUG
|
|
}
|
|
|
|
// loop for the number of reps requested
|
|
for (ULONG iRep = 0; iRep < pEP->cReps; iRep++)
|
|
{
|
|
// wait for the start signal
|
|
if (!WaitForEvent(pEP->hEventRepStart))
|
|
{
|
|
return E_OUTOFMEMORY; // BUGBUG
|
|
}
|
|
|
|
MSGOUT(" TID:%x Rep:%x of %x\n",
|
|
GetCurrentThreadId(), iRep, pEP->cReps);
|
|
|
|
// loop for the number of INTERFACEPARAMSs, performing
|
|
// the requested operation(s) on each interface.
|
|
|
|
for (ULONG iIP=0; iIP < pEP->cIPs; iIP++)
|
|
{
|
|
hr = DoIfOperation(pEP->dwFlags, &(pEP->aIP[iIP]));
|
|
}
|
|
|
|
// signal the completion event
|
|
SignalEvent(pEP->hEventRepDone);
|
|
}
|
|
|
|
// signal the thread completion event. Cant touch pEP after this
|
|
// point in time since the main thread may delete it. We extract
|
|
// the ThreadExit event and NULL it in the parameter block so that
|
|
// the main thread wont release it. We release it after the event
|
|
// has been signaled.
|
|
|
|
HANDLE hEventThreadExit = pEP->hEventThreadExit;
|
|
SignalEvent(pEP->hEventThreadDone);
|
|
|
|
// wait on the thread exit event. This allows other threads to
|
|
// complete their work (eg unmarshaling/Releasing interfaces on
|
|
// object in this thread.
|
|
|
|
WaitForEvent(hEventThreadExit);
|
|
ReleaseEvent(hEventThreadExit);
|
|
|
|
// uninitialize OLE for this thread
|
|
CoUninitialize();
|
|
|
|
DBGOUT("ExitWorkerThread TID:%x hr:%x\n", GetCurrentThreadId(), hr);
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: DoIfOperation
|
|
//
|
|
// Synopsis: executes one interface operation
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT DoIfOperation(DWORD dwFlags, INTERFACEPARAMS *pIP)
|
|
{
|
|
// find the interface pointers and IID in the params
|
|
IUnknown *punk = pIP->punk;
|
|
IStream *pStm = pIP->pStm;
|
|
REFIID riid = pIP->iid;
|
|
HRESULT hr = S_OK;
|
|
|
|
DBGOUT("DoIfOperation Oper:%x pUnk:%x pStm:%x\n", dwFlags, punk, pStm);
|
|
|
|
// wait for the start signal
|
|
if (!WaitForEvent(pIP->hEventStart))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
// do the requested operation(s) on the interface
|
|
if (dwFlags & OPF_MARSHAL)
|
|
{
|
|
// marshal the interface into the stream
|
|
ResetStream(pStm);
|
|
hr = CoMarshalInterface(pStm, riid, punk, 0, NULL, MSHLFLAGS_NORMAL);
|
|
CHKOP(hr, "CoMarshalInterface");
|
|
}
|
|
|
|
if (dwFlags & OPF_DISCONNECT)
|
|
{
|
|
hr = CoDisconnectObject(punk, 0);
|
|
CHKOP(hr, "CoDisconnectObject");
|
|
}
|
|
|
|
if (dwFlags & OPF_RELEASEMARSHALDATA)
|
|
{
|
|
// call RMD on the stream
|
|
ResetStream(pStm);
|
|
hr = CoReleaseMarshalData(pStm);
|
|
CHKOP(hr, "CoReleaseMarshalData");
|
|
}
|
|
|
|
if (dwFlags & OPF_UNMARSHAL)
|
|
{
|
|
// unmarshal the interface from the stream
|
|
ResetStream(pStm);
|
|
hr = CoUnmarshalInterface(pStm, riid, (void **)&punk);
|
|
CHKOP(hr, "CoUnmarshalInterface");
|
|
}
|
|
|
|
if (dwFlags & OPF_RELEASE)
|
|
{
|
|
// release the interface pointer (if there is one).
|
|
if (punk != NULL)
|
|
{
|
|
ULONG cRefs = punk->Release();
|
|
}
|
|
}
|
|
|
|
SignalEvent(pIP->hEventDone);
|
|
|
|
DBGOUT("DoIfOperation Oper:%x hr:%x\n", dwFlags, hr);
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: CreateExecParam
|
|
//
|
|
// Synopsis: allocates an exec parameter packet for the given # of
|
|
// INTERFACEPARAMSs.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
EXECPARAMS *CreateExecParam(ULONG cIP)
|
|
{
|
|
// allocate memory
|
|
ULONG ulSize = sizeof(EXECPARAMS) + (cIP * sizeof(INTERFACEPARAMS));
|
|
|
|
EXECPARAMS *pEP = (EXECPARAMS *) new BYTE[ulSize];
|
|
if (pEP == NULL)
|
|
{
|
|
DBGOUT("CreateExecParams OOM\n");
|
|
return NULL;
|
|
}
|
|
|
|
// zero fill the packet
|
|
memset((BYTE*)pEP, 0, ulSize);
|
|
pEP->cIPs = cIP;
|
|
|
|
DBGOUT("CreateExecParam pEP:%x\n", pEP);
|
|
return pEP;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: FillExecParam
|
|
//
|
|
// Synopsis: fills an exec parameter packet
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void FillExecParam(EXECPARAMS *pEP, DWORD dwFlags, ULONG cReps,
|
|
HANDLE hEventRepStart, HANDLE hEventRepDone,
|
|
HANDLE hEventThreadStart, HANDLE hEventThreadDone)
|
|
{
|
|
DBGOUT("FillExecParam pEP:%x\n", pEP);
|
|
|
|
pEP->dwFlags = dwFlags;
|
|
pEP->hEventThreadStart = hEventThreadStart;
|
|
pEP->hEventThreadDone = hEventThreadDone;
|
|
pEP->hEventThreadExit = GetEvent();
|
|
|
|
pEP->cReps = cReps;
|
|
pEP->hEventRepStart = hEventRepStart;
|
|
pEP->hEventRepDone = hEventRepDone;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: ReleaseExecParam
|
|
//
|
|
// Synopsis: releases an exec parameter packet
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void ReleaseExecParam(EXECPARAMS *pEP)
|
|
{
|
|
DBGOUT("ReleaseExecParam pEP:%x\n", pEP);
|
|
|
|
if (!pEP)
|
|
return;
|
|
|
|
// release the events.
|
|
ReleaseEvent(pEP->hEventThreadStart);
|
|
ReleaseEvent(pEP->hEventThreadDone);
|
|
ReleaseEvent(pEP->hEventThreadExit);
|
|
ReleaseEvent(pEP->hEventRepStart);
|
|
ReleaseEvent(pEP->hEventRepDone);
|
|
|
|
// release the interface parameter blocks
|
|
for (ULONG i=0; i<pEP->cIPs; i++)
|
|
{
|
|
ReleaseInterfaceParam(&(pEP->aIP[i]));
|
|
}
|
|
|
|
// free the memory
|
|
delete pEP;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: FillInterfaceParam
|
|
//
|
|
// Synopsis: fills default info into the interface parms
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void FillInterfaceParam(INTERFACEPARAMS *pIP, REFIID riid, IUnknown *punk,
|
|
IStream *pStm, HANDLE hEventStart, HANDLE hEventDone)
|
|
{
|
|
DBGOUT("FillInterfaceParam pIP:%x\n", pIP);
|
|
|
|
pIP->iid = riid;
|
|
pIP->punk = punk;
|
|
pIP->pStm = pStm;
|
|
pIP->hEventStart = hEventStart;
|
|
pIP->hEventDone = hEventDone;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: ReleaseInterfaceParam
|
|
//
|
|
// Synopsis: releases an interface parameter packet
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void ReleaseInterfaceParam(INTERFACEPARAMS *pIP)
|
|
{
|
|
DBGOUT("ReleaseInterfaceParam pIP:%x\n", pIP);
|
|
|
|
if (!pIP)
|
|
return;
|
|
|
|
// release the interfaces
|
|
ReleaseInterface(pIP->punk);
|
|
ReleaseInterface(pIP->pStm);
|
|
|
|
// release the events
|
|
ReleaseEvent(pIP->hEventStart);
|
|
ReleaseEvent(pIP->hEventDone);
|
|
}
|