title: COM interface modifications have suddenly started causing exceptions
body: <p>A couple of years ago I inherited a C# app that uses COM objects defined in an unmanaged C++ DLL.  I've been successfully tweaking the object interfaces ever since, but following a (possibly irrelevant) VS2012 upgrade, function signature additions and changes are suddenly being punished by random exceptions such as ExecutionEngineException and SEHException.</p>
  
  <p>My understanding was that the app uses registration-free COM.  There's no DLLRegisterServer implementation, and I see no mention of the interface guids in the registry, just one in C#...</p>
  
  <pre><code>[ComImport,
  Guid("C2427CB1-D6AE-49e8-B266-114F981C3353"),
  InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
  SuppressUnmanagedCodeSecurity()]
  public interface IDC
  {
  </code></pre>
  
  <p>and one in a C++ header.</p>
  
  <pre><code>interface __declspec(uuid("C2427CB1-D6AE-49e8-B266-114F981C3353"))
  IDC : IUnknown
  {
  </code></pre>
  
  <p>To be sure though, I decided to swap a new guid into these two places, and discovered that it stopped C# from recognizing the class at all:</p>
  
  <pre><code>System.InvalidCastException
  
  Unable to cast COM object of type 'System.__ComObject' to interface type 'Apx.IDC'.
  This operation failed because the QueryInterface call on the COM component for the
  interface with IID '{the new guid}' failed due to the following error:
  No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
  </code></pre>
  
  <p>(The above error is apparently often caused by mixing appartment states, but swapping a guid doesn't cause that).  So I deduce there must be additional relevant detail <em>somewhere</em> that's conflicting with my changes.  But where might that somewhere be?  Thanks for reading...</p>
  
  <p>Edit:</p>
  
  <p>An example exception is...</p>
  
  <pre><code>First-chance exception at 0x000007feec748be4 (clr.dll) in Apex.exe: 0xC0000005:
  Access violation reading location 0xffffffffffffffff.
  The Common Language Runtime cannot stop at this exception. Common causes include:
  incorrect COM interop marshalling, and memory corruption. To investigate further,
  using native-only debugging.
  
  An unhandled exception of type 'System.ExecutionEngineException' occurred in Apex.exe
  </code></pre>
  
  <p>for</p>
  
  <pre><code>[PreserveSig] [return: MarshalAs(UnmanagedType.I1)]
  bool LoadDisplayList(IntPtr fileHandle, IntPtr pDisplayList,
  UInt16 version, IntPtr pComparison);
  </code></pre>
  
  <p>and</p>
  
  <pre><code>virtual bool __stdcall LoadDisplayList(HANDLE fileHandle, class CDisplayList * pDisplayList,
  WORD version, CDisplayList * pComparison) = 0;
  </code></pre>
  
  <p>with a stack trace ending</p>
  
  <pre><code>[Native to Managed Transition]  
  Apex.Graphics64.dll!CDisplayList::LoadRenderRecs(void * f=0x000000000000056c, CDisplayList * pComparison=0x0000000023ad2cf0)  Line 1772 C++
  Apex.Graphics64.dll!CDisplayList::Load(void * f=0x000000000000056c, unsigned short version=0x0002, CDisplayList * pComparison=0x0000000023ad2cf0)  Line 1845 + 0x26 bytes   C++
  Apex.Graphics64.dll!CBaseDC::LoadDisplayList(void * f=0x000000000000056c, CDisplayList * pList=0x0000000023ad2cf0, unsigned short version=0x0002, CDisplayList * pComparison=0x0000000023ad2cf0)  Line 1896 + 0x33 bytes    C++
  [Managed to Native Transition]  
  Apex.exe!Apex.DDC.LoadDisplayList(System.IO.FileStream file = {System.IO.FileStream}, Apex.DisplayList displayList = {Apex.DisplayList}, ushort version = 0x0002, Apex.DisplayList comparison = null) Line 1124 + 0xaf bytes    C#
  Apex.exe!Apex.DisplayList.Load(System.IO.FileStream f = {System.IO.FileStream}, ushort loadVersion = 0x0002, Apex.INode stubsRoot = {Apex.ViewPort3D}, Apex.DisplayList comparison = null) Line 166 + 0x53 bytes    C#
  </code></pre>
  
  <p>The exact crash point varies somewhat - here it actually managed to get inside LoadDisplayList(), which is better than usual.  As the crash suggests heap damage, I've tried stripping the function's signature down to a parameterless void return, reduced its contents to a trace, and called it right after the object's creation - still to get a crash.  The same function doesn't crash if I move it to the top of the definitions, in which case some other interface function crashes out instead, leading me to think it's more likely to be a COM problem than algorithm-level memory corruption.</p>