You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3728 lines
108 KiB
3728 lines
108 KiB
//=--------------------------------------------------------------------------=
|
|
// 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;
|
|
}
|