Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

COM interface modifications have suddenly started causing exceptions

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.

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#...

[ComImport,
Guid("C2427CB1-D6AE-49e8-B266-114F981C3353"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
SuppressUnmanagedCodeSecurity()]
public interface IDC
{

and one in a C++ header.

interface __declspec(uuid("C2427CB1-D6AE-49e8-B266-114F981C3353"))
IDC : IUnknown
{

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:

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)).

(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 somewhere that's conflicting with my changes. But where might that somewhere be? Thanks for reading...

Edit:

An example exception is...

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

for

[PreserveSig] [return: MarshalAs(UnmanagedType.I1)]
bool LoadDisplayList(IntPtr fileHandle, IntPtr pDisplayList,
UInt16 version, IntPtr pComparison);

and

virtual bool __stdcall LoadDisplayList(HANDLE fileHandle, class CDisplayList * pDisplayList,
WORD version, CDisplayList * pComparison) = 0;

with a stack trace ending

[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#

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.

like image 555
tombola Avatar asked Jun 01 '26 08:06

tombola


1 Answers

I think I've fixed the problem. Once I was able to step into the DLL a little, a popup saying that the source didn't match the executable led me to investigate another longstanding but previously unproblematic quirk, that the DLL's Linker / General / Output File wasn't inside the project's General / Output Directory (warning MSB8012). After cleaning up this anomaly I was able change the guid successfully, so it seems VS2012 uses these settings slightly differently to older versions. The moral...don't let warnings hang around.

like image 197
tombola Avatar answered Jun 03 '26 20:06

tombola



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!