The traditional way to determine the function pointed to by [edi+1Ch]
is as follows:
Find the Interface Definition Language (IDL) file for the given interface. In your case, the interface is IShellWindows
. According to the documentation for IShellWindows
, its interface is defined in IDL file Exdisp.idl
. That IDL file is included in the Windows SDK (downloadable for free), and will be installed to a location such as C:\Program Files\Microsoft SDKs\Windows\v7.1A\Include\Exdisp.idl
. You can open that Exdisp.idl
file with a text editor to see the Interface Definition of IShellWindows
:
[
uuid(85CB6900-4D95-11CF-960C-0080C7F4EE85), // IID_IShellWindows
helpstring("Definition of interface IShellWindows"),
oleautomation,
dual,
odl,
]
interface IShellWindows : IDispatch
{
//Properties
[propget, helpstring("Get count of open Shell windows")]
HRESULT Count([out, retval] long *Count);
//Methods
[id(0), helpstring("Return the shell window for the given index")]
HRESULT Item([in,optional] VARIANT index, [out, retval]IDispatch **Folder);
[id(-4), helpstring("Enumerates the figures")]
HRESULT _NewEnum([out, retval] IUnknown **ppunk);
// Some private hidden members to allow shell windows to add and
// remove themself from the list. We mark them hidden to keep
// random VB apps from trying to Register...
[helpstring("Register a window with the list"), hidden]
HRESULT Register([in] IDispatch *pid,
[in] long hwnd,
[in] int swClass,
[out]long *plCookie);
[helpstring("Register a pending open with the list"), hidden]
HRESULT RegisterPending([in] long lThreadId,
[in] VARIANT* pvarloc, // will hold pidl that is being opened.
[in] VARIANT* pvarlocRoot, // Optional root pidl
[in] int swClass,
[out]long *plCookie);
[helpstring("Remove a window from the list"), hidden]
HRESULT Revoke([in]long lCookie);
// As an optimization, each window notifies the new location
// only when
// (1) it's being deactivated
// (2) getFullName is called (we overload it to force update)
[helpstring("Notifies the new location"), hidden]
HRESULT OnNavigate([in]long lCookie, [in] VARIANT* pvarLoc);
[helpstring("Notifies the activation"), hidden]
HRESULT OnActivated([in]long lCookie, [in] VARIANT_BOOL fActive);
[helpstring("Find the window based on the location"), hidden]
HRESULT FindWindowSW([in] VARIANT* pvarLoc,
[in] VARIANT* pvarLocRoot, /* unused */
[in] int swClass,
[out] long * phwnd,
[in] int swfwOptions,
[out,retval] IDispatch** ppdispOut);
[helpstring("Notifies on creation and frame name set"), hidden]
HRESULT OnCreated([in]long lCookie,[in] IUnknown *punk);
[helpstring("Used by IExplore to register different processes"), hidden]
HRESULT ProcessAttachDetach([in] VARIANT_BOOL fAttach);
}
We can see that the IShellWindows
interface has the following vtable entries:
- Count()
- Item()
- _NewEnum()
- Register()
- RegisterPending()
- Revoke()
- OnNavigate()
- OnActivated()
- FindWindowSW()
- OnCreated()
- ProcessAttachDetach()
However, you can also see in the IDL that the IShellWindows
interface inherits from IDispatch
. IDispatch
has the following vtable entries (from OAIdl.idl
):
- GetTypeInfoCount()
- GetTypeInfo()
- GetIDsOfNames()
- Invoke()
The IDL for IDispatch
in OAIdl.idl
also specifies that IDispatch
inherits from IUnknown
. IUnknown
has the following vtable entries (from Unknwn.idl
):
- QueryInterface()
- AddRef()
- Release()
So now we know that IShellWindows
inherits from IDispatch
, which inherits from IUnknown
. As such, the full layout of the vtable for IShellWindows
is as follows:
*ppv+00h = QueryInterface()
*ppv+04h = AddRef()
*ppv+08h = Release()
*ppv+0Ch = GetTypeInfoCount()
*ppv+10h = GetTypeInfo()
*ppv+14h = GetIDsOfNames()
*ppv+18h = Invoke()
*ppv+1Ch = Count()
*ppv+20h = Item()
*ppv+24h = _NewEnum()
*ppv+28h = Register()
...
Looking back at your code, we see a call to *ppv+1Ch
, which we see from our constructed vtable above is a call to the function IShellWindows::Count()
, and &var_C
is the pointer to IShellWindows::Count()
's [out, retval] long *Count
parameter.
The dynamic way to determine the function pointed to by [edi+1Ch]
is as follows:
Run your code above in a debugger, set a breakpoint on call dword ptr [edi+1Ch]
, and see what function that instruction calls.
The easiest way to determine the function pointed to by [edi+1Ch]
is as follows:
Use COMView (wayback machine link to COMView) to inspect the IShellWindows
interface:
You can see in the screenshot above that the function at vtable offset 28 (1Ch) is Count()
.