Consecutive interface function IDs - windows

I have a COM object interface in midl like
interface InterfaceName : IDispatch
{
[id(1)] HRESULT FunA(...);
[id(2)] HRESULT FunB(...);
[id(3)] HRESULT FunC(...);
}
Are the ids required to be consecutive? Or can I define it like
interface InterfaceName : IDispatch
{
[id(1)] HRESULT FunA(...);
[id(3)] HRESULT FunB(...);
[id(5)] HRESULT FunC(...);
}
Compiling the second version seems to be fine but will there occur any problems at runtime?

Actual id values are arbitrary numbers. They do not have to be consecutive; they just have to be unique. Zero and negative values are, by convention, reserved for certain special methods. Apart from that, there are no rules.

Related

::GetClipboardData of CF_HDROP returns DROPFILE not STGMEDIUM?

Docs for CF_HDROP says:
The data consists of an STGMEDIUM structure that contains a global
memory object. The structure's hGlobal member points to a DROPFILES
structure as its hGlobal member.
but in fact when you use GetClipboardData() it returns data to the DROPFILES itself. That is you don't get the data as a STGMEDIUM that you then have to access via the hGlobal member. Why is that? Docs wrong? Missing docs/details of automatic conversion? or am I reading something wrong?
typedef struct tagSTGMEDIUM {
DWORD tymed;
union {
HBITMAP hBitmap;
HMETAFILEPICT hMetaFilePict;
HENHMETAFILE hEnhMetaFile;
HGLOBAL hGlobal;
LPOLESTR lpszFileName;
IStream *pstm;
IStorage *pstg;
} DUMMYUNIONNAME;
IUnknown *pUnkForRelease;
} uSTGMEDIUM;

How do you use SHCreateShellItemArrayFromDataObject in ShellExtInit::Initialize?

Docs tell me that SHCreateShellItemArrayFromDataObject might be a simpler way to get a list of files from DataObject than DataObject::GetFiles. I want to use the function in ShellExtInit::Initialize, but cannot figure out how.
I need some kind of IShellItemArray to place the result in, but it is an abstract class so I don't know how to define it. And SHCreateShellItemArrayFromDataObject final argument is supposed to be type void**, which I don't know how to satisfy.
How could I fix the code?
HRESULT MyContextMenuHandler::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtObj, HKEY hkeyProgId)
{
[...]
IShellItemArray items; // Class IShellItemArray is abstract
HRESULT hr = SHCreateShellItemArrayFromDataObject(pdtObj, IID_IShellItemArray, &items); // Cannot convert to void**
Interfaces must be accessed by pointers/references only. In this case, you need a pointer variable, and must pass the address of that variable to SHCreateShellItemArrayFromDataObject() (using a type cast) so it can set that pointer to the address of an IShellItemArray-implementing object that the Shell creates for you. For example:
HRESULT MyContextMenuHandler::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtObj, HKEY hkeyProgId)
{
...
IShellItemArray *items; // <-- pointer
HRESULT hr = SHCreateShellItemArrayFromDataObject(pdtObj, IID_IShellItemArray, (void**)&items); // <-- type cast
...
}

What argument should DllGetClassObject to the constructor of it's Shell Extension Handler?

Sorry if that question did not make a lot of sense. I am trying to make a Hello World Shell Extension Handler. I have been following this tutorial.
It says Shell Extension Handlers must implement IUnknown interface and a class factory which I have done.
class TestInterfaceImplementation : public IUnknown, public IClassFactory
ULONG STDMETHODCALLTYPE AddRef()
RESULT STDMETHODCALLTYPE QueryInterface(IN REFIID riid, OUT void **ppvObject)
ULONG STDMETHODCALLTYPE Release()
HRESULT STDMETHODCALLTYPE CreateInstance(IN IUnknown *pUnkOuter, IN REFIID riid, OUT void **ppvObject)
HRESULT STDMETHODCALLTYPE LockServer(IN BOOL fLock)
But that's all it says. When I go to implement DllGetClassObject it says I am providing the wrong argument to the constructor of my Shell Extension.
HRESULT __stdcall DllGetClassObject(IN REFCLSID rclsid, IN REFIID riid, OUT LPVOID *ppv) {
TestInterfaceImplementation *tii = new TestInterfaceImplementation(rclsid);
}
The exact error is:
error C2664: 'TestInterfaceImplementation::TestInterfaceImplementation(const TestInterfaceImplementation &)' : cannot convert parameter 1 from 'const IID' to 'const TestInterfaceImplementation &'
But nowhere in the tutorial (first link I posted) does it say you have to (or how to) override the constructor so I am lost.
Here is my complete code up until this point.
Your class seems to be missing the constructor your're implicitly using. Anyway, you're heading for a long trip. Shell extensions are COM objects, so you need to understand COM, and they also can be hard to write. One good way to write COM is to use the ATL library provided by Microsoft with Visual Studio.
I suggest you read some good tutorials and articles on all this:
The Complete Idiot's Guide to Writing Shell Extensions - Part I
How to write a shell extension in C++?

