/// <summary> /// Inits the vTable method from GUID. This is a tricky part of this class. /// </summary> /// <param name="asioGuid">The ASIO GUID.</param> private void InitFromGuid(Guid asioGuid) { const uint CLSCTX_INPROC_SERVER = 1; // Start to query the virtual table a index 3 (init method of AsioDriver) const int INDEX_VTABLE_FIRST_METHOD = 3; // Pointer to the ASIO object // USE CoCreateInstance instead of builtin COM-Class instantiation, // because the AsioDriver expect to have the ASIOGuid used for both COM Object and COM interface // The CoCreateInstance is working only in STAThread mode. int hresult = CoCreateInstance(ref asioGuid, IntPtr.Zero, CLSCTX_INPROC_SERVER, ref asioGuid, out pAsioComObject); if (hresult != 0) { throw new COMException("Unable to instantiate ASIO. Check if STAThread is set", hresult); } // The first pointer at the adress of the ASIO Com Object is a pointer to the // C++ Virtual table of the object. // Gets a pointer to VTable. IntPtr pVtable = Marshal.ReadIntPtr(pAsioComObject); // Instantiate our Virtual table mapping asioDriverVTable = new AsioDriverVTable(); // This loop is going to retrieve the pointer from the C++ VirtualTable // and attach an internal delegate in order to call the method on the COM Object. FieldInfo[] fieldInfos = typeof(AsioDriverVTable).GetFields(); for (int i = 0; i < fieldInfos.Length; i++) { FieldInfo fieldInfo = fieldInfos[i]; // Read the method pointer from the VTable IntPtr pPointerToMethodInVTable = Marshal.ReadIntPtr(pVtable, (i + INDEX_VTABLE_FIRST_METHOD) * IntPtr.Size); // Instantiate a delegate object methodDelegate = Marshal.GetDelegateForFunctionPointer(pPointerToMethodInVTable, fieldInfo.FieldType); // Store the delegate in our C# VTable fieldInfo.SetValue(asioDriverVTable, methodDelegate); } }