Add support for ISOSDacInterface15 - MethodTable enumeration api (#4767)
authorDavid Wrighton <davidwr@microsoft.com>
Wed, 17 Jul 2024 17:27:40 +0000 (10:27 -0700)
committerGitHub <noreply@github.com>
Wed, 17 Jul 2024 17:27:40 +0000 (10:27 -0700)
- Support iterating methods from the new ISOSDacInterface15
- Re-plumb the existing logic as a local implementation of
ISOSDacInterface15 on top of apis that have been present for a long time

This is dependent on https://github.com/dotnet/runtime/pull/101580

src/SOS/Strike/strike.cpp
src/SOS/Strike/util.cpp
src/SOS/Strike/util.h
src/shared/inc/sospriv.idl
src/shared/pal/prebuilt/idl/sospriv_i.cpp
src/shared/pal/prebuilt/inc/sospriv.h

index a27c3d57de162e06bd317f2b5c35bdeee47163e9..9cc7c472f003bbf493987aeb77526af73ef7c0f4 100644 (file)
@@ -1239,72 +1239,94 @@ DECLARE_API(DumpMT)
 
     if (bDumpMDTable)
     {
-        table.ReInit(4, POINTERSIZE_HEX, AlignRight);
+        table.ReInit(5, POINTERSIZE_HEX, AlignRight);
         table.SetColAlignment(3, AlignLeft);
         table.SetColWidth(2, 6);
 
         Print("--------------------------------------\n");
         Print("MethodDesc Table\n");
 
-        table.WriteRow("Entry", "MethodDesc", "JIT", "Name");
+        table.WriteRow("Entry", "MethodDesc", "JIT", "Slot", "Name");
 
-        for (DWORD n = 0; n < vMethTable.wNumMethods; n++)
+        ISOSMethodEnum *pMethodEnumerator;
+        if (SUCCEEDED(g_sos15->GetMethodTableSlotEnumerator(dwStartAddr, &pMethodEnumerator)))
         {
-            JITTypes jitType;
-            DWORD_PTR methodDesc=0;
-            DWORD_PTR gcinfoAddr;
-
-            CLRDATA_ADDRESS entry;
-            if (g_sos->GetMethodTableSlot(dwStartAddr, n, &entry) != S_OK)
+            SOSMethodData entry;
+            unsigned int fetched;
+            while (SUCCEEDED(pMethodEnumerator->Next(1, &entry, &fetched)) && fetched != 0)
             {
-                PrintLn("<error getting slot ", Decimal(n), ">");
-                continue;
-            }
+                JITTypes jitType = TYPE_UNKNOWN;
+                DWORD_PTR methodDesc = (DWORD_PTR)entry.MethodDesc;
+                DWORD_PTR methodDescFromIP2MD = 0;
+                DWORD_PTR gcinfoAddr = 0;
+
+                if (entry.Entrypoint != 0)
+                {
+                    IP2MethodDesc((DWORD_PTR)entry.Entrypoint, methodDescFromIP2MD, jitType, gcinfoAddr);
+                    if ((methodDescFromIP2MD != methodDesc) && methodDesc != 0)
+                    {
+                        ExtOut("MethodDesc from IP2MD does not match MethodDesc from enumerator\n");
+                    }
+                }
 
-            IP2MethodDesc((DWORD_PTR)entry, methodDesc, jitType, gcinfoAddr);
-            table.WriteColumn(0, entry);
-            table.WriteColumn(1, MethodDescPtr(methodDesc));
+                table.WriteColumn(0, entry.Entrypoint);
+                table.WriteColumn(1, MethodDescPtr(methodDesc));
 
-            if (jitType == TYPE_UNKNOWN && methodDesc != (TADDR)0)
-            {
-                // We can get a more accurate jitType from NativeCodeAddr of the methoddesc,
-                // because the methodtable entry hasn't always been patched.
-                DacpMethodDescData tmpMethodDescData;
-                if (tmpMethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK)
+                if (jitType == TYPE_UNKNOWN && methodDesc != (TADDR)0)
                 {
-                    DacpCodeHeaderData codeHeaderData;
-                    if (codeHeaderData.Request(g_sos,tmpMethodDescData.NativeCodeAddr) == S_OK)
+                    // We can get a more accurate jitType from NativeCodeAddr of the methoddesc,
+                    // because the methodtable entry hasn't always been patched.
+                    DacpMethodDescData tmpMethodDescData;
+                    if (tmpMethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK)
                     {
-                        jitType = (JITTypes) codeHeaderData.JITType;
+                        DacpCodeHeaderData codeHeaderData;
+                        if (codeHeaderData.Request(g_sos,tmpMethodDescData.NativeCodeAddr) == S_OK)
+                        {
+                            jitType = (JITTypes) codeHeaderData.JITType;
+                        }
                     }
                 }
-            }
 
-            const char *pszJitType = "NONE";
-            if (jitType == TYPE_JIT)
-                pszJitType = "JIT";
-            else if (jitType == TYPE_PJIT)
-                pszJitType = "PreJIT";
-            else
-            {
-                DacpMethodDescData MethodDescData;
-                if (MethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK)
+                const char *pszJitType = "NONE";
+                if (jitType == TYPE_JIT)
+                    pszJitType = "JIT";
+                else if (jitType == TYPE_PJIT)
+                    pszJitType = "PreJIT";
+                else
                 {
-                    // Is it an fcall?
-                    ULONG64 baseAddress = g_pRuntime->GetModuleAddress();
-                    ULONG64 size = g_pRuntime->GetModuleSize();
-                    if ((TO_TADDR(MethodDescData.NativeCodeAddr) >=  TO_TADDR(baseAddress)) &&
-                        ((TO_TADDR(MethodDescData.NativeCodeAddr) <  TO_TADDR(baseAddress + size))))
+                    DacpMethodDescData MethodDescData;
+                    if (MethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK)
                     {
-                        pszJitType = "FCALL";
+                        // Is it an fcall?
+                        ULONG64 baseAddress = g_pRuntime->GetModuleAddress();
+                        ULONG64 size = g_pRuntime->GetModuleSize();
+                        if ((TO_TADDR(MethodDescData.NativeCodeAddr) >=  TO_TADDR(baseAddress)) &&
+                            ((TO_TADDR(MethodDescData.NativeCodeAddr) <  TO_TADDR(baseAddress + size))))
+                        {
+                            pszJitType = "FCALL";
+                        }
                     }
                 }
-            }
 
-            table.WriteColumn(2, pszJitType);
+                table.WriteColumn(2, pszJitType);
+                table.WriteColumn(3, entry.Slot);
 
-            NameForMD_s(methodDesc,g_mdName,mdNameLen);
-            table.WriteColumn(3, g_mdName);
+                if (methodDesc != 0)
+                    NameForMD_s(methodDesc,g_mdName,mdNameLen);
+                else
+                {
+                    DacpModuleData moduleData;
+                    if(moduleData.Request(g_sos, entry.DefiningModule)==S_OK)
+                    {
+                        NameForToken_s(&moduleData, entry.Token, g_mdName, mdNameLen, true);
+                    }
+                    else
+                    {
+                        _snwprintf_s(g_mdName, mdNameLen, _TRUNCATE, W("Unknown Module!%08x"), entry.Token);
+                    }
+                }
+                table.WriteColumn(4, g_mdName);
+            }
         }
     }
     return Status;
index 606451115a7d0a28b2d0d9b5bb6307079fd36638..c80a47079b6c54806ce0151b616e21fad713532a 100644 (file)
@@ -59,6 +59,7 @@ const char * const CorElementTypeNamespace[ELEMENT_TYPE_MAX]=
 
 IXCLRDataProcess *g_clrData = NULL;
 ISOSDacInterface *g_sos = NULL;
+ISOSDacInterface15 *g_sos15 = NULL;
 
 #ifndef IfFailRet
 #define IfFailRet(EXPR) do { Status = (EXPR); if(FAILED(Status)) { return (Status); } } while (0)
@@ -3930,6 +3931,154 @@ void ResetGlobals(void)
     Output::ResetIndent();
 }
 
+class SOSDacInterface15Simulator : public ISOSDacInterface15
+{
+    class SOSMethodEnum : public ISOSMethodEnum
+    {
+        CLRDATA_ADDRESS pMT;
+        unsigned int index;
+        unsigned int slotCount;
+        ULONG refCount;
+    public:
+        SOSMethodEnum(CLRDATA_ADDRESS mt) : pMT(mt), refCount(1)
+        {
+        }
+
+        virtual ~SOSMethodEnum() {}
+
+        virtual HRESULT STDMETHODCALLTYPE Reset()
+        {
+            index = 0;
+            DacpMethodTableData vMethTable;
+            HRESULT hr = vMethTable.Request(g_sos, pMT);
+            if (FAILED(hr))
+                return hr;
+
+            slotCount = vMethTable.wNumMethods;
+            return S_OK;
+        }
+
+        virtual HRESULT STDMETHODCALLTYPE GetCount(unsigned int *pc)
+        {
+            *pc = slotCount;
+            return S_OK;
+        }
+
+        virtual HRESULT STDMETHODCALLTYPE Skip(unsigned int skipCount)
+        {
+            index += skipCount;
+            return S_OK;
+        }
+
+        virtual HRESULT STDMETHODCALLTYPE Next( 
+            /* [in] */ unsigned int count,
+            /* [length_is][size_is][out] */ SOSMethodData methods[  ],
+            /* [out] */ unsigned int *pFetched)
+        {
+            if (!pFetched)
+                return E_POINTER;
+
+            if (!methods)
+                return E_POINTER;
+
+            unsigned int i = 0;
+            while (i < count && index < slotCount)
+            {
+                SOSMethodData methodData = { 0 };
+
+                JITTypes jitType;
+                DWORD_PTR methodDesc=0;
+                DWORD_PTR gcinfoAddr;
+
+                CLRDATA_ADDRESS entry;
+                methodData.Slot = index;
+                HRESULT hr = g_sos->GetMethodTableSlot(pMT, index++, &entry);
+                if (hr != S_OK)
+                {
+                    PrintLn("<error getting slot ", Decimal(index - 1), ">");
+                    continue;
+                }
+
+                IP2MethodDesc((DWORD_PTR)entry, methodDesc, jitType, gcinfoAddr);
+
+                methodData.MethodDesc = methodDesc;
+                methodData.Entrypoint = entry;
+
+                methods[i++] = methodData;
+            }
+
+            *pFetched = i;
+            return i < count ? S_FALSE : S_OK;
+        }
+
+        STDMETHOD_(ULONG, AddRef)() { return ++refCount; }
+        STDMETHOD_(ULONG, Release)()
+        {
+            --refCount;
+            if (refCount == 0)
+            {
+                delete this;
+                return 0;
+            }
+            return refCount;
+        }
+
+        STDMETHOD(QueryInterface)(
+            THIS_
+            ___in REFIID InterfaceId,
+            ___out PVOID* Interface
+            )
+        {
+            if (InterfaceId == IID_IUnknown ||
+                InterfaceId == IID_ISOSMethodEnum)
+            {
+                *Interface = (ISOSMethodEnum*)this;
+                AddRef();
+                return S_OK;
+            }
+            *Interface = NULL;
+            return E_NOINTERFACE;
+        }
+    };
+
+public:
+    STDMETHOD_(ULONG, AddRef)() { return 1; };
+    STDMETHOD_(ULONG, Release)() { return 1; };
+    STDMETHOD(QueryInterface)(
+        THIS_
+        ___in REFIID InterfaceId,
+        ___out PVOID* Interface
+        )
+    {
+        if (InterfaceId == IID_IUnknown ||
+            InterfaceId == IID_ISOSDacInterface15)
+        {
+            *Interface = (ISOSDacInterface15*)this;
+            return S_OK;
+        }
+        *Interface = NULL;
+        return E_NOINTERFACE;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetMethodTableSlotEnumerator( 
+            CLRDATA_ADDRESS mt,
+            ISOSMethodEnum **enumerator)
+    {
+        SOSMethodEnum *simulator = new(std::nothrow) SOSMethodEnum(mt);
+        *enumerator = simulator;
+        if (simulator == NULL)
+        {
+            return E_OUTOFMEMORY;
+        }
+        HRESULT hr = simulator->Reset();
+        if (FAILED(hr))
+        {
+            simulator->Release();
+        }
+        return hr;
+    }
+} SOSDacInterface15Simulator_Instance;
+
 //---------------------------------------------------------------------------------------
 //
 // Loads private DAC interface, and points g_clrData to it.
@@ -3960,6 +4109,13 @@ HRESULT LoadClrDebugDll(void)
         g_sos = NULL;
         return hr;
     }
+
+    // Always have an instance of the MethodTable enumerator
+    hr = g_clrData->QueryInterface(__uuidof(ISOSDacInterface15), (void**)&g_sos15);
+    if (FAILED(hr))
+    {
+        g_sos15 = &SOSDacInterface15Simulator_Instance;
+    }
     return S_OK;
 }
 
index dad6bf9c4a20fb2314037a3b3b0b705fa1e6e8fe..3c2bfb8bb0df0893697d9b47fa450030a743232e 100644 (file)
@@ -150,6 +150,7 @@ enum EEFLAVOR {UNKNOWNEE, MSCOREE, MSCORWKS, MSCOREND};
 #include "sospriv.h"
 extern IXCLRDataProcess *g_clrData;
 extern ISOSDacInterface *g_sos;
+extern ISOSDacInterface15 *g_sos15;
 
 #include "dacprivate.h"
 
index 98cfa0afe9a5157decdf02b1408f695f0005f56e..141f597dcb4e942d4bfd77e72802d5a1e1f2d9d1 100644 (file)
@@ -519,3 +519,46 @@ interface ISOSDacInterface14 : IUnknown
     HRESULT GetThreadStaticBaseAddress(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS thread, CLRDATA_ADDRESS *nonGCStaticsAddress, CLRDATA_ADDRESS *GCStaticsAddress);
     HRESULT GetMethodTableInitializationFlags(CLRDATA_ADDRESS methodTable, MethodTableInitializationFlags *initializationStatus);
 }
+
+cpp_quote("#ifndef _SOS_MethodData")
+cpp_quote("#define _SOS_MethodData")
+
+typedef struct _SOSMethodData
+{
+    // At least one of MethodDesc, Entrypoint, or Token/DefiningMethodTable/DefiningModule is guaranteed to be set.
+    // Multiple of them may be set as well
+    CLRDATA_ADDRESS MethodDesc;
+
+    CLRDATA_ADDRESS Entrypoint;
+
+    CLRDATA_ADDRESS DefininingMethodTable; // Useful for when the method is inherited from a parent type which is instantiated
+    CLRDATA_ADDRESS DefiningModule;
+    unsigned int Token;
+
+    // Slot data, a given MethodDesc may be present in multiple slots for a single MethodTable
+    unsigned int Slot; // Will be set to 0xFFFFFFFF for EnC added methods
+} SOSMethodData;
+
+cpp_quote("#endif //_SOS_MethodData")
+
+[
+    object,
+    local,
+    uuid(3c0fe725-c324-4a4f-8100-d399588a662e)
+]
+interface ISOSMethodEnum : ISOSEnum
+{
+    HRESULT Next([in] unsigned int count,
+                 [out, size_is(count), length_is(*pNeeded)] SOSMethodData handles[],
+                 [out] unsigned int *pNeeded);
+}
+
+[
+    object,
+    local,
+    uuid(7ed81261-52a9-4a23-a358-c3313dea30a8)
+]
+interface ISOSDacInterface15 : IUnknown
+{
+    HRESULT GetMethodTableSlotEnumerator(CLRDATA_ADDRESS mt, ISOSMethodEnum **enumerator);
+}
index f070ae5816a8a8ca8fcd02011568cc773e720a31..579be51d356f7fb934a6e5f2f76641a3ff5cce21 100644 (file)
@@ -121,6 +121,12 @@ MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface13,0x3176a8ed,0x597b,0x4f54,0xa7,0x1f,
 
 MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface14,0x9aa22aca,0x6dc6,0x4a0c,0xb4,0xe0,0x70,0xd2,0x41,0x6b,0x98,0x37);
 
+
+MIDL_DEFINE_GUID(IID, IID_ISOSMethodEnum,0x3c0fe725,0xc324,0x4a4f,0x81,0x00,0xd3,0x99,0x58,0x8a,0x66,0x2e);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface15,0x7ed81261,0x52a9,0x4a23,0xa3,0x58,0xc3,0x31,0x3d,0xea,0x30,0xa8);
+
 #undef MIDL_DEFINE_GUID
 
 #ifdef __cplusplus
index 64db79c7921cc17d6e973f0bb9224d44b2aa1b9c..a3d741f740defa9a96a2451ff0f0e66952d234f3 100644 (file)
@@ -3333,6 +3333,27 @@ EXTERN_C const IID IID_ISOSDacInterface13;
 #define ISOSDacInterface13_TraverseLoaderHeap(This,loaderHeapAddr,kind,pCallback)      \
     ( (This)->lpVtbl -> TraverseLoaderHeap(This,loaderHeapAddr,kind,pCallback) )
 
+#define ISOSDacInterface13_GetDomainLoaderAllocator(This,domainAddress,pLoaderAllocator)       \
+    ( (This)->lpVtbl -> GetDomainLoaderAllocator(This,domainAddress,pLoaderAllocator) ) 
+
+#define ISOSDacInterface13_GetLoaderAllocatorHeapNames(This,count,ppNames,pNeeded)     \
+    ( (This)->lpVtbl -> GetLoaderAllocatorHeapNames(This,count,ppNames,pNeeded) ) 
+
+#define ISOSDacInterface13_GetLoaderAllocatorHeaps(This,loaderAllocator,count,pLoaderHeaps,pKinds,pNeeded)     \
+    ( (This)->lpVtbl -> GetLoaderAllocatorHeaps(This,loaderAllocator,count,pLoaderHeaps,pKinds,pNeeded) ) 
+
+#define ISOSDacInterface13_GetHandleTableMemoryRegions(This,ppEnum)    \
+    ( (This)->lpVtbl -> GetHandleTableMemoryRegions(This,ppEnum) ) 
+
+#define ISOSDacInterface13_GetGCBookkeepingMemoryRegions(This,ppEnum)  \
+    ( (This)->lpVtbl -> GetGCBookkeepingMemoryRegions(This,ppEnum) ) 
+
+#define ISOSDacInterface13_GetGCFreeRegions(This,ppEnum)       \
+    ( (This)->lpVtbl -> GetGCFreeRegions(This,ppEnum) ) 
+
+#define ISOSDacInterface13_LockedFlush(This)   \
+    ( (This)->lpVtbl -> LockedFlush(This) ) 
+
 #endif /* COBJMACROS */
 
 
@@ -3456,6 +3477,214 @@ EXTERN_C const IID IID_ISOSDacInterface14;
 #endif         /* __ISOSDacInterface14_INTERFACE_DEFINED__ */
 
 
+/* interface __MIDL_itf_sospriv_0000_0019 */
+/* [local] */ 
+
+#ifndef _SOS_MethodData
+#define _SOS_MethodData
+typedef struct _SOSMethodData
+    {
+    CLRDATA_ADDRESS MethodDesc;
+    CLRDATA_ADDRESS Entrypoint;
+    CLRDATA_ADDRESS DefininingMethodTable;
+    CLRDATA_ADDRESS DefiningModule;
+    unsigned int Token;
+    unsigned int Slot;
+    }  SOSMethodData;
+
+#endif //_SOS_MethodData
+
+
+extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0019_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0019_v0_0_s_ifspec;
+
+#ifndef __ISOSMethodEnum_INTERFACE_DEFINED__
+#define __ISOSMethodEnum_INTERFACE_DEFINED__
+
+/* interface ISOSMethodEnum */
+/* [uuid][local][object] */ 
+
+
+EXTERN_C const IID IID_ISOSMethodEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+    
+    MIDL_INTERFACE("3c0fe725-c324-4a4f-8100-d399588a662e")
+    ISOSMethodEnum : public ISOSEnum
+    {
+    public:
+        virtual HRESULT STDMETHODCALLTYPE Next( 
+            /* [in] */ unsigned int count,
+            /* [length_is][size_is][out] */ SOSMethodData handles[  ],
+            /* [out] */ unsigned int *pNeeded) = 0;
+        
+    };
+    
+    
+#else  /* C style interface */
+
+    typedef struct ISOSMethodEnumVtbl
+    {
+        BEGIN_INTERFACE
+        
+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
+            ISOSMethodEnum * This,
+            /* [in] */ REFIID riid,
+            /* [annotation][iid_is][out] */ 
+            _COM_Outptr_  void **ppvObject);
+        
+        ULONG ( STDMETHODCALLTYPE *AddRef )( 
+            ISOSMethodEnum * This);
+        
+        ULONG ( STDMETHODCALLTYPE *Release )( 
+            ISOSMethodEnum * This);
+        
+        HRESULT ( STDMETHODCALLTYPE *Skip )( 
+            ISOSMethodEnum * This,
+            /* [in] */ unsigned int count);
+        
+        HRESULT ( STDMETHODCALLTYPE *Reset )( 
+            ISOSMethodEnum * This);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetCount )( 
+            ISOSMethodEnum * This,
+            /* [out] */ unsigned int *pCount);
+        
+        HRESULT ( STDMETHODCALLTYPE *Next )( 
+            ISOSMethodEnum * This,
+            /* [in] */ unsigned int count,
+            /* [length_is][size_is][out] */ SOSMethodData handles[  ],
+            /* [out] */ unsigned int *pNeeded);
+        
+        END_INTERFACE
+    } ISOSMethodEnumVtbl;
+
+    interface ISOSMethodEnum
+    {
+        CONST_VTBL struct ISOSMethodEnumVtbl *lpVtbl;
+    };
+
+    
+
+#ifdef COBJMACROS
+
+
+#define ISOSMethodEnum_QueryInterface(This,riid,ppvObject)     \
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
+
+#define ISOSMethodEnum_AddRef(This)    \
+    ( (This)->lpVtbl -> AddRef(This) ) 
+
+#define ISOSMethodEnum_Release(This)   \
+    ( (This)->lpVtbl -> Release(This) ) 
+
+
+#define ISOSMethodEnum_Skip(This,count)        \
+    ( (This)->lpVtbl -> Skip(This,count) ) 
+
+#define ISOSMethodEnum_Reset(This)     \
+    ( (This)->lpVtbl -> Reset(This) ) 
+
+#define ISOSMethodEnum_GetCount(This,pCount)   \
+    ( (This)->lpVtbl -> GetCount(This,pCount) ) 
+
+
+#define ISOSMethodEnum_Next(This,count,handles,pNeeded)        \
+    ( (This)->lpVtbl -> Next(This,count,handles,pNeeded) ) 
+
+#endif /* COBJMACROS */
+
+
+#endif         /* C style interface */
+
+
+
+
+#endif         /* __ISOSMethodEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISOSDacInterface15_INTERFACE_DEFINED__
+#define __ISOSDacInterface15_INTERFACE_DEFINED__
+
+/* interface ISOSDacInterface15 */
+/* [uuid][local][object] */ 
+
+
+EXTERN_C const IID IID_ISOSDacInterface15;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+    
+    MIDL_INTERFACE("7ed81261-52a9-4a23-a358-c3313dea30a8")
+    ISOSDacInterface15 : public IUnknown
+    {
+    public:
+        virtual HRESULT STDMETHODCALLTYPE GetMethodTableSlotEnumerator( 
+            CLRDATA_ADDRESS mt,
+            ISOSMethodEnum **enumerator) = 0;
+        
+    };
+    
+    
+#else  /* C style interface */
+
+    typedef struct ISOSDacInterface15Vtbl
+    {
+        BEGIN_INTERFACE
+        
+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
+            ISOSDacInterface15 * This,
+            /* [in] */ REFIID riid,
+            /* [annotation][iid_is][out] */ 
+            _COM_Outptr_  void **ppvObject);
+        
+        ULONG ( STDMETHODCALLTYPE *AddRef )( 
+            ISOSDacInterface15 * This);
+        
+        ULONG ( STDMETHODCALLTYPE *Release )( 
+            ISOSDacInterface15 * This);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetMethodTableSlotEnumerator )( 
+            ISOSDacInterface15 * This,
+            CLRDATA_ADDRESS mt,
+            ISOSMethodEnum **enumerator);
+        
+        END_INTERFACE
+    } ISOSDacInterface15Vtbl;
+
+    interface ISOSDacInterface15
+    {
+        CONST_VTBL struct ISOSDacInterface15Vtbl *lpVtbl;
+    };
+
+    
+
+#ifdef COBJMACROS
+
+
+#define ISOSDacInterface15_QueryInterface(This,riid,ppvObject) \
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
+
+#define ISOSDacInterface15_AddRef(This)        \
+    ( (This)->lpVtbl -> AddRef(This) ) 
+
+#define ISOSDacInterface15_Release(This)       \
+    ( (This)->lpVtbl -> Release(This) ) 
+
+
+#define ISOSDacInterface15_GetMethodTableSlotEnumerator(This,mt,enumerator)    \
+    ( (This)->lpVtbl -> GetMethodTableSlotEnumerator(This,mt,enumerator) ) 
+
+#endif /* COBJMACROS */
+
+
+#endif         /* C style interface */
+
+
+
+
+#endif         /* __ISOSDacInterface15_INTERFACE_DEFINED__ */
+
+
 /* Additional Prototypes for ALL interfaces */
 
 /* end of Additional Prototypes */