Allocator for [unique] pointers

I'm slightly puzzled by the lack of documentation on the issue, so I may be completely off track here:
When I allocate memory in order to return an object through an unique pointer whose value I have modified, what allocater should I use?
The documentation says that I can provide MIDL_user_allocate() and MIDL_user_free() and the stub will use these -- however that does not make sense in CLSCTX_INPROC_SERVER, as the calling object would need to use (and hence resolve) my allocater.
So, how should I allocate memory here, so that the stub code can properly free the list if the DLL is loaded into SVCHOST, and applications can still use the DLL directly if they so desire.
idl:
HRESULT GetItems([out] DWORD *count, [out, size_is(,count)] ITEM **items);
cpp:
HRESULT STDMETHODCALLTYPE impl::GetBuffer(DWORD *count, ITEM **items)
{
*count = 0;
*items = reinterpret_cast<ITEM *>(/* ??? */);
if(!*items)
return E_OUTOFMEMORY;
*count = 5;
/* fill in items */
return S_OK;
}
From here:
Out-parameters must be allocated by the one called; they are freed by the caller using the standard COM task memory allocator.
where COM task memory allocator is either the set of IMalloc methods or the set of CoTaskMemAlloc()/CoTaskMemRealloc()/CoTaskMemFree() functions that provide the same functionality.
The midl_user-*() functions you mention are used for RPC memory management. You need them in case you deal with RPC interfaces, not COM interfaces.

IDebugSymbols::GetNameByOffset and overloaded functions

I'm using IDebugSymbols::GetNameByOffset and I'm finding that I get the same symbol name for different functions that overload the same name.
E.g. The code I'm looking up the symbols for might be as follows:
void SomeFunction(int) {..}
void SomeFunction(float) {..}
At runtime, when I have an address of an instruction from each of these functions I'd like to use GetNameByOffset and tell the two apart somehow. I've experimented with calling SetSymbolOptions toggling the SYMOPT_UNDNAME and SYMOPT_NO_CPP flags as documented here, but this didn't work.
Does anyone know how to tell these to symbols apart in the debugger engine universe?
Edit: Please see me comment on the accepted answer for a minor amendment to the proposed solution.
Quote from dbgeng.h:
// A symbol name may not be unique, particularly
// when overloaded functions exist which all
// have the same name. If GetOffsetByName
// finds multiple matches for the name it
// can return any one of them. In that
// case it will return S_FALSE to indicate
// that ambiguity was arbitrarily resolved.
// A caller can then use SearchSymbols to
// find all of the matches if it wishes to
// perform different disambiguation.
STDMETHOD(GetOffsetByName)(
THIS_
__in PCSTR Symbol,
__out PULONG64 Offset
) PURE;
So, I would get the name with IDebugSymbols::GetNameByOffset() (it comes back like "module!name" I believe), make sure it is an overload (if you're not sure) using IDebugSymbols::GetOffsetByName() (which is supposed to return S_FALSE for multiple overloads), and look up all possibilities with this name using StartSymbolMatch()/EndSymbolMatch(). Not a one liner though (and not really helpful for that matter...)
Another option would be to go with
HRESULT
IDebugSymbols3::GetFunctionEntryByOffset(
IN ULONG64 Offset,
IN ULONG Flags,
OUT OPTIONAL PVOID Buffer,
IN ULONG BufferSize,
OUT OPTIONAL PULONG BufferNeeded
);
// It can be used to retrieve FPO data on a particular function:
FPO_DATA fpo;
HRESULT hres=m_Symbols3->GetFunctionEntryByOffset(
addr, // Offset
0, // Flags
&fpo, // Buffer
sizeof(fpo), // BufferSize
0 // BufferNeeded
));
and then use fpo.cdwParams for basic parameter size discrimination (cdwParams=size of parameters)

Resources