{"id":4813,"date":"2013-03-29T07:00:00","date_gmt":"2013-03-29T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/03\/29\/how-do-i-convert-a-method-name-to-a-method-index-for-the-purpose-of-interfaceinfo\/"},"modified":"2013-03-29T07:00:00","modified_gmt":"2013-03-29T07:00:00","slug":"how-do-i-convert-a-method-name-to-a-method-index-for-the-purpose-of-interfaceinfo","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130329-00\/?p=4813","title":{"rendered":"How do I convert a method name to a method index for the purpose of INTERFACEINFO?"},"content":{"rendered":"<p><P>\nThe\n<CODE>IMessage&shy;Filter::Handle&shy;Incoming&shy;Call<\/CODE>\nmethod describes the incoming call by means of an\n<CODE>INTERFACE&shy;INFO<\/CODE> structure:\n<\/P>\n<BLOCKQUOTE CLASS=\"q\">\n<PRE>\ntypedef struct tagINTERFACEINFO { \n  LPUNKNOWN pUnk; \n  IID iid; \n  WORD wMethod; \n} INTERFACEINFO, *LPINTERFACEINFO;\n<\/PRE>\n<\/BLOCKQUOTE>\n<P>\nThe <CODE>wMethod<\/CODE> is a zero-based index of the method\nwithin the interface.\nFor example,\n<CODE>IUnknown::Query&shy;Interface<\/CODE>\nhas index zero,\n<CODE>IUnknown::Add&shy;Ref<\/CODE>\nhas index one,\nand\n<CODE>IUnknown::Release<\/CODE>\nhas index two.\n<\/P>\n<P>\nIf you want to filter on a method in an interface,\nyou need to know its index.\nOne way of doing this would be to sit and count the methods,\nbut this is error-prone,\nespecially if the interface is still under active\ndevelopment and is not yet set in stone.\n<\/P>\n<P>\nC to the rescue.\n<\/P>\n<P>\nThe IDL compiler spits out a C-compatible structure for the\nvirtual function table,\nand you can use that structure to derive the method indices.\nFor example:\n<\/P>\n<PRE>\n#if defined(__cplusplus) &amp;&amp; !defined(CINTERFACE)\n    &#8230;\n#else   \/* C style interface *\/\n    typedef struct IPersistStreamVtbl\n    {\n        BEGIN_INTERFACE<\/p>\n<p>        HRESULT ( STDMETHODCALLTYPE *QueryInterface )(\n            __RPC__in IPersistStream * This,\n            \/* [in] *\/ __RPC__in REFIID riid,\n            \/* [annotation][iid_is][out] *\/\n            _COM_Outptr_  void **ppvObject);<\/p>\n<p>        ULONG ( STDMETHODCALLTYPE *AddRef )(\n            __RPC__in IPersistStream * This);<\/p>\n<p>        ULONG ( STDMETHODCALLTYPE *Release )(\n            __RPC__in IPersistStream * This);<\/p>\n<p>        HRESULT ( STDMETHODCALLTYPE *GetClassID )(\n            __RPC__in IPersistStream * This,\n            \/* [out] *\/ __RPC__out CLSID *pClassID);<\/p>\n<p>        HRESULT ( STDMETHODCALLTYPE *IsDirty )(\n            __RPC__in IPersistStream * This);<\/p>\n<p>        HRESULT ( STDMETHODCALLTYPE *Load )(\n            __RPC__in IPersistStream * This,\n            \/* [unique][in] *\/ __RPC__in_opt IStream *pStm);<\/p>\n<p>        HRESULT ( STDMETHODCALLTYPE *Save )(\n            __RPC__in IPersistStream * This,\n            \/* [unique][in] *\/ __RPC__in_opt IStream *pStm,\n            \/* [in] *\/ BOOL fClearDirty);<\/p>\n<p>        HRESULT ( STDMETHODCALLTYPE *GetSizeMax )(\n            __RPC__in IPersistStream * This,\n            \/* [out] *\/ __RPC__out ULARGE_INTEGER *pcbSize);<\/p>\n<p>        END_INTERFACE\n    } IPersistStreamVtbl;\n    &#8230;\n#endif  \/* C style interface *\/\n<\/PRE>\n<P>\n(You get roughly the same thing if you\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/10\/05\/238050.aspx\">\nuse the\n<CODE>DECLARE_INTERFACE<\/CODE> macros<\/A>.)\n<\/P>\n<P>\nAfter we remove the distractions, the structure is just\n<\/P>\n<PRE>\n    typedef struct IPersistStreamVtbl\n    {\n        BEGIN_INTERFACE\n        HRESULT (*QueryInterface)(&#8230;);\n        ULONG (*AddRef)(&#8230;);\n        ULONG (*Release)(&#8230;);\n        HRESULT (*GetClassID)(&#8230;);\n        HRESULT (*IsDirty)(&#8230;);\n        HRESULT (*Load)(&#8230;);\n        HRESULT (*Save)(&#8230;);\n        HRESULT (*GetSizeMax)(&#8230;);\n        END_INTERFACE\n    } IPersistStreamVtbl;\n<\/PRE>\n<P>\nFrom this, we can write a macro which extracts the method index:\n<\/P>\n<PRE>\n\/\/ If your compiler supports offsetof, then you can use that\n\/\/ instead of FIELD_OFFSET.\n#define METHOD_OFFSET(itf, method) FIELD_OFFSET(itf##Vtbl, method)<\/p>\n<p>#define METHOD_INDEX(itf, method) \\\n    ((METHOD_OFFSET(itf, method) &#8211; \\\n      METHOD_OFFSET(itf, QueryInterface)) \/ sizeof(FARPROC))\n<\/PRE>\n<P>\nThe macro works by looking at the position of the method in the\nvtable and calculating its index relative to\n<CODE>Query&shy;Interface<\/CODE>,\nwhich we know has index zero\nfor all <CODE>IUnknown<\/CODE>-derived COM interfaces.\n<\/P>\n<P>\nThese macros assume\nthat the size of a pointer-to-function\nis the same regardless of the prototype,\nbut this assumption is safe to make because it is required by the COM ABI.\n<\/P>\n<P>\nObserve that in order to get the C-style interfaces,\nyou must define the <CODE>CINTERFACE<\/CODE> macro before\nincluding the header file.\n(And observe that the C-style interfaces are not available\nin C++;\nyou must do this in C.)\n<\/P>\n<P>\nIf the bulk of your program is in C++,\nyou can slip in a single C file to extract the method indices\nand expose them to the C++ side either through global variables\nor short functions.\nDepending on how fancy your link-time code generator is,\nthe global variable or function call might even become eliminated.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The IMessage&shy;Filter::Handle&shy;Incoming&shy;Call method describes the incoming call by means of an INTERFACE&shy;INFO structure: typedef struct tagINTERFACEINFO { LPUNKNOWN pUnk; IID iid; WORD wMethod; } INTERFACEINFO, *LPINTERFACEINFO; The wMethod is a zero-based index of the method within the interface. For example, IUnknown::Query&shy;Interface has index zero, IUnknown::Add&shy;Ref has index one, and IUnknown::Release has index two. If you [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-4813","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The IMessage&shy;Filter::Handle&shy;Incoming&shy;Call method describes the incoming call by means of an INTERFACE&shy;INFO structure: typedef struct tagINTERFACEINFO { LPUNKNOWN pUnk; IID iid; WORD wMethod; } INTERFACEINFO, *LPINTERFACEINFO; The wMethod is a zero-based index of the method within the interface. For example, IUnknown::Query&shy;Interface has index zero, IUnknown::Add&shy;Ref has index one, and IUnknown::Release has index two. If you [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4813","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=4813"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4813\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=4813"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=4813"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=4813"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}