windows-nt/Source/XPSP1/NT/admin/activec/designer/vb98ctls/mmcproxy/proxy.c
2020-09-26 16:20:57 +08:00

3729 lines
104 KiB
C

//=--------------------------------------------------------------------------=
// proxy.cpp
//=--------------------------------------------------------------------------=
// Copyright (c) 1999, Microsoft Corp.
// All Rights Reserved
// Information Contained Herein Is Proprietary and Confidential.
//=--------------------------------------------------------------------------=
//
// MMC Interfcace Proxy and Stub Functions
//
//=--------------------------------------------------------------------------=
// This file contains proxy and stub functions for MMC methods that are not
// remotable using a MIDL generated proxy and stub. Non-remotable methods have
// parameters that are ambiguous i.e. can be casted to different data types.
// For example, IComponentData::Notify() is passed an event and two additional
// LPARAM arguments that are interpreted according to the event. Sometimes an
// LPARAM contains a simple value such as a long or two BOOLs and sometimes it
// contains an IDataObject *. MIDL doesn't know the difference between
// MMCN_SELECT and MMCN_PRINT so we need to write some code to help out.
//
// The version of MMC.IDL in the designer directory has added a [local]
// attribute to all non-remotable methods. In addition, an extra method has
// been added to the same interface that is a remotable version of the method.
// The remotable version has more parameters and represents the union of all
// possible interpretations of the ambiguous parameter. For example,
// IExtendControlbar::ControlbarNotify() is defined as:
//
// [helpstring("User actions"), local]
// HRESULT ControlbarNotify([in] MMC_NOTIFY_TYPE event,
// [in] LPARAM arg, [in] LPARAM param);
//
// This method can receive MMCN_SELECT, MMCN_BTN_CLICK, and MMCN_MENU_BTNCLICK.
// The union of all possible parameter types is used in the following method
// added to that interface:
//
//
// HRESULT RemControlbarNotify([in] MMC_NOTIFY_TYPE event,
// [in] LPARAM lparam,
// [in] IDataObject *piDataObject,
// [in] MENUBUTTONDATA *MenuButtonData);
//
// Note, that normal, in-proc, non-remoted versions of IExtendControlbar do not
// have this extra method in their vtable because no one is going to call it.
// It is only used in the MILD generated proxy object.
//
// In order to tell MIDL which method remotes ControlbarNotify() an attribute
// control file (ACF) is used. The entry in the ACF for IExtendControlbar is:
//
// interface IExtendControlbar
// {
// [call_as (ControlbarNotify)]
// RemControlbarNotify();
//
// }
//
// This says that RemControlbarNotify should be called when remoting
// ControlbarNotify(). MIDL generates the proxy/stub code as usual but it only
// generates the prototypes for ControlbarNotify proxy and stub. We have to
// write these routines.
//
// When a remote client has an IExtendControlbarNotify pointer it actually
// points into the proxy vtable. MIDL sets the ControlbarNotify entry pointing to
// our IExtendControlbar_ControlbarNotify_Proxy() function below. That function
// interprets the parameters and then calls the MIDL generated
// IExtendControlbar_RemControlbarNotify_Proxy() that packs up the parameters
// and sends them off to the server. If a parameters is not applicable, (e.g.
// MMCN_SELECT does not receive a pointer to a MENUBUTTONDATA stuct), then a
// pointer to an empty struct or zeroes are sent.
//
// When the packet reaches the server side the MIDL generated
// IExtendControlbar_RemControlbarNotify_Stub() unpacks them and then calls our
// IExtendControlbar_ControlbarNotify_Stub() passing it the parameters and the
// IExtendControlbar pointer into the server. This function interprets the
// parameters and then calls ControlbarNotify in the server.
//
//=--------------------------------------------------------------------------=
#include "mmc.h"
extern HRESULT GetClipboardFormat
(
WCHAR *pwszFormatName,
CLIPFORMAT *pcfFormat
);
extern HRESULT CreateMultiSelDataObject
(
IDataObject **ppiDataObjects,
long cDataObjects,
IDataObject **ppiMultiSelDataObject
);
static HRESULT MenuButtonClickProxy
(
IExtendControlbar __RPC_FAR *This,
IDataObject *piDataObject,
MENUBUTTONDATA *pMenuButtonData
);
static HRESULT IsMultiSelect(IDataObject *piDataObject, BOOL *pfMultiSelect)
{
HRESULT hr = S_OK;
DWORD *pdwMultiSelect = NULL;
BOOL fGotData = FALSE;
FORMATETC FmtEtc;
STGMEDIUM StgMed;
ZeroMemory(&FmtEtc, sizeof(FmtEtc));
ZeroMemory(&StgMed, sizeof(StgMed));
*pfMultiSelect = FALSE;
if (NULL == piDataObject)
{
goto Cleanup;
}
if (IS_SPECIAL_DATAOBJECT(piDataObject))
{
goto Cleanup;
}
hr = GetClipboardFormat(CCF_MMC_MULTISELECT_DATAOBJECT, &FmtEtc.cfFormat);
if (FAILED(hr))
{
goto Cleanup;
}
FmtEtc.dwAspect = DVASPECT_CONTENT;
FmtEtc.lindex = -1L;
FmtEtc.tymed = TYMED_HGLOBAL;
StgMed.tymed = TYMED_HGLOBAL;
hr = piDataObject->lpVtbl->GetData(piDataObject, &FmtEtc, &StgMed);
if (SUCCEEDED(hr))
{
fGotData = TRUE;
}
else
{
hr = S_OK;
}
// Ignore any failures and assume that it is not multi-select. Snap-ins
// should return DV_E_FORMATETC or DV_E_CLIPFORMAT but in practice that
// is not the case. For example, the IIS snap-in returns E_NOTIMPL.
// It would be impossible to cover the range of reasonable return codes so
// we treat any error as format not supported.
if (fGotData)
{
pdwMultiSelect = (DWORD *)GlobalLock(StgMed.hGlobal);
if ((DWORD)1 == *pdwMultiSelect)
{
*pfMultiSelect = TRUE;
}
}
Cleanup:
if (NULL != pdwMultiSelect)
{
(void)GlobalUnlock(StgMed.hGlobal);
}
if (fGotData)
{
ReleaseStgMedium(&StgMed);
}
return hr;
}
static HRESULT InterpretMultiSelect
(
IDataObject *piDataObject,
long *pcDataObjects,
IDataObject ***pppiDataObjects
)
{
HRESULT hr = S_OK;
SMMCDataObjects *pMMCDataObjects = NULL;
BOOL fGotData = FALSE;
size_t cbObjectTypes = 0;
long i = 0;
FORMATETC FmtEtc;
STGMEDIUM StgMed;
ZeroMemory(&FmtEtc, sizeof(FmtEtc));
ZeroMemory(&StgMed, sizeof(StgMed));
*pcDataObjects = 0;
*pppiDataObjects = NULL;
// Get the SMMCDataObjects structure from MMC
hr = GetClipboardFormat(CCF_MULTI_SELECT_SNAPINS, &FmtEtc.cfFormat);
if (FAILED(hr))
{
goto Cleanup;
}
FmtEtc.dwAspect = DVASPECT_CONTENT;
FmtEtc.lindex = -1L;
FmtEtc.tymed = TYMED_HGLOBAL;
StgMed.tymed = TYMED_HGLOBAL;
hr = piDataObject->lpVtbl->GetData(piDataObject, &FmtEtc, &StgMed);
if (FAILED(hr))
{
goto Cleanup;
}
fGotData = TRUE;
pMMCDataObjects = (SMMCDataObjects *)GlobalLock(StgMed.hGlobal);
if (NULL == pMMCDataObjects)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
// Allocate an array of IDataObject and copy the IDataObjects to it
*pcDataObjects = pMMCDataObjects->count;
*pppiDataObjects = (IDataObject **)GlobalAlloc(GPTR,
pMMCDataObjects->count * sizeof(IDataObject *));
if (NULL == *pppiDataObjects)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
for (i = 0; i < *pcDataObjects; i++)
{
(*pppiDataObjects)[i] = pMMCDataObjects->lpDataObject[i];
}
Cleanup:
if (NULL != pMMCDataObjects)
{
(void)GlobalUnlock(StgMed.hGlobal);
}
if (fGotData)
{
ReleaseStgMedium(&StgMed);
}
return hr;
}
void CheckForSpecialDataObjects
(
IDataObject **ppiDataObject,
BOOL *pfSpecialDataObject,
long *plSpecialDataObject
)
{
long lSpecialDataObject = (long)(*ppiDataObject);
if (IS_SPECIAL_DATAOBJECT(lSpecialDataObject))
{
*plSpecialDataObject = lSpecialDataObject;
*ppiDataObject = NULL;
*pfSpecialDataObject = TRUE;
}
else
{
*pfSpecialDataObject = FALSE;
}
}
static HRESULT SetRemote(IUnknown *This)
{
HRESULT hr = S_OK;
IMMCRemote *piMMCRemote = NULL;
DWORD cbFileName = 0;
char szModuleFileName[MAX_PATH] = "";
// Call IMMCRemote methods: ObjectIsRemote and SetMMCExePath so that the
// snap-in will know it is remote and so that it will have MMC.EXE's full
// path in order to build taskpad display strings.
hr = This->lpVtbl->QueryInterface(This, &IID_IMMCRemote,
(void **)&piMMCRemote);
if (FAILED(hr))
{
// If the object doesn't support IMMCRemote that is not an error.
// The designer runtime will get this QI on both its main object and
// its IComponent object but only the main object needs to support the
// interface.
hr = S_OK;
goto Cleanup;
}
hr = piMMCRemote->lpVtbl->ObjectIsRemote(piMMCRemote);
if (FAILED(hr))
{
goto Cleanup;
}
cbFileName = GetModuleFileName(NULL, // get executable that loaded us (MMC)
szModuleFileName,
sizeof(szModuleFileName));
if (0 == cbFileName)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
hr = piMMCRemote->lpVtbl->SetMMCExePath(piMMCRemote, szModuleFileName);
if (FAILED(hr))
{
goto Cleanup;
}
hr = piMMCRemote->lpVtbl->SetMMCCommandLine(piMMCRemote, GetCommandLine());
if (FAILED(hr))
{
goto Cleanup;
}
Cleanup:
if (NULL != piMMCRemote)
{
piMMCRemote->lpVtbl->Release(piMMCRemote);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendControlbar_SetControlbar_Proxy
(
IExtendControlbar __RPC_FAR *This,
LPCONTROLBAR pControlbar
)
{
HRESULT hr = S_OK;
// Make sure the snap-in knows we are remoted. We do this here because
// this is the first opportunity for the proxy to inform a toolbar
// extension that it is remote.
hr = SetRemote((IUnknown *)This);
if (FAILED(hr))
{
goto Cleanup;
}
hr = IExtendControlbar_RemSetControlbar_Proxy(This, pControlbar);
Cleanup:
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendControlbar_SetControlbar_Stub
(
IExtendControlbar __RPC_FAR *This,
LPCONTROLBAR pControlbar
)
{
return This->lpVtbl->SetControlbar(This, pControlbar);
}
HRESULT STDMETHODCALLTYPE IExtendControlbar_ControlbarNotify_Proxy
(
IExtendControlbar __RPC_FAR *This,
MMC_NOTIFY_TYPE event,
LPARAM arg,
LPARAM param
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject **ppiDataObjects = NULL;
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
// If this is not a menu button click then we can use the generated remoting
// code with the arg and param unions
if (MMCN_MENU_BTNCLICK == event)
{
hr = MenuButtonClickProxy(This,
(IDataObject *)arg,
(MENUBUTTONDATA *)param);
goto Cleanup;
}
// Get any IDataObject associated with the event
switch (event)
{
case MMCN_SELECT:
piDataObject = (IDataObject *)param;
break;
case MMCN_BTN_CLICK:
piDataObject = (IDataObject *)arg;
break;
default:
piDataObject = NULL;
break;
}
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObject)
{
hr = IsMultiSelect(piDataObject, &fIsMultiSelect);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelect)
{
hr = InterpretMultiSelect(piDataObject, &cDataObjects,
&ppiDataObjects);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjects = &piDataObject;
}
hr = IExtendControlbar_RemControlbarNotify_Proxy(This,
cDataObjects,
ppiDataObjects,
fSpecialDataObject,
lSpecialDataObject,
event, arg, param);
Cleanup:
if ( fIsMultiSelect && (NULL != ppiDataObjects) )
{
(void)GlobalFree(ppiDataObjects);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendControlbar_ControlbarNotify_Stub
(
IExtendControlbar __RPC_FAR *This,
long cDataObjects,
IDataObject **ppiDataObjects,
BOOL fSpecialDataObject,
long lSpecialDataObject,
MMC_NOTIFY_TYPE event,
LPARAM arg,
LPARAM param
)
{
HRESULT hr = S_OK;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObject = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjects > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjects, cDataObjects,
&piMultiSelDataObject);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObject = piMultiSelDataObject;
}
else if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
else
{
piDataObject = ppiDataObjects[0];
}
// Put the IDataObject into the corresponding parameter for the event
switch (event)
{
case MMCN_SELECT:
param = (LPARAM)piDataObject;
break;
case MMCN_BTN_CLICK:
arg = (LPARAM)piDataObject;
break;
default:
break;
}
// Call into the snap-in with all parameters appearing as they would
// when in-proc.
hr = This->lpVtbl->ControlbarNotify(This, event, arg, param);
Cleanup:
if (NULL != piMultiSelDataObject)
{
piMultiSelDataObject->lpVtbl->Release(piMultiSelDataObject);
}
return hr;
}
static HRESULT MenuButtonClickProxy
(
IExtendControlbar __RPC_FAR *This,
IDataObject *piDataObject,
MENUBUTTONDATA *pMenuButtonData
)
{
HRESULT hr = S_OK;
POPUP_MENUDEF *pPopupMenuDef = NULL;
HMENU hMenu = NULL;
UINT uiSelectedItemID = 0;
IExtendControlbarRemote *piECRemote = NULL;
long i = 0;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject **ppiDataObjects = NULL;
// The generated remoting cannot easily handle what we need to do so we get
// IExtendControlbarRemote on the snap-in. This interface has methods that
// allow us to ask the snap-in for its popup menu items, display the menu
// here on the MMC side, and then tell the snap-in which item was selected.
hr = This->lpVtbl->QueryInterface(This, &IID_IExtendControlbarRemote,
(void **)&piECRemote);
if (FAILED(hr))
{
goto Cleanup;
}
// Tell the snap-in about the menu button click and get back its list of
// popup menu items.
hr = piECRemote->lpVtbl->MenuButtonClick(piECRemote,
piDataObject,
pMenuButtonData->idCommand,
&pPopupMenuDef);
if ( FAILED(hr) || (NULL == pPopupMenuDef) )
{
goto Cleanup;
}
// Create an empty Win32 menu
hMenu = CreatePopupMenu();
if (NULL == hMenu)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
// Iterate through each of the items and add them to the menu
for (i = 0; i < pPopupMenuDef->cMenuItems; i++)
{
if (!AppendMenu(hMenu,
pPopupMenuDef->MenuItems[i].uiFlags,
pPopupMenuDef->MenuItems[i].uiItemID,
pPopupMenuDef->MenuItems[i].pszItemText))
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
}
// If the owner HWND is NULL then this is an extension and it does not have
// access to IConsole2 on MMC to get the main frame HWND. In this case just
// use the active window on this thread.
if (NULL == pPopupMenuDef->hwndMenuOwner)
{
pPopupMenuDef->hwndMenuOwner = GetActiveWindow();
}
// Display the popup menu and wait for a selection.
uiSelectedItemID = (UINT)TrackPopupMenu(
hMenu, // menu to display
TPM_LEFTALIGN | // align left side of menu with x
TPM_TOPALIGN | // align top of menu with y
TPM_NONOTIFY | // don't send any messages during selection
TPM_RETURNCMD | // make the ret val the selected item
TPM_LEFTBUTTON, // allow selection with left button only
pMenuButtonData->x, // left side coordinate
pMenuButtonData->y, // top coordinate
0, // reserved,
pPopupMenuDef->hwndMenuOwner, // owner window, this comes from snap-in
// as it can call IConsole2->GetMainWindow
NULL); // not used
// A zero return could indicate either an error or that the user hit
// Escape or clicked off of the menu to cancel the operation. GetLastError()
// determines whether there was an error. Either way we're done but set the
// hr first.
if (0 == uiSelectedItemID)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
// If i is non-zero then it contains the ID of the selected item.
// Tell the snap-in what was selected and pass it the extra IUnknown it
// included in its menu definition (this is snap-in defined and it allows
// the snap-in to include some more identifying information to handle the
// event).
if (0 != uiSelectedItemID)
{
hr = piECRemote->lpVtbl->PopupMenuClick(
piECRemote,
piDataObject,
uiSelectedItemID,
pPopupMenuDef->punkSnapInDefined);
}
Cleanup:
if (NULL != piECRemote)
{
piECRemote->lpVtbl->Release(piECRemote);
}
if (NULL != hMenu)
{
(void)DestroyMenu(hMenu);
}
if (NULL != pPopupMenuDef)
{
for (i = 0; i < pPopupMenuDef->cMenuItems; i++)
{
if (NULL != pPopupMenuDef->MenuItems[i].pszItemText)
{
CoTaskMemFree(pPopupMenuDef->MenuItems[i].pszItemText);
}
}
if (NULL != pPopupMenuDef->punkSnapInDefined)
{
pPopupMenuDef->punkSnapInDefined->lpVtbl->Release(pPopupMenuDef->punkSnapInDefined);
}
CoTaskMemFree(pPopupMenuDef);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendControlbarRemote_MenuButtonClick_Proxy
(
IExtendControlbarRemote __RPC_FAR *This,
IDataObject __RPC_FAR *piDataObject,
int idCommand,
POPUP_MENUDEF __RPC_FAR *__RPC_FAR *ppPopupMenuDef
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject **ppiDataObjects = NULL;
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObject)
{
hr = IsMultiSelect(piDataObject, &fIsMultiSelect);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelect)
{
hr = InterpretMultiSelect(piDataObject, &cDataObjects, &ppiDataObjects);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjects = &piDataObject;
}
hr = IExtendControlbarRemote_RemMenuButtonClick_Proxy(This,
cDataObjects,
ppiDataObjects,
fSpecialDataObject,
lSpecialDataObject,
idCommand,
ppPopupMenuDef);
Cleanup:
if ( fIsMultiSelect && (NULL != ppiDataObjects) )
{
(void)GlobalFree(ppiDataObjects);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendControlbarRemote_MenuButtonClick_Stub
(
IExtendControlbarRemote __RPC_FAR *This,
long cDataObjects,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjects[ ],
BOOL fSpecialDataObject,
long lSpecialDataObject,
int idCommand,
POPUP_MENUDEF __RPC_FAR *__RPC_FAR *ppPopupMenuDef
)
{
HRESULT hr = S_OK;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObject = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjects > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjects, cDataObjects,
&piMultiSelDataObject);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObject = piMultiSelDataObject;
}
else if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
else
{
piDataObject = ppiDataObjects[0];
}
// Call the snap-in
hr = This->lpVtbl->MenuButtonClick(This, piDataObject,
idCommand, ppPopupMenuDef);
Cleanup:
if (NULL != piMultiSelDataObject)
{
piMultiSelDataObject->lpVtbl->Release(piMultiSelDataObject);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendControlbarRemote_PopupMenuClick_Proxy
(
IExtendControlbarRemote __RPC_FAR *This,
IDataObject __RPC_FAR *piDataObject,
UINT uIDItem,
IUnknown __RPC_FAR *punkParam
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject **ppiDataObjects = NULL;
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObject)
{
hr = IsMultiSelect(piDataObject, &fIsMultiSelect);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelect)
{
hr = InterpretMultiSelect(piDataObject, &cDataObjects, &ppiDataObjects);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjects = &piDataObject;
}
hr = IExtendControlbarRemote_RemPopupMenuClick_Proxy(This,
cDataObjects,
ppiDataObjects,
fSpecialDataObject,
lSpecialDataObject,
uIDItem,
punkParam);
Cleanup:
if ( fIsMultiSelect && (NULL != ppiDataObjects) )
{
(void)GlobalFree(ppiDataObjects);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendControlbarRemote_PopupMenuClick_Stub
(
IExtendControlbarRemote __RPC_FAR *This,
long cDataObjects,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjects[ ],
BOOL fSpecialDataObject,
long lSpecialDataObject,
UINT uIDItem,
IUnknown __RPC_FAR *punkParam
)
{
HRESULT hr = S_OK;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObject = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjects > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjects, cDataObjects,
&piMultiSelDataObject);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObject = piMultiSelDataObject;
}
else if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
else
{
piDataObject = ppiDataObjects[0];
}
// Call the snap-in
hr = This->lpVtbl->PopupMenuClick(This, piDataObject, uIDItem, punkParam);
Cleanup:
if (NULL != piMultiSelDataObject)
{
piMultiSelDataObject->lpVtbl->Release(piMultiSelDataObject);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IComponentData_Initialize_Proxy
(
IComponentData *This,
LPUNKNOWN pUnknown
)
{
HRESULT hr = S_OK;
// Tell the object it is remote and give the path to mmc.exe
hr = SetRemote((IUnknown *)This);
if (FAILED(hr))
{
goto Cleanup;
}
// Now pass on the Initiaize call normally. Using this order allows a snap-in
// to know it is remote prior to its IComponentData::Initialize in case it
// needs that information up front.
hr = IComponentData_RemInitialize_Proxy(This, pUnknown);
if (FAILED(hr))
{
goto Cleanup;
}
Cleanup:
return hr;
}
HRESULT STDMETHODCALLTYPE IComponentData_Initialize_Stub
(
IComponentData *This,
LPUNKNOWN pUnknown
)
{
return This->lpVtbl->Initialize(This, pUnknown);
}
HRESULT STDMETHODCALLTYPE IComponentData_CreateComponent_Proxy
(
IComponentData *This,
LPCOMPONENT *ppComponent
)
{
HRESULT hr = S_OK;
// Tell the object it is remote and give the path to mmc.exe
hr = SetRemote((IUnknown *)This);
if (FAILED(hr))
{
goto Cleanup;
}
// Now pass on the CreateComponent call normally. Using this order allows a
// snap-in to know it is remote prior to its
// IComponentData::CreateComponent in case it needs that information up
// front.
// We do this in IComponentData::Initialize and
// IComponentData::CreateComponent. Most cases will use Initialize but in
// MMC 1.1 a taskpad extension does not receive IComponentData::Initialize.
// MMC only calls IComponentData::CreateComponent. As a taskpad extension
// may need to resolve a res:// URL to use the mmc.exe path we need to do
// it here as well.
hr = IComponentData_RemCreateComponent_Proxy(This, ppComponent);
if (FAILED(hr))
{
goto Cleanup;
}
Cleanup:
return hr;
}
HRESULT STDMETHODCALLTYPE IComponentData_CreateComponent_Stub
(
IComponentData *This,
LPCOMPONENT *ppComponent
)
{
return This->lpVtbl->CreateComponent(This, ppComponent);
}
HRESULT STDMETHODCALLTYPE IComponentData_Notify_Proxy
(
IComponentData __RPC_FAR *This,
LPDATAOBJECT piDataObject,
MMC_NOTIFY_TYPE event,
LPARAM arg,
LPARAM param
)
{
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
ICDNotifyParam ParamUnion;
ZeroMemory(&ParamUnion, sizeof(ParamUnion));
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
ParamUnion.value = param;
return IComponentData_RemNotify_Proxy(This, piDataObject,
fSpecialDataObject,
lSpecialDataObject,
event, arg, &ParamUnion);
}
HRESULT STDMETHODCALLTYPE IComponentData_Notify_Stub
(
IComponentData __RPC_FAR *This,
LPDATAOBJECT piDataObject,
BOOL fSpecialDataObject,
long lSpecialDataObject,
MMC_NOTIFY_TYPE event,
LPARAM arg,
ICDNotifyParam *pParamUnion
)
{
if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
return This->lpVtbl->Notify(This, piDataObject,
event, arg, pParamUnion->value);
}
HRESULT STDMETHODCALLTYPE IComponentData_CompareObjects_Proxy
(
IComponentData __RPC_FAR *This,
IDataObject *piDataObjectA,
IDataObject *piDataObjectB
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelectA = FALSE;
long cDataObjectsA = 1L;
IDataObject **ppiDataObjectsA = NULL;
BOOL fSpecialDataObjectA = FALSE;
long lSpecialDataObjectA = 0;
BOOL fIsMultiSelectB = FALSE;
long cDataObjectsB = 1L;
IDataObject **ppiDataObjectsB = NULL;
BOOL fSpecialDataObjectB = FALSE;
long lSpecialDataObjectB = 0;
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObjectA, &fSpecialDataObjectA, &lSpecialDataObjectA);
CheckForSpecialDataObjects(&piDataObjectB, &fSpecialDataObjectB, &lSpecialDataObjectB);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObjectA)
{
hr = IsMultiSelect(piDataObjectA, &fIsMultiSelectA);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (!fSpecialDataObjectB)
{
hr = IsMultiSelect(piDataObjectB, &fIsMultiSelectB);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelectA)
{
hr = InterpretMultiSelect(piDataObjectA, &cDataObjectsA, &ppiDataObjectsA);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjectsA = &piDataObjectA;
}
if (fIsMultiSelectB)
{
hr = InterpretMultiSelect(piDataObjectB, &cDataObjectsB, &ppiDataObjectsB);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjectsB = &piDataObjectB;
}
hr = IComponentData_RemCompareObjects_Proxy(This,
cDataObjectsA,
ppiDataObjectsA,
fSpecialDataObjectA,
lSpecialDataObjectA,
cDataObjectsB,
ppiDataObjectsB,
fSpecialDataObjectB,
lSpecialDataObjectB);
Cleanup:
if ( fIsMultiSelectA && (NULL != ppiDataObjectsA) )
{
(void)GlobalFree(ppiDataObjectsA);
}
if ( fIsMultiSelectB && (NULL != ppiDataObjectsB) )
{
(void)GlobalFree(ppiDataObjectsB);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IComponentData_CompareObjects_Stub
(
IComponentData __RPC_FAR *This,
long cDataObjectsA,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjectsA[ ],
BOOL fSpecialDataObjectA,
long lSpecialDataObjectA,
long cDataObjectsB,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjectsB[ ],
BOOL fSpecialDataObjectB,
long lSpecialDataObjectB
)
{
HRESULT hr = S_OK;
IDataObject *piDataObjectA = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObjectA = NULL;
IDataObject *piDataObjectB = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObjectB = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjectsA > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjectsA, cDataObjectsA,
&piMultiSelDataObjectA);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObjectA = piMultiSelDataObjectA;
}
else if (fSpecialDataObjectA)
{
piDataObjectA = (IDataObject *)lSpecialDataObjectA;
}
else
{
piDataObjectA = ppiDataObjectsA[0];
}
if (cDataObjectsB > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjectsB, cDataObjectsB,
&piMultiSelDataObjectB);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObjectB = piMultiSelDataObjectB;
}
else if (fSpecialDataObjectB)
{
piDataObjectB = (IDataObject *)lSpecialDataObjectB;
}
else
{
piDataObjectB = ppiDataObjectsB[0];
}
// Call the snap-in
hr = This->lpVtbl->CompareObjects(This, piDataObjectA, piDataObjectB);
Cleanup:
if (NULL != piMultiSelDataObjectA)
{
piMultiSelDataObjectA->lpVtbl->Release(piMultiSelDataObjectA);
}
if (NULL != piMultiSelDataObjectB)
{
piMultiSelDataObjectB->lpVtbl->Release(piMultiSelDataObjectB);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IComponent_Notify_Proxy
(
IComponent __RPC_FAR *This,
LPDATAOBJECT piDataObject,
MMC_NOTIFY_TYPE event,
LPARAM arg,
LPARAM param
)
{
ICNotifyArg ArgUnion;
ICNotifyParam ParamUnion;
ICOutParam *pOutParam = NULL;
HRESULT hr = S_OK;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject **ppiDataObjects = NULL;
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
ZeroMemory(&ArgUnion, sizeof(ArgUnion));
ZeroMemory(&ParamUnion, sizeof(ParamUnion));
// Switch any potential multiselect data objects with arg/param so that
// piDataObject always contains the potential multiselect.
switch (event)
{
case MMCN_QUERY_PASTE:
ArgUnion.pidoQueryPasteTarget = piDataObject;
piDataObject = (IDataObject *)arg;
ParamUnion.value = param;
break;
case MMCN_PASTE:
ArgUnion.pidoPasteTarget = piDataObject;
piDataObject = (IDataObject *)arg;
// Pass through param as an LPARAM rather than the IDataObject **
// it really is. This is just to let the stub know whether it is
// a copy or a move. If it is a move the CUTORMOVE IDataObject will
// be in the ICOutParam returned from the stub.
ParamUnion.value = param;
break;
case MMCN_RESTORE_VIEW:
ArgUnion.value = arg;
// Don't pass param because it is a BOOL * that will not be
// marshaled. The BOOL will be received in the ICOutParam returned
// from the stub.
break;
default:
ArgUnion.value = arg;
ParamUnion.value = param;
}
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObject)
{
hr = IsMultiSelect(piDataObject, &fIsMultiSelect);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelect)
{
hr = InterpretMultiSelect(piDataObject, &cDataObjects, &ppiDataObjects);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjects = &piDataObject;
}
hr = IComponent_RemNotify_Proxy(This,
cDataObjects, ppiDataObjects,
fSpecialDataObject, lSpecialDataObject,
event, &ArgUnion, &ParamUnion, &pOutParam);
Cleanup:
if (NULL != pOutParam)
{
if (MMCN_PASTE == event)
{
*((IDataObject **)param) = pOutParam->pidoCutOrMove;
}
else if (MMCN_RESTORE_VIEW == event)
{
*((BOOL *)param) = pOutParam->fRestoreHandled;
}
CoTaskMemFree(pOutParam);
}
if ( fIsMultiSelect && (NULL != ppiDataObjects) )
{
(void)GlobalFree(ppiDataObjects);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IComponent_Notify_Stub
(
IComponent __RPC_FAR *This,
long cDataObjects,
IDataObject **ppiDataObjects,
BOOL fSpecialDataObject,
long lSpecialDataObject,
MMC_NOTIFY_TYPE event,
ICNotifyArg *pArgUnion,
ICNotifyParam *pParamUnion,
ICOutParam **ppOutParam
)
{
HRESULT hr = S_OK;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObject = NULL;
LPARAM Arg = 0;
LPARAM Param = 0;
*ppOutParam = (ICOutParam *)CoTaskMemAlloc(sizeof(ICOutParam));
if (NULL == *ppOutParam)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
ZeroMemory(*ppOutParam, sizeof(ICOutParam));
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjects > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjects, cDataObjects,
&piMultiSelDataObject);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObject = piMultiSelDataObject;
}
else if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
else
{
piDataObject = ppiDataObjects[0];
}
// If the event required swaping Arg and IDataObject then swap it back
// before calling into the object. For MMCN_QUERY_PASTE and
// MMCN_RESTORE_VIEW we need to make Param contain the out pointer.
switch (event)
{
case MMCN_PASTE:
Arg = (LPARAM)piDataObject;
piDataObject = pArgUnion->pidoPasteTarget;
if (0 == pParamUnion->value)
{
// This is a copy, pass zero in Param so snap-in will know that
Param = 0;
}
else
{
// This is a move. Pass the address of the IDataObject in
// the ICOutParam that we will return to the proxy.
Param = (LPARAM)&((*ppOutParam)->pidoCutOrMove);
}
break;
case MMCN_QUERY_PASTE:
Arg = (LPARAM)piDataObject;
piDataObject = pArgUnion->pidoQueryPasteTarget;
Param = pParamUnion->value;
break;
case MMCN_RESTORE_VIEW:
Arg = pArgUnion->value;
Param = (LPARAM)&((*ppOutParam)->fRestoreHandled);
break;
default:
Arg = pArgUnion->value;
Param = pParamUnion->value;
break;
}
hr = This->lpVtbl->Notify(This, piDataObject, event, Arg, Param);
Cleanup:
if (FAILED(hr))
{
if (NULL != *ppOutParam)
{
CoTaskMemFree(*ppOutParam);
*ppOutParam = NULL;
}
}
if (NULL != piMultiSelDataObject)
{
piMultiSelDataObject->lpVtbl->Release(piMultiSelDataObject);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IComponent_CompareObjects_Proxy
(
IComponent __RPC_FAR *This,
IDataObject *piDataObjectA,
IDataObject *piDataObjectB
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelectA = FALSE;
long cDataObjectsA = 1L;
IDataObject **ppiDataObjectsA = NULL;
BOOL fSpecialDataObjectA = FALSE;
long lSpecialDataObjectA = 0;
BOOL fIsMultiSelectB = FALSE;
long cDataObjectsB = 1L;
IDataObject **ppiDataObjectsB = NULL;
BOOL fSpecialDataObjectB = FALSE;
long lSpecialDataObjectB = 0;
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObjectA, &fSpecialDataObjectA, &lSpecialDataObjectA);
CheckForSpecialDataObjects(&piDataObjectB, &fSpecialDataObjectB, &lSpecialDataObjectB);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObjectA)
{
hr = IsMultiSelect(piDataObjectA, &fIsMultiSelectA);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (!fSpecialDataObjectB)
{
hr = IsMultiSelect(piDataObjectB, &fIsMultiSelectB);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelectA)
{
hr = InterpretMultiSelect(piDataObjectA, &cDataObjectsA, &ppiDataObjectsA);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjectsA = &piDataObjectA;
}
if (fIsMultiSelectB)
{
hr = InterpretMultiSelect(piDataObjectB, &cDataObjectsB, &ppiDataObjectsB);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjectsB = &piDataObjectB;
}
hr = IComponent_RemCompareObjects_Proxy(This,
cDataObjectsA,
ppiDataObjectsA,
fSpecialDataObjectA,
lSpecialDataObjectA,
cDataObjectsB,
ppiDataObjectsB,
fSpecialDataObjectB,
lSpecialDataObjectB);
Cleanup:
if ( fIsMultiSelectA && (NULL != ppiDataObjectsA) )
{
(void)GlobalFree(ppiDataObjectsA);
}
if ( fIsMultiSelectB && (NULL != ppiDataObjectsB) )
{
(void)GlobalFree(ppiDataObjectsB);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IComponent_CompareObjects_Stub
(
IComponent __RPC_FAR *This,
long cDataObjectsA,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjectsA[ ],
BOOL fSpecialDataObjectA,
long lSpecialDataObjectA,
long cDataObjectsB,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjectsB[ ],
BOOL fSpecialDataObjectB,
long lSpecialDataObjectB
)
{
HRESULT hr = S_OK;
IDataObject *piDataObjectA = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObjectA = NULL;
IDataObject *piDataObjectB = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObjectB = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjectsA > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjectsA, cDataObjectsA,
&piMultiSelDataObjectA);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObjectA = piMultiSelDataObjectA;
}
else if (fSpecialDataObjectA)
{
piDataObjectA = (IDataObject *)lSpecialDataObjectA;
}
else
{
piDataObjectA = ppiDataObjectsA[0];
}
if (cDataObjectsB > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjectsB, cDataObjectsB,
&piMultiSelDataObjectB);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObjectB = piMultiSelDataObjectB;
}
else if (fSpecialDataObjectB)
{
piDataObjectB = (IDataObject *)lSpecialDataObjectB;
}
else
{
piDataObjectB = ppiDataObjectsB[0];
}
// Call the snap-in
hr = This->lpVtbl->CompareObjects(This, piDataObjectA, piDataObjectB);
Cleanup:
if (NULL != piMultiSelDataObjectA)
{
piMultiSelDataObjectA->lpVtbl->Release(piMultiSelDataObjectA);
}
if (NULL != piMultiSelDataObjectB)
{
piMultiSelDataObjectB->lpVtbl->Release(piMultiSelDataObjectB);
}
return hr;
}
//=--------------------------------------------------------------------------=
//
// SCOPEDATAITEM Marshaling
//
//
//=--------------------------------------------------------------------------=
// Caveat: When returning a string in SCOPEDATAITEM MMC does not use a
// callee allocate/caller free strategy. When in-proc, the owner of the memory
// must insure that it stays alive for as long as the caller is expected to
// use it (e.g. scope item display name must remain valid for the life of the
// scope item). When out-of-proc, that returned string will be allocated by
// the proxy using CoTaskMemAlloc() and it will never be freed so there will
// be some leaks.
//=--------------------------------------------------------------------------=
static void SCOPEDATAITEM_TO_WIRE
(
SCOPEDATAITEM *psdi,
WIRE_SCOPEDATAITEM *pwsdi
)
{
pwsdi->mask = psdi->mask;
pwsdi->nImage = psdi->nImage;
pwsdi->nOpenImage = psdi->nOpenImage;
pwsdi->nState = psdi->nState;
pwsdi->cChildren = psdi->cChildren;
pwsdi->lParam = psdi->lParam;
pwsdi->relativeID = psdi->relativeID;
pwsdi->ID = psdi->ID;
if ( SDI_STR != (psdi->mask & SDI_STR) )
{
pwsdi->pwszDisplayName = NULL;
pwsdi->fUsingCallbackForString = FALSE;
}
else if (MMC_CALLBACK == psdi->displayname)
{
pwsdi->pwszDisplayName = NULL;
pwsdi->fUsingCallbackForString = TRUE;
}
else if (NULL == psdi->displayname)
{
pwsdi->pwszDisplayName = NULL;
pwsdi->fUsingCallbackForString = FALSE;
}
else
{
// A string is being passed. Need to CoTaskMemAlloc() it so that
// the MIDL generated stub can free it after transmission
int cbString = (lstrlenW(psdi->displayname) + 1) * sizeof(psdi->displayname[0]);
pwsdi->pwszDisplayName = (LPOLESTR)CoTaskMemAlloc(cbString);
if (NULL == pwsdi->pwszDisplayName)
{
RpcRaiseException( E_OUTOFMEMORY );
}
else
{
memcpy(pwsdi->pwszDisplayName, psdi->displayname, cbString);
}
pwsdi->fUsingCallbackForString = FALSE;
}
}
static void WIRE_TO_SCOPEDATAITEM
(
WIRE_SCOPEDATAITEM *pwsdi,
SCOPEDATAITEM *psdi
)
{
psdi->mask = pwsdi->mask;
psdi->nImage = pwsdi->nImage;
psdi->nOpenImage = pwsdi->nOpenImage;
psdi->nState = pwsdi->nState;
psdi->cChildren = pwsdi->cChildren;
psdi->lParam = pwsdi->lParam;
psdi->relativeID = pwsdi->relativeID;
psdi->ID = pwsdi->ID;
if ( SDI_STR != (psdi->mask & SDI_STR) )
{
psdi->displayname = NULL;
}
else if (pwsdi->fUsingCallbackForString)
{
psdi->displayname = MMC_CALLBACK;
}
else
{
psdi->displayname = pwsdi->pwszDisplayName;
}
}
HRESULT STDMETHODCALLTYPE IComponentData_GetDisplayInfo_Proxy
(
IComponentData __RPC_FAR *This,
SCOPEDATAITEM __RPC_FAR *pScopeDataItem
)
{
WIRE_SCOPEDATAITEM wsdi;
HRESULT hr;
// Make sure the string pointer is NULL so that it is not marshaled as it
// is never passed from MMC to the snap-in. (MMC might not have initialized
// the pointer).
pScopeDataItem->displayname = NULL;
SCOPEDATAITEM_TO_WIRE(pScopeDataItem, &wsdi);
hr = IComponentData_RemGetDisplayInfo_Proxy(This, &wsdi);
WIRE_TO_SCOPEDATAITEM(&wsdi, pScopeDataItem);
return hr;
}
HRESULT STDMETHODCALLTYPE IComponentData_GetDisplayInfo_Stub
(
IComponentData __RPC_FAR *This,
WIRE_SCOPEDATAITEM __RPC_FAR *pwsdi
)
{
SCOPEDATAITEM sdi;
HRESULT hr;
WIRE_TO_SCOPEDATAITEM(pwsdi, &sdi);
hr = This->lpVtbl->GetDisplayInfo(This, &sdi);
SCOPEDATAITEM_TO_WIRE(&sdi, pwsdi);
return hr;
}
HRESULT STDMETHODCALLTYPE IConsoleNameSpace_InsertItem_Proxy
(
IConsoleNameSpace __RPC_FAR *This,
LPSCOPEDATAITEM pItem
)
{
WIRE_SCOPEDATAITEM wsdi;
HRESULT hr;
HSCOPEITEM ItemID;
SCOPEDATAITEM_TO_WIRE(pItem, &wsdi);
hr = IConsoleNameSpace_RemInsertItem_Proxy(This, &wsdi, &ItemID);
// The only returned field is the item ID so copy it from the wire
// structure to the client structure
pItem->ID = ItemID;
return hr;
}
HRESULT STDMETHODCALLTYPE IConsoleNameSpace_InsertItem_Stub
(
IConsoleNameSpace __RPC_FAR *This,
WIRE_SCOPEDATAITEM __RPC_FAR *pwsdi,
HSCOPEITEM __RPC_FAR *pItemID
)
{
SCOPEDATAITEM sdi;
HRESULT hr;
WIRE_TO_SCOPEDATAITEM(pwsdi, &sdi);
hr = This->lpVtbl->InsertItem(This, &sdi);
// The only returned field is the itemID.
*pItemID = sdi.ID;
return hr;
}
HRESULT STDMETHODCALLTYPE IConsoleNameSpace_SetItem_Proxy
(
IConsoleNameSpace __RPC_FAR *This,
LPSCOPEDATAITEM pItem
)
{
WIRE_SCOPEDATAITEM wsdi;
SCOPEDATAITEM_TO_WIRE(pItem, &wsdi);
return IConsoleNameSpace_RemSetItem_Proxy(This, &wsdi);
}
HRESULT STDMETHODCALLTYPE IConsoleNameSpace_SetItem_Stub
(
IConsoleNameSpace __RPC_FAR *This,
WIRE_SCOPEDATAITEM __RPC_FAR *pwsdi
)
{
SCOPEDATAITEM sdi;
WIRE_TO_SCOPEDATAITEM(pwsdi, &sdi);
return This->lpVtbl->SetItem(This, &sdi);
}
HRESULT STDMETHODCALLTYPE IConsoleNameSpace_GetItem_Proxy
(
IConsoleNameSpace __RPC_FAR *This,
LPSCOPEDATAITEM pItem
)
{
WIRE_SCOPEDATAITEM wsdi;
HRESULT hr;
// Make sure the string pointer is NULL so that it is not marshaled as it
// is never passed from the snap-in to MMC. (It might not have be
// initialized).
pItem->displayname = NULL;
SCOPEDATAITEM_TO_WIRE(pItem, &wsdi);
hr = IConsoleNameSpace_RemGetItem_Proxy(This, &wsdi);
WIRE_TO_SCOPEDATAITEM(&wsdi, pItem);
return hr;
}
HRESULT STDMETHODCALLTYPE IConsoleNameSpace_GetItem_Stub
(
IConsoleNameSpace __RPC_FAR *This,
WIRE_SCOPEDATAITEM __RPC_FAR *pwsdi
)
{
SCOPEDATAITEM sdi;
HRESULT hr;
WIRE_TO_SCOPEDATAITEM(pwsdi, &sdi);
hr = This->lpVtbl->GetItem(This, &sdi);
SCOPEDATAITEM_TO_WIRE(&sdi, pwsdi);
return hr;
}
//=--------------------------------------------------------------------------=
//
// RESULTDATAITEM Marshaling
//
//
//=--------------------------------------------------------------------------=
// Caveat: When returning a string in RESULTDATAITEM MMC does not use a
// callee allocate/caller free strategy. When in-proc, the owner of the memory
// must insure that it stays alive for as long as the caller is expected to
// use it (e.g. list item column data must remain valid for the life of the
// list item). When out-of-proc, that returned string will be allocated by
// the proxy using SysAllocString() and it will never be freed so there will
// be some leaks.
//=--------------------------------------------------------------------------=
static void RESULTDATAITEM_TO_WIRE
(
RESULTDATAITEM *prdi,
WIRE_RESULTDATAITEM *pwrdi
)
{
pwrdi->mask = prdi->mask;
pwrdi->bScopeItem = prdi->bScopeItem;
pwrdi->itemID = prdi->itemID;
pwrdi->nIndex = prdi->nIndex;
pwrdi->nCol = prdi->nCol;
pwrdi->nImage = prdi->nImage;
pwrdi->nState = prdi->nState;
pwrdi->lParam = prdi->lParam;
pwrdi->iIndent = prdi->iIndent;
if ( RDI_STR != (prdi->mask & RDI_STR) )
{
pwrdi->str = NULL;
pwrdi->fUsingCallbackForString = FALSE;
}
else if (MMC_CALLBACK == prdi->str)
{
pwrdi->str = NULL;
pwrdi->fUsingCallbackForString = TRUE;
}
else if (NULL == prdi->str)
{
pwrdi->str = NULL;
pwrdi->fUsingCallbackForString = FALSE;
}
else
{
// A string is being passed. Need to CoTaskMemAlloc() it so that
// the MIDL generated stub can free it after transmission
int cbString = (lstrlenW(prdi->str) + 1) * sizeof(prdi->str[0]);
pwrdi->str = (LPOLESTR)CoTaskMemAlloc(cbString);
if (NULL == pwrdi->str)
{
RpcRaiseException( E_OUTOFMEMORY );
}
else
{
memcpy(pwrdi->str, prdi->str, cbString);
}
pwrdi->fUsingCallbackForString = FALSE;
}
}
static void WIRE_TO_RESULTDATAITEM
(
WIRE_RESULTDATAITEM *pwrdi,
RESULTDATAITEM *prdi
)
{
prdi->mask = pwrdi->mask;
prdi->bScopeItem = pwrdi->bScopeItem;
prdi->itemID = pwrdi->itemID;
prdi->nIndex = pwrdi->nIndex;
prdi->nCol = pwrdi->nCol;
prdi->nImage = pwrdi->nImage;
prdi->nState = pwrdi->nState;
prdi->lParam = pwrdi->lParam;
prdi->iIndent = pwrdi->iIndent;
if ( RDI_STR != (prdi->mask & RDI_STR) )
{
prdi->str = NULL;
}
else if (pwrdi->fUsingCallbackForString)
{
prdi->str = MMC_CALLBACK;
}
else
{
prdi->str = pwrdi->str;
}
}
HRESULT STDMETHODCALLTYPE IComponent_GetDisplayInfo_Proxy
(
IComponent __RPC_FAR *This,
RESULTDATAITEM __RPC_FAR *pResultDataItem
)
{
WIRE_RESULTDATAITEM wrdi;
HRESULT hr;
// Make sure the string pointer is NULL so that it is not marshaled as it
// is never passed from MMC to the snap-in. (MMC might not have initialized
// the pointer).
pResultDataItem->str = NULL;
RESULTDATAITEM_TO_WIRE(pResultDataItem, &wrdi);
hr = IComponent_RemGetDisplayInfo_Proxy(This, &wrdi);
WIRE_TO_RESULTDATAITEM(&wrdi, pResultDataItem);
return hr;
}
HRESULT STDMETHODCALLTYPE IComponent_GetDisplayInfo_Stub
(
IComponent __RPC_FAR *This,
WIRE_RESULTDATAITEM __RPC_FAR *pwrdi
)
{
RESULTDATAITEM rdi;
HRESULT hr;
WIRE_TO_RESULTDATAITEM(pwrdi, &rdi);
hr = This->lpVtbl->GetDisplayInfo(This, &rdi);
RESULTDATAITEM_TO_WIRE(&rdi, pwrdi);
return hr;
}
HRESULT STDMETHODCALLTYPE IResultData_InsertItem_Proxy
(
IResultData __RPC_FAR *This,
LPRESULTDATAITEM pItem
)
{
WIRE_RESULTDATAITEM wrdi;
HRESULT hr;
HRESULTITEM ItemID;
RESULTDATAITEM_TO_WIRE(pItem, &wrdi);
hr = IResultData_RemInsertItem_Proxy(This, &wrdi, &ItemID);
// The only returned field is the itemID so copy it from the wire
// structure to the client structure
pItem->itemID = ItemID;
return hr;
}
HRESULT STDMETHODCALLTYPE IResultData_InsertItem_Stub
(
IResultData __RPC_FAR *This,
WIRE_RESULTDATAITEM __RPC_FAR *pwrdi,
HRESULTITEM __RPC_FAR *pItemID
)
{
RESULTDATAITEM rdi;
HRESULT hr;
WIRE_TO_RESULTDATAITEM(pwrdi, &rdi);
hr = This->lpVtbl->InsertItem(This, &rdi);
// The only returned field is the itemID.
*pItemID = rdi.itemID;
return hr;
}
HRESULT STDMETHODCALLTYPE IResultData_SetItem_Proxy
(
IResultData __RPC_FAR *This,
LPRESULTDATAITEM pItem
)
{
WIRE_RESULTDATAITEM wrdi;
RESULTDATAITEM_TO_WIRE(pItem, &wrdi);
return IResultData_RemSetItem_Proxy(This, &wrdi);
}
HRESULT STDMETHODCALLTYPE IResultData_SetItem_Stub
(
IResultData __RPC_FAR *This,
WIRE_RESULTDATAITEM __RPC_FAR *pwrdi
)
{
RESULTDATAITEM rdi;
WIRE_TO_RESULTDATAITEM(pwrdi, &rdi);
return This->lpVtbl->SetItem(This, &rdi);
}
HRESULT STDMETHODCALLTYPE IResultData_GetItem_Proxy
(
IResultData __RPC_FAR *This,
LPRESULTDATAITEM pItem
)
{
WIRE_RESULTDATAITEM wrdi;
HRESULT hr;
// Make sure the string pointer is NULL so that it is not marshaled as it
// is never passed from the snap-in to MMC. (It might not have be
// initialized).
pItem->str = NULL;
RESULTDATAITEM_TO_WIRE(pItem, &wrdi);
hr = IResultData_RemGetItem_Proxy(This, &wrdi);
WIRE_TO_RESULTDATAITEM(&wrdi, pItem);
return hr;
}
HRESULT STDMETHODCALLTYPE IResultData_GetItem_Stub
(
IResultData __RPC_FAR *This,
WIRE_RESULTDATAITEM __RPC_FAR *pwrdi
)
{
RESULTDATAITEM rdi;
HRESULT hr;
WIRE_TO_RESULTDATAITEM(pwrdi, &rdi);
hr = This->lpVtbl->GetItem(This, &rdi);
RESULTDATAITEM_TO_WIRE(&rdi, pwrdi);
return hr;
}
HRESULT STDMETHODCALLTYPE IResultData_GetNextItem_Proxy
(
IResultData __RPC_FAR *This,
LPRESULTDATAITEM pItem
)
{
WIRE_RESULTDATAITEM wrdi;
HRESULT hr;
// Make sure the string pointer is NULL so that it is not marshaled as it
// is never passed from the snap-in to MMC. (It might not have be
// initialized).
pItem->str = NULL;
RESULTDATAITEM_TO_WIRE(pItem, &wrdi);
hr = IResultData_RemGetNextItem_Proxy(This, &wrdi);
WIRE_TO_RESULTDATAITEM(&wrdi, pItem);
return hr;
}
HRESULT STDMETHODCALLTYPE IResultData_GetNextItem_Stub
(
IResultData __RPC_FAR *This,
WIRE_RESULTDATAITEM __RPC_FAR *pwrdi
)
{
RESULTDATAITEM rdi;
HRESULT hr;
WIRE_TO_RESULTDATAITEM(pwrdi, &rdi);
hr = This->lpVtbl->GetNextItem(This, &rdi);
RESULTDATAITEM_TO_WIRE(&rdi, pwrdi);
return hr;
}
//=--------------------------------------------------------------------------=
//
// HICON Marshaling
//
//=--------------------------------------------------------------------------=
// In wtypes.idl HICON is defined with the wire_marshal attribute with its
// 'on-the-wire' type as a pointer to a RemotableHandle. RemotableHandle is
// defined in wtypes.idl as
//
// typedef union _RemotableHandle switch( long fContext ) u
// {
// case WDT_INPROC_CALL: long hInproc;
// case WDT_REMOTE_CALL: long hRemote;
// } RemotableHandle;
//
// A wire_marshal type must supply routines to size, marhsal, unmarshal, and
// free marshaling data. Those routines are in ole32.dll but someone forgot to
// export them. (ole32 also has routines to marshal bitmaps, hwnds, etc. that
// are all exported). The code has been plagiarized here from ole32. The source
// is in \\savik\cairo\src\ole32\oleprx32\proxy\transmit.cxx with some macros in
// transmit.h in that same directory.
//
//=--------------------------------------------------------------------------=
//
// The following defines and macros are from transmit.h. Note that
// USER_CALL_CTXT_MASK is from rpcndr.h and WDT_REMOTE_CALL is from wtypes.idl.
//
#define ALIGN( pStuff, cAlign ) \
pStuff = (unsigned char *)((ULONG_PTR)((pStuff) + (cAlign)) & ~ (cAlign))
#define LENGTH_ALIGN( Length, cAlign ) \
Length = (((Length) + (cAlign)) & ~ (cAlign))
#define PULONG_LV_CAST *(unsigned long __RPC_FAR * __RPC_FAR *)&
#define DIFFERENT_MACHINE_CALL( Flags) \
(USER_CALL_CTXT_MASK(Flags) == MSHCTX_DIFFERENTMACHINE)
#define WDT_HANDLE_MARKER WDT_INPROC_CALL
//=--------------------------------------------------------------------------=
// HICON_UserSize
//=--------------------------------------------------------------------------=
//
// Parameters:
// unsigned long __RPC_FAR *pFlags [in] data format & context (see below)
// unsigned long StartingSize [in] current buffer size
// HICON __RPC_FAR *hIcon [in] HICON to be marshaled
//
//
// Flags Layout
// ============
//
//----------------------------------------------------------------------
// Bits Flag Value
//----------------------------------------------------------------------
// 31-24 Floating-point representation 0 = IEEE
// 1 = VAX
// 2 = Cray
// 3 = IBM
//----------------------------------------------------------------------
// 23-20 Integer and floating-point byte
// order 0 = Big-endian
// 1 = Little-endian
//----------------------------------------------------------------------
// 19-16 Character representation 0 = ASCII
// 1 = EBCDIC
//----------------------------------------------------------------------
// 15-0 Marshaling context flag 0 = MSHCTX_LOCAL
// 1 = MSHCTX_NOSHAREDMEM
// 2 = MSHCTX_DIFFERENTMSCHINE
// 3 = MSHCTX_INPROC
//----------------------------------------------------------------------
//
// Output:
// New buffer size after adding amount needed for HICON marshaled data
//
// Notes:
//
// Called from MIDL generated proxy to determine buffer size needed for
// marhaled data.
//
unsigned long __RPC_USER HICON_UserSize
(
unsigned long __RPC_FAR *pFlags,
unsigned long StartingSize,
HICON __RPC_FAR *hIcon
)
{
if (NULL == hIcon)
{
return StartingSize;
}
// If marshaling context is to a different machine then we don't support
// that.
if ( DIFFERENT_MACHINE_CALL(*pFlags) )
{
RpcRaiseException( RPC_S_INVALID_TAG );
}
// Make sure that our data will fall at a long boundary
LENGTH_ALIGN( StartingSize, 3 );
//Add the length
return StartingSize + 8;
}
//=--------------------------------------------------------------------------=
// HICON_UserMarhsal
//=--------------------------------------------------------------------------=
//
// Parameters:
// unsigned long __RPC_FAR *pFlags [in] data format & context (see above)
// unsigned char __RPC_FAR *pBuffer [in] current buffer size
// HICON __RPC_FAR *hIcon [in] HICON to be marshaled
//
//
// Output:
// Pointer to buffer location following HICON's marshaling data
//
// Notes:
//
// Called from MIDL generated proxy to marshal an HICON
//
unsigned char __RPC_FAR * __RPC_USER HICON_UserMarshal
(
unsigned long __RPC_FAR *pFlags,
unsigned char __RPC_FAR *pBuffer,
HICON __RPC_FAR *hIcon
)
{
if (NULL == hIcon)
{
return pBuffer;
}
if ( DIFFERENT_MACHINE_CALL(*pFlags) )
{
RpcRaiseException( RPC_S_INVALID_TAG );
}
// Make sure that our data will fall at a long boundary
ALIGN( pBuffer, 3 );
*( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER;
*( PULONG_LV_CAST pBuffer)++ = *((long *)hIcon);
return pBuffer;
}
//=--------------------------------------------------------------------------=
// HICON_UserUnmarhsal
//=--------------------------------------------------------------------------=
//
// Parameters:
// unsigned long __RPC_FAR *pFlags [in] data format & context (see above)
// unsigned char __RPC_FAR *pBuffer [in] current buffer size
// HICON __RPC_FAR *hIcon [in] HICON to be marshaled
//
//
// Output:
// Pointer to buffer location following HICON's marshaling data
//
// Notes:
//
// Called from MIDL generated stub to unmarshal an HICON
//
unsigned char __RPC_FAR *__RPC_USER HICON_UserUnmarshal
(
unsigned long __RPC_FAR *pFlags,
unsigned char __RPC_FAR *pBuffer,
HICON __RPC_FAR *hIcon
)
{
unsigned long HandleMarker;
ALIGN( pBuffer, 3 );
HandleMarker = *( PULONG_LV_CAST pBuffer)++;
if ( HandleMarker == WDT_HANDLE_MARKER )
*((long *)hIcon) = *( PULONG_LV_CAST pBuffer)++;
else
RpcRaiseException( RPC_S_INVALID_TAG );
return pBuffer;
}
//=--------------------------------------------------------------------------=
// HICON_UserUnmarhsal
//=--------------------------------------------------------------------------=
//
// Parameters:
// unsigned long __RPC_FAR *pFlags [in] data format & context (see above)
// HICON __RPC_FAR *hIcon [in] HICON that was unmarshaled
//
//
// Output:
// None
//
// Notes:
//
// Called from MIDL generated stub to free any associated marshaling data
// allocated during unmarshaling for embedded pointers. Not used for HICON.
//
void __RPC_USER HICON_UserFree
(
unsigned long __RPC_FAR *pFlags,
HICON __RPC_FAR *hIcon
)
{
}
//=--------------------------------------------------------------------------=
//
// IImageList Marshaling
//
//
//=--------------------------------------------------------------------------=
// These methods needed call_as because the HICON and HBITMAP parameters are
// specified as long pointers in the original IDL.
//=--------------------------------------------------------------------------=
HRESULT STDMETHODCALLTYPE IImageList_ImageListSetIcon_Proxy
(
IImageList __RPC_FAR *This,
LONG_PTR __RPC_FAR *pIcon,
long nLoc
)
{
return IImageList_RemImageListSetIcon_Proxy(This, (HICON)pIcon, nLoc);
}
HRESULT STDMETHODCALLTYPE IImageList_ImageListSetIcon_Stub
(
IImageList __RPC_FAR *This,
HICON hIcon,
long nLoc
)
{
return This->lpVtbl->ImageListSetIcon(This, (LONG_PTR __RPC_FAR*)hIcon, nLoc);
}
HRESULT STDMETHODCALLTYPE IImageList_ImageListSetStrip_Proxy
(
IImageList __RPC_FAR *This,
LONG_PTR __RPC_FAR *pBMapSm,
LONG_PTR __RPC_FAR *pBMapLg,
long nStartLoc,
COLORREF cMask
)
{
return IImageList_RemImageListSetStrip_Proxy(This,
(HBITMAP)pBMapSm,
(HBITMAP)pBMapLg,
nStartLoc,
cMask);
}
HRESULT STDMETHODCALLTYPE IImageList_ImageListSetStrip_Stub
(
IImageList __RPC_FAR *This,
HBITMAP hbmSmall,
HBITMAP hbmLarge,
long nStartLoc,
COLORREF cMask
)
{
return This->lpVtbl->ImageListSetStrip(This,
(LONG_PTR __RPC_FAR*)hbmSmall,
(LONG_PTR __RPC_FAR*)hbmLarge,
nStartLoc,
cMask);
}
HRESULT STDMETHODCALLTYPE IExtendPropertySheet_CreatePropertyPages_Proxy
(
IExtendPropertySheet __RPC_FAR *This,
LPPROPERTYSHEETCALLBACK lpProvider,
LONG_PTR handle,
LPDATAOBJECT lpIDataObject
)
{
HRESULT hr = S_OK;
WIRE_PROPERTYPAGES *pPages = NULL;
WIRE_PROPERTYPAGE *pPage = NULL;
ULONG i = 0;
ULONG j = 0;
IExtendPropertySheetRemote *piExtendPropertySheetRemote = NULL;
IRemotePropertySheetManager *piRemotePropertySheetManager = NULL;
// Make sure the snap-in knows we are remoted. We do this here because
// this is the first opportunity for the proxy to inform a property page
// extension that it is remote and pass it data such as the MMC.exe path
// and the MMC command line.
hr = SetRemote((IUnknown *)This);
if (FAILED(hr))
{
goto Cleanup;
}
// Call the IExtendPropertySheetRemote method which will return a filled in
// WIRE_PROPERTYPAGES from the remoted snap-in.
hr = This->lpVtbl->QueryInterface(This, &IID_IExtendPropertySheetRemote,
(void **)&piExtendPropertySheetRemote);
if (FAILED(hr))
{
goto Cleanup;
}
hr = piExtendPropertySheetRemote->lpVtbl->CreatePropertyPageDefs(
piExtendPropertySheetRemote, lpIDataObject, &pPages);
if (FAILED(hr))
{
goto Cleanup;
}
// If there are pages (snap-in might not have added any) then
// CoCreateInstance the remote property sheet manager using the clsid
// returned in WIRE_PROPERTYPAGES. This object will be created in-proc here
// on the MMC side.
if (0 == pPages->cPages)
{
goto Cleanup;
}
hr = CoCreateInstance(&pPages->clsidRemotePropertySheetManager,
NULL, // no aggregation,
CLSCTX_INPROC_SERVER,
&IID_IRemotePropertySheetManager,
(void **)&piRemotePropertySheetManager);
if (FAILED(hr))
{
goto Cleanup;
}
// Pass the remote property sheet manager the WIRE_PROPERTYPAGES and let it
// actually create the property pages and add them to the sheet here on the
// MMC side.
hr = piRemotePropertySheetManager->lpVtbl->CreateRemotePages(
piRemotePropertySheetManager,
lpProvider,
handle,
lpIDataObject,
pPages);
Cleanup:
if (NULL != piRemotePropertySheetManager)
{
piRemotePropertySheetManager->lpVtbl->Release(piRemotePropertySheetManager);
}
if (NULL != piExtendPropertySheetRemote)
{
piExtendPropertySheetRemote->lpVtbl->Release(piExtendPropertySheetRemote);
}
// Free the WIRE_PROPERTYPAGES and all of its contents.
if (NULL != pPages)
{
// Release the object and free the title for each individual page
for (i = 0, pPage = &pPages->aPages[0]; i < pPages->cPages; i++, pPage++)
{
if (NULL != pPage->apunkObjects)
{
for (j = 0; j < pPage->cObjects; j++)
{
if (NULL != pPage->apunkObjects[j])
{
pPage->apunkObjects[j]->lpVtbl->Release(pPage->apunkObjects[j]);
}
}
CoTaskMemFree(pPage->apunkObjects);
}
if (NULL != pPage->pwszTitle)
{
CoTaskMemFree(pPage->pwszTitle);
}
}
// Free the ProgID prefix
if (NULL != pPages->pwszProgIDStart)
{
CoTaskMemFree(pPages->pwszProgIDStart);
}
// Free all of the snap-in's property page info
if (NULL != pPages->pPageInfos)
{
for (i = 0; i < pPages->pPageInfos->cPages; i++)
{
if (NULL != pPages->pPageInfos->aPageInfo[i].pwszTitle)
{
CoTaskMemFree(pPages->pPageInfos->aPageInfo[i].pwszTitle);
}
if (NULL != pPages->pPageInfos->aPageInfo[i].pwszProgID)
{
CoTaskMemFree(pPages->pPageInfos->aPageInfo[i].pwszProgID);
}
}
CoTaskMemFree(pPages->pPageInfos);
}
// Free all of the objects associated with the sheet
if (NULL != pPages->apunkObjects)
{
for (i = 0; i < pPages->cObjects; i++)
{
if (NULL != pPages->apunkObjects[i])
{
pPages->apunkObjects[i]->lpVtbl->Release(pPages->apunkObjects[i]);
}
}
CoTaskMemFree(pPages->apunkObjects);
}
// Release the extra object and the WIRE_PROPERTYPAGES struct itself
if (NULL != pPages->punkExtra)
{
pPages->punkExtra->lpVtbl->Release(pPages->punkExtra);
}
CoTaskMemFree(pPages);
}
return hr;
}
//=--------------------------------------------------------------------------=
// IExtendPropertySheet_CreatePropertyPages_Stub
//=--------------------------------------------------------------------------=
//
// Parameters:
// IExtendPropertySheet __RPC_FAR *This [in] this pointer
//
// Output:
//
// Notes:
//
// This stub is never called because
// IExtendPropertySheet_CreatePropertyPages_Proxy() (see above) reroutes the
// call to IExtendPropertySheetRemote::CreatePropertyPageDefs().
//
HRESULT STDMETHODCALLTYPE IExtendPropertySheet_CreatePropertyPages_Stub
(
IExtendPropertySheet __RPC_FAR *This
)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE IExtendPropertySheet_QueryPagesFor_Proxy
(
IExtendPropertySheet __RPC_FAR *This,
IDataObject *piDataObject
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject **ppiDataObjects = NULL;
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObject)
{
hr = IsMultiSelect(piDataObject, &fIsMultiSelect);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelect)
{
hr = InterpretMultiSelect(piDataObject, &cDataObjects, &ppiDataObjects);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjects = &piDataObject;
}
hr = IExtendPropertySheet_RemQueryPagesFor_Proxy(This,
cDataObjects,
ppiDataObjects,
fSpecialDataObject,
lSpecialDataObject);
Cleanup:
if ( fIsMultiSelect && (NULL != ppiDataObjects) )
{
(void)GlobalFree(ppiDataObjects);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendPropertySheet_QueryPagesFor_Stub
(
IExtendPropertySheet __RPC_FAR *This,
long cDataObjects,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjects[ ],
BOOL fSpecialDataObject,
long lSpecialDataObject
)
{
HRESULT hr = S_OK;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObject = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjects > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjects, cDataObjects,
&piMultiSelDataObject);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObject = piMultiSelDataObject;
}
else if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
else
{
piDataObject = ppiDataObjects[0];
}
// Call the snap-in
hr = This->lpVtbl->QueryPagesFor(This, piDataObject);
Cleanup:
if (NULL != piMultiSelDataObject)
{
piMultiSelDataObject->lpVtbl->Release(piMultiSelDataObject);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendPropertySheet2_GetWatermarks_Proxy
(
IExtendPropertySheet2 __RPC_FAR *This,
IDataObject *piDataObject,
HBITMAP *lphWatermark,
HBITMAP *lphHeader,
HPALETTE *lphPalette,
BOOL *bStretch
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject **ppiDataObjects = NULL;
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObject)
{
hr = IsMultiSelect(piDataObject, &fIsMultiSelect);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelect)
{
hr = InterpretMultiSelect(piDataObject, &cDataObjects, &ppiDataObjects);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjects = &piDataObject;
}
hr = IExtendPropertySheet2_RemGetWatermarks_Proxy(This,
cDataObjects,
ppiDataObjects,
fSpecialDataObject,
lSpecialDataObject,
lphWatermark,
lphHeader,
lphPalette,
bStretch);
Cleanup:
if ( fIsMultiSelect && (NULL != ppiDataObjects) )
{
(void)GlobalFree(ppiDataObjects);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendPropertySheet2_GetWatermarks_Stub
(
IExtendPropertySheet2 __RPC_FAR *This,
long cDataObjects,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjects[ ],
BOOL fSpecialDataObject,
long lSpecialDataObject,
HBITMAP *lphWatermark,
HBITMAP *lphHeader,
HPALETTE *lphPalette,
BOOL *bStretch
)
{
HRESULT hr = S_OK;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObject = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjects > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjects, cDataObjects,
&piMultiSelDataObject);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObject = piMultiSelDataObject;
}
else if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
else
{
piDataObject = ppiDataObjects[0];
}
// Call the snap-in
hr = This->lpVtbl->GetWatermarks(This,
piDataObject,
lphWatermark,
lphHeader,
lphPalette,
bStretch);
Cleanup:
if (NULL != piMultiSelDataObject)
{
piMultiSelDataObject->lpVtbl->Release(piMultiSelDataObject);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendPropertySheetRemote_CreatePropertyPageDefs_Proxy
(
IExtendPropertySheetRemote __RPC_FAR *This,
IDataObject *piDataObject,
WIRE_PROPERTYPAGES **ppPages
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject **ppiDataObjects = NULL;
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObject)
{
hr = IsMultiSelect(piDataObject, &fIsMultiSelect);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelect)
{
hr = InterpretMultiSelect(piDataObject, &cDataObjects, &ppiDataObjects);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjects = &piDataObject;
}
hr = IExtendPropertySheetRemote_RemCreatePropertyPageDefs_Proxy(
This,
cDataObjects,
ppiDataObjects,
fSpecialDataObject,
lSpecialDataObject,
ppPages);
Cleanup:
if ( fIsMultiSelect && (NULL != ppiDataObjects) )
{
(void)GlobalFree(ppiDataObjects);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendPropertySheetRemote_CreatePropertyPageDefs_Stub
(
IExtendPropertySheetRemote __RPC_FAR *This,
long cDataObjects,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjects[ ],
BOOL fSpecialDataObject,
long lSpecialDataObject,
WIRE_PROPERTYPAGES **ppPages
)
{
HRESULT hr = S_OK;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObject = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjects > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjects, cDataObjects,
&piMultiSelDataObject);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObject = piMultiSelDataObject;
}
else if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
else
{
piDataObject = ppiDataObjects[0];
}
// Call the snap-in
hr = This->lpVtbl->CreatePropertyPageDefs(This, piDataObject, ppPages);
Cleanup:
if (NULL != piMultiSelDataObject)
{
piMultiSelDataObject->lpVtbl->Release(piMultiSelDataObject);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IPropertySheetProvider_CreatePropertySheet_Proxy
(
IPropertySheetProvider __RPC_FAR *This,
LPCWSTR title,
boolean type,
MMC_COOKIE cookie,
IDataObject *piDataObject,
DWORD dwOptions
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject **ppiDataObjects = NULL;
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObject)
{
hr = IsMultiSelect(piDataObject, &fIsMultiSelect);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelect)
{
hr = InterpretMultiSelect(piDataObject, &cDataObjects, &ppiDataObjects);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjects = &piDataObject;
}
hr = IPropertySheetProvider_RemCreatePropertySheet_Proxy(This,
title,
type,
cookie,
cDataObjects,
ppiDataObjects,
fSpecialDataObject,
lSpecialDataObject,
dwOptions);
Cleanup:
if ( fIsMultiSelect && (NULL != ppiDataObjects) )
{
(void)GlobalFree(ppiDataObjects);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IPropertySheetProvider_CreatePropertySheet_Stub
(
IPropertySheetProvider __RPC_FAR *This,
LPCWSTR title,
boolean type,
MMC_COOKIE cookie,
long cDataObjects,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjects[ ],
BOOL fSpecialDataObject,
long lSpecialDataObject,
DWORD dwOptions
)
{
HRESULT hr = S_OK;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObject = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjects > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjects, cDataObjects,
&piMultiSelDataObject);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObject = piMultiSelDataObject;
}
else if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
else
{
piDataObject = ppiDataObjects[0];
}
// Call the snap-in
hr = This->lpVtbl->CreatePropertySheet(This, title, type, cookie, piDataObject, dwOptions);
Cleanup:
if (NULL != piMultiSelDataObject)
{
piMultiSelDataObject->lpVtbl->Release(piMultiSelDataObject);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IPropertySheetProvider_FindPropertySheet_Proxy
(
IPropertySheetProvider __RPC_FAR *This,
MMC_COOKIE cookie,
IComponent *piComponent,
IDataObject *piDataObject
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject **ppiDataObjects = NULL;
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObject)
{
hr = IsMultiSelect(piDataObject, &fIsMultiSelect);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelect)
{
hr = InterpretMultiSelect(piDataObject, &cDataObjects, &ppiDataObjects);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjects = &piDataObject;
}
hr = IPropertySheetProvider_RemFindPropertySheet_Proxy(This,
cookie,
piComponent,
cDataObjects,
ppiDataObjects,
fSpecialDataObject,
lSpecialDataObject);
Cleanup:
if ( fIsMultiSelect && (NULL != ppiDataObjects) )
{
(void)GlobalFree(ppiDataObjects);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IPropertySheetProvider_FindPropertySheet_Stub
(
IPropertySheetProvider __RPC_FAR *This,
MMC_COOKIE cookie,
IComponent *piComponent,
long cDataObjects,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjects[ ],
BOOL fSpecialDataObject,
long lSpecialDataObject
)
{
HRESULT hr = S_OK;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObject = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjects > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjects, cDataObjects,
&piMultiSelDataObject);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObject = piMultiSelDataObject;
}
else if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
else
{
piDataObject = ppiDataObjects[0];
}
// Call the snap-in
hr = This->lpVtbl->FindPropertySheet(This, cookie, piComponent, piDataObject);
Cleanup:
if (NULL != piMultiSelDataObject)
{
piMultiSelDataObject->lpVtbl->Release(piMultiSelDataObject);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendContextMenu_AddMenuItems_Proxy
(
IExtendContextMenu __RPC_FAR *This,
LPDATAOBJECT piDataObject,
LPCONTEXTMENUCALLBACK piCallback,
long __RPC_FAR *pInsertionAllowed
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject **ppiDataObjects = NULL;
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
// Make sure the snap-in knows we are remoted. We do this here because
// this is the first opportunity for the proxy to inform a context menu
// extension that it is remote.
hr = SetRemote((IUnknown *)This);
if (FAILED(hr))
{
goto Cleanup;
}
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObject)
{
hr = IsMultiSelect(piDataObject, &fIsMultiSelect);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelect)
{
hr = InterpretMultiSelect(piDataObject, &cDataObjects, &ppiDataObjects);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjects = &piDataObject;
}
hr = IExtendContextMenu_RemAddMenuItems_Proxy(This,
cDataObjects,
ppiDataObjects,
fSpecialDataObject,
lSpecialDataObject,
piCallback,
pInsertionAllowed);
Cleanup:
if ( fIsMultiSelect && (NULL != ppiDataObjects) )
{
(void)GlobalFree(ppiDataObjects);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendContextMenu_AddMenuItems_Stub
(
IExtendContextMenu __RPC_FAR *This,
long cDataObjects,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjects[ ],
BOOL fSpecialDataObject,
long lSpecialDataObject,
LPCONTEXTMENUCALLBACK piCallback,
long __RPC_FAR *pInsertionAllowed
)
{
HRESULT hr = S_OK;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObject = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjects > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjects, cDataObjects,
&piMultiSelDataObject);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObject = piMultiSelDataObject;
}
else if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
else
{
piDataObject = ppiDataObjects[0];
}
// Call the snap-in
hr = This->lpVtbl->AddMenuItems(This, piDataObject,
piCallback, pInsertionAllowed);
Cleanup:
if (NULL != piMultiSelDataObject)
{
piMultiSelDataObject->lpVtbl->Release(piMultiSelDataObject);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendContextMenu_Command_Proxy
(
IExtendContextMenu __RPC_FAR *This,
long lCommandID,
LPDATAOBJECT piDataObject
)
{
HRESULT hr = S_OK;
BOOL fIsMultiSelect = FALSE;
long cDataObjects = 1L;
IDataObject **ppiDataObjects = NULL;
BOOL fSpecialDataObject = FALSE;
long lSpecialDataObject = 0;
// Check for special data objects such DOBJ_CUSTOMWEB etc.
CheckForSpecialDataObjects(&piDataObject, &fSpecialDataObject, &lSpecialDataObject);
// If this is a mutliple selection then we need to extract the data
// objects in the HGLOBAL
if (!fSpecialDataObject)
{
hr = IsMultiSelect(piDataObject, &fIsMultiSelect);
if (FAILED(hr))
{
goto Cleanup;
}
}
if (fIsMultiSelect)
{
hr = InterpretMultiSelect(piDataObject, &cDataObjects, &ppiDataObjects);
if (FAILED(hr))
{
goto Cleanup;
}
}
else
{
ppiDataObjects = &piDataObject;
}
hr = IExtendContextMenu_RemCommand_Proxy(This,
cDataObjects,
ppiDataObjects,
fSpecialDataObject,
lSpecialDataObject,
lCommandID);
Cleanup:
if ( fIsMultiSelect && (NULL != ppiDataObjects) )
{
(void)GlobalFree(ppiDataObjects);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IExtendContextMenu_Command_Stub
(
IExtendContextMenu __RPC_FAR *This,
long cDataObjects,
IDataObject __RPC_FAR *__RPC_FAR ppiDataObjects[ ],
BOOL fSpecialDataObject,
long lSpecialDataObject,
long lCommandID
)
{
HRESULT hr = S_OK;
IDataObject *piDataObject = NULL; // Not AddRef()ed
IDataObject *piMultiSelDataObject = NULL;
// If there is more than one data object then we need to pack them into a
// a separate data object that appears as a multi-select data object.
if (cDataObjects > 1L)
{
hr = CreateMultiSelDataObject(ppiDataObjects, cDataObjects,
&piMultiSelDataObject);
if (FAILED(hr))
{
goto Cleanup;
}
piDataObject = piMultiSelDataObject;
}
else if (fSpecialDataObject)
{
piDataObject = (IDataObject *)lSpecialDataObject;
}
else
{
piDataObject = ppiDataObjects[0];
}
// Call the snap-in
hr = This->lpVtbl->Command(This, lCommandID, piDataObject);
Cleanup:
if (NULL != piMultiSelDataObject)
{
piMultiSelDataObject->lpVtbl->Release(piMultiSelDataObject);
}
return hr;
}
HRESULT STDMETHODCALLTYPE IColumnData_GetColumnConfigData_Proxy
(
IColumnData __RPC_FAR *This,
SColumnSetID __RPC_FAR *pColID,
MMC_COLUMN_SET_DATA __RPC_FAR *__RPC_FAR *ppColSetData
)
{
HRESULT hr = S_OK;
size_t cbColData = 0;
MMC_COLUMN_SET_DATA *pColSetData = NULL;
// Call the proxy and get the returned data from MMC
hr = IColumnData_RemGetColumnConfigData_Proxy(This, pColID, ppColSetData);
if (FAILED(hr))
{
goto Cleanup;
}
// If no data was returned then there is nothing to do
if (NULL == *ppColSetData)
{
goto Cleanup;
}
if (NULL == (*ppColSetData)->pColData)
{
goto Cleanup;
}
// At this point the MIDL-generated proxy has returned an MMC_COLUMN_SET_DATA
// in which the embedded pointer pColData points to a separate block of
// memory which must be freed independently. The snap-in thinks that
// pColData points into the same block of memory so it will only call
// CoTaskMemFree for the MMC_COLUMN_SET_DATA. We need to allocate a new single
// block in the format the snap-in is expecting and free the memory returned
// from the proxy.
cbColData = sizeof(MMC_COLUMN_DATA) * (*ppColSetData)->nNumCols;
pColSetData = (MMC_COLUMN_SET_DATA *)CoTaskMemAlloc(
sizeof(MMC_COLUMN_SET_DATA) + cbColData);
if (NULL == pColSetData)
{
CoTaskMemFree((*ppColSetData)->pColData);
CoTaskMemFree(*ppColSetData);
*ppColSetData = NULL;
hr = E_OUTOFMEMORY;
}
else
{
// Copy the column set data
memcpy(pColSetData, (*ppColSetData), sizeof(MMC_COLUMN_SET_DATA));
// Set the embedded pointer to point immediately following the
// MMC_COLUMN_SET_DATA
pColSetData->pColData = (MMC_COLUMN_DATA *)(pColSetData + 1);
// Copy the column data
memcpy(pColSetData->pColData, (*ppColSetData)->pColData, cbColData);
// Free the data returned from the proxy
CoTaskMemFree((*ppColSetData)->pColData);
CoTaskMemFree(*ppColSetData);
// Return the new single block pointer to the snap-in
*ppColSetData = pColSetData;
}
Cleanup:
return hr;
}
HRESULT STDMETHODCALLTYPE IColumnData_GetColumnConfigData_Stub
(
IColumnData __RPC_FAR *This,
SColumnSetID __RPC_FAR *pColID,
MMC_COLUMN_SET_DATA __RPC_FAR *__RPC_FAR *ppColSetData
)
{
HRESULT hr = S_OK;
size_t cbColData = 0;
MMC_COLUMN_DATA *pColData = NULL;
// Call into MMC and get the returned data
hr = This->lpVtbl->GetColumnConfigData(This, pColID, ppColSetData);
if (FAILED(hr))
{
goto Cleanup;
}
// If no data was returned then there is nothing to do
if (NULL == *ppColSetData)
{
goto Cleanup;
}
if (NULL == (*ppColSetData)->pColData)
{
goto Cleanup;
}
// At this point MMC has returned a pointer to an MMC_COLUMN_SET_DATA
// that contains an embedded pointer into the same block of memory (pColData).
// MMC expects that the caller will make a single call to CoTaskMemFree().
// The MIDL-generated stub thinks the embedded pointer needs to be freed
// separately so we need to reconstruct the output to use two separate
// blocks.
// Allocate a new MMC_COLUMN_DATA array
cbColData = sizeof(MMC_COLUMN_DATA) * (*ppColSetData)->nNumCols;
pColData = (MMC_COLUMN_DATA *)CoTaskMemAlloc(cbColData);
if (NULL == pColData)
{
CoTaskMemFree(*ppColSetData);
*ppColSetData = NULL;
hr = E_OUTOFMEMORY;
}
else
{
// Copy the column data
memcpy(pColData, (*ppColSetData)->pColData, cbColData);
// Overwrite the existing embedded pointer. There will be no memory leak
// because that pointer pointed into the same block as the
// MMC_COLUMN_SET_DATA and the stub will free the MMC_COLUMN_SET_DATA pointer.
// Now both pointers can be freed independently as the stub expects.
(*ppColSetData)->pColData = pColData;
}
Cleanup:
return hr;
}
HRESULT STDMETHODCALLTYPE IColumnData_GetColumnSortData_Proxy
(
IColumnData __RPC_FAR *This,
SColumnSetID __RPC_FAR *pColID,
MMC_SORT_SET_DATA __RPC_FAR *__RPC_FAR *ppColSortData
)
{
HRESULT hr = S_OK;
size_t cbSortData = 0;
MMC_SORT_SET_DATA *pColSortData = NULL;
// Call the proxy and get the returned data from MMC
hr = IColumnData_RemGetColumnSortData_Proxy(This, pColID, ppColSortData);
if (FAILED(hr))
{
goto Cleanup;
}
// If no data was returned then there is nothing to do
if (NULL == *ppColSortData)
{
goto Cleanup;
}
if (NULL == (*ppColSortData)->pSortData)
{
goto Cleanup;
}
// At this point the MIDL-generated proxy has returned an MMC_SORT_SET_DATA
// in which the embedded pointer pSortData points to a separate block of
// memory which must be freed independently. The snap-in thinks that
// pSortData points into the same block of memory so it will only call
// CoTaskMemFree for the MMC_SORT_SET_DATA. We need to allocate a new single
// block in the format the snap-in is expecting and free the memory returned
// from the proxy.
cbSortData = sizeof(MMC_SORT_DATA) * (*ppColSortData)->nNumItems;
pColSortData = (MMC_SORT_SET_DATA *)CoTaskMemAlloc(
sizeof(MMC_SORT_SET_DATA) + cbSortData);
if (NULL == pColSortData)
{
CoTaskMemFree((*ppColSortData)->pSortData);
CoTaskMemFree(*ppColSortData);
*ppColSortData = NULL;
hr = E_OUTOFMEMORY;
}
else
{
// Copy the sort set data
memcpy(pColSortData, (*ppColSortData), sizeof(MMC_SORT_SET_DATA));
// Set the embedded pointer to point immediately following the
// MMC_SORT_SET_DATA
pColSortData->pSortData = (MMC_SORT_DATA *)(pColSortData + 1);
// Copy the sort data
memcpy(pColSortData->pSortData, (*ppColSortData)->pSortData, cbSortData);
// Free the data returned from the proxy
CoTaskMemFree((*ppColSortData)->pSortData);
CoTaskMemFree(*ppColSortData);
// Return the new single block pointer to the snap-in
*ppColSortData = pColSortData;
}
Cleanup:
return hr;
}
HRESULT STDMETHODCALLTYPE IColumnData_GetColumnSortData_Stub
(
IColumnData __RPC_FAR *This,
SColumnSetID __RPC_FAR *pColID,
MMC_SORT_SET_DATA __RPC_FAR *__RPC_FAR *ppColSortData
)
{
HRESULT hr = S_OK;
size_t cbSortData = 0;
MMC_SORT_DATA *pSortData = NULL;
// Call into MMC and get the returned data
hr = This->lpVtbl->GetColumnSortData(This, pColID, ppColSortData);
if (FAILED(hr))
{
goto Cleanup;
}
// If no data was returned then there is nothing to do
if (NULL == *ppColSortData)
{
goto Cleanup;
}
if (NULL == (*ppColSortData)->pSortData)
{
goto Cleanup;
}
// At this point MMC has returned a pointer to an MMC_SORT_SET_DATA
// that contains an embedded pointer into the same block of memory (pSortData).
// MMC expects that the caller will make a single call to CoTaskMemFree().
// The MIDL-generated stub thinks the embedded pointer needs to be freed
// separately so we need to reconstruct the output to use two separate
// blocks.
// Allocate a new MMC_SORT_DATA array
cbSortData = sizeof(MMC_SORT_DATA) * (*ppColSortData)->nNumItems;
pSortData = (MMC_SORT_DATA *)CoTaskMemAlloc(cbSortData);
if (NULL == pSortData)
{
CoTaskMemFree(*ppColSortData);
*ppColSortData = NULL;
hr = E_OUTOFMEMORY;
}
else
{
// Copy the column data
memcpy(pSortData, (*ppColSortData)->pSortData, cbSortData);
// Overwrite the existing embedded pointer. There will be no memory leak
// because that pointer pointed into the same block as the
// MMC_SORT_SET_DATA and the stub will free the MMC_SORT_SET_DATA pointer.
// Now both pointers can be freed independently as the stub expects.
(*ppColSortData)->pSortData = pSortData;
}
Cleanup:
return hr;
}