COM interface modifications have suddenly started causing exceptions - c#

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.

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.

Related

.NET Activex control access violation in MFC application

Background: I developed an Activex control in .NET, but found it was causing stability issues in various applications that used it. I managed to find a series of steps, from sample applications, similar unstabilities outlined below.
I have a sample Activex control that I've downloaded from the Dev-Center website called 'CSActivex' (http://code.msdn.microsoft.com/windowsdesktop/CSActiveX-b86194f8)
It was fairly easy to build, I just loaded the project up in VS2010 Express (C#) and it compiled into a .dll
I then created a sample MFC application from VS2008 C++ to model a legacy applications (it does not use any .NET). The target is the simple dialog based GUI that has an About box.
I registered the csactivex.dll with regasm and just copied the dll to the VS IDE folder, so I can insert the Activex control at design time, and then to the Debug folder, so it can be found during runtime.
At design time, I insert the CSActivex control onto the About dialog box, it appears with no surprises. After building and copying the dll to the Debug folder and run a debug session, if I continually navigate to the about box, click in various places on the control, close the about dialog and repeat a few times, I start to see messages in the output log about access violations, and it starts to look like this:
'CSActivexMFC.exe': Loaded 'C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Windows.Forms\63406259e94d5c0ff5b79401dfe113ce\System.Windows.Forms.ni.dll'
'CSActivexMFC.exe': Loaded 'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorjit.dll'
'CSActivexMFC.exe': Loaded 'C:\WINDOWS\WinSxS\x86_Microsoft.Windows.GdiPlus_6595b64144ccf1df_1.0.2600.5581_x-ww_dfbc4fc4\GdiPlus.dll'
'CSActivexMFC.exe': Loaded 'C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\Accessibility\11eb4f6606ba01e5128805759121ea6c\Accessibility.ni.dll'
First-chance exception at 0x00000000 in CSActivexMFC.exe: 0xC0000005: Access violation reading location 0x00000000.
First-chance exception at 0x00000000 in CSActivexMFC.exe: 0xC0000005: Access violation reading location 0x00000000.
First-chance exception at 0x79f4c2f7 in CSActivexMFC.exe: 0xC0000005: Access violation reading location 0x0000000b.
First-chance exception at 0x79f4c2f7 in CSActivexMFC.exe: 0xC0000005: Access violation reading location 0x0000000b.
While it does not crash in the debugger, I can't help but think this in not good, and I have a feeling that it may be related to the instability of other .NET Activex controls. If I can figure out a way to solve this issue, the same resolution may help the original control.
I tried breaking on the exception, but it appears to happen in a few different places. one stack trace when I closed the applications is below:
mscorwks.dll!79f4c2f7() [Frames below may be incorrect and/or
missing, no symbols loaded for mscorwks.dll]
mscorwks.dll!79f4c370() mscorwks.dll!79faaa91()
mscorwks.dll!79faa858() mscorwks.dll!79faa9ad()
mscorwks.dll!79faa9d9() mscorwks.dll!7a079480()
mscorwks.dll!7a0798e8() mscorwks.dll!7a043f25()
ole32.dll!77525834() rpcrt4.dll!77e799f4()
rpcrt4.dll!77ef421a() ntdll.dll!7c915239()
ntdll.dll!7c91542b() ntdll.dll!7c91534a()
ntdll.dll!7c915239() ntdll.dll!7c91542b()
ntdll.dll!7c91534a() ntdll.dll!7c915f75()
ntdll.dll!7c9155ed() ntdll.dll!7c915ce9()
ntdll.dll!7c96f07c() ole32.dll!77600c15()
ole32.dll!77600bbf() ole32.dll!7752ad31()
ole32.dll!7752ac56() ole32.dll!7752b771()
ole32.dll!77600e1f() ole32.dll!7752b7ab()
ole32.dll!7752b5e1() ole32.dll!7752b54e()
user32.dll!7e418734() ole32.dll!7752b54e()
ole32.dll!7752b54e() ole32.dll!7752b54e()
ole32.dll!7752b54e() ole32.dll!7752f2d0()
ole32.dll!7752f23e() ole32.dll!77557237()
mscorwks.dll!79f9e14d() mscorwks.dll!79f9e0b4()
mscorwks.dll!79f9e018() mscorwks.dll!79f4c879()
mscorwks.dll!79f3bb76() mscoreei.dll!603cc966()
mscoreei.dll!603d1f25() mscoree.dll!790186ad()
msvcr90d.dll!_crtCorExitProcess(int status=2) Line 716 C msvcr90d.dll!_crtExitProcess(int status=2) Line 722 + 0x9 bytes C
msvcr90d.dll!doexit(int code=2, int quick=0, int retcaller=0) Line
644 + 0x9 bytes C msvcr90d.dll!exit(int code=2) Line 412 + 0xd
bytes C CSActivexMFC.exe!__tmainCRTStartup() Line 595 C
CSActivexMFC.exe!wWinMainCRTStartup() Line 399 C
kernel32.dll!7c817077()
I was hoping someone may have run into this before, I'm running into this on mulitple machines (home and at work) and at least have it narrowed down to either a problem with CSActivex not doing something it should, or something in MFC.
so my question is how to get these samples working without the access violations?
Edit:
Just opening the about window and closing it repeatedly eventually results in a crash in the debugger (unhandled exception) with a stack trace below, to me it looks like an object that was destructed is being destroyed again?
First-chance exception at 0x00400003 in CSActivexMFC.exe: 0xC0000005: Access violation writing location 0x00000000.
First-chance exception at 0x00400003 in CSActivexMFC.exe: 0xC0000005: Access violation writing location 0x00000000.
First-chance exception at 0x003a005c in CSActivexMFC.exe: 0xC0000096: Privileged instruction.
First-chance exception at 0x00460020 in CSActivexMFC.exe: 0xC0000005: Access violation reading location 0x00460020.
First-chance exception at 0x78b6ba1d (mfc90ud.dll) in CSActivexMFC.exe: 0xC0000005: Access violation writing location 0x00000018.
Unhandled exception at 0x78b6ba1d (mfc90ud.dll) in CSActivexMFC.exe: 0xC0000005: Access violation writing location 0x00000018.
mfc90ud.dll!CDataSourceControl::~CDataSourceControl() Line 2431 + 0x2d bytes C++
mfc90ud.dll!CDataSourceControl::`scalar deleting destructor'() + 0x11 bytes C++
mfc90ud.dll!COleControlSite::~COleControlSite() Line 77 + 0x22 bytes C++
mfc90ud.dll!COleControlSite::`scalar deleting destructor'() + 0x11 bytes C++
mfc90ud.dll!COleControlSiteOrWnd::~COleControlSiteOrWnd() Line 161 + 0x24 bytes C++
mfc90ud.dll!COleControlSiteOrWnd::`scalar deleting destructor'() + 0x11 bytes C++
mfc90ud.dll!COleControlContainer::~COleControlContainer() Line 199 + 0x1c bytes C++
mfc90ud.dll!COleControlContainer::`scalar deleting destructor'() + 0x11 bytes C++
mfc90ud.dll!CWnd::OnDestroy() Line 786 + 0x24 bytes C++
mfc90ud.dll!CWnd::OnWndMsg(unsigned int message=2, unsigned int wParam=0, long lParam=0, long * pResult=0x0012f510) Line 2042 C++
mfc90ud.dll!CWnd::WindowProc(unsigned int message=2, unsigned int wParam=0, long lParam=0) Line 1755 + 0x20 bytes C++
mfc90ud.dll!AfxCallWndProc(CWnd * pWnd=0x0012f88c, HWND__ * hWnd=0x002c04fc, unsigned int nMsg=2, unsigned int wParam=0, long lParam=0) Line 240 + 0x1c bytes C++
mfc90ud.dll!AfxWndProc(HWND__ * hWnd=0x002c04fc, unsigned int nMsg=2, unsigned int wParam=0, long lParam=0) Line 403 C++
mfc90ud.dll!AfxWndProcBase(HWND__ * hWnd=0x002c04fc, unsigned int nMsg=2, unsigned int wParam=0, long lParam=0) Line 441 + 0x15 bytes C++
user32.dll!7e418734()
[Frames below may be incorrect and/or missing, no symbols loaded for user32.dll]
user32.dll!7e418816()
mfc90ud.dll!CThreadSlotData::GetThreadValue(int nSlot=6623744) Line 268 C++
user32.dll!7e428eec()
ntdll.dll!7c90e473()
user32.dll!7e42b1a8()
mfc90ud.dll!CWnd::DestroyWindow() Line 1007 + 0xd bytes C++
90909090()
Take a look at this MSDN Blog by David Kline on What is a First Chance Exception.
From Blog
Does a first chance exception mean there is a problem in my code?
First chance exception messages most often do not mean there is a problem in the code. For applications / components which handle exceptions gracefully, first chance exception messages let the developer know that an exceptional situation was encountered and was handled.
For code without exception handling, the debugger will receive a second chance exception notification and will stop with a unhandled exception.
And by looking at another MSDN Blog by David Kline it will tell you how to Stop on a First Chance Exception to see what caused it.
And this MSDN Forum Posting

"Win32Exception: The operation completed successfully" after WTSQueryUserToken on 32bit Windows (64bit works)

I'm developing a small Windows Service in C# that needs to do interop with Win32 API at some point. I'm getting the following exception which does not make sense to me:
System.ComponentModel.Win32Exception: The operation completed successfully
Right after the last line in this C# snippet:
var sessionId = Kernel32.WTSGetActiveConsoleSessionId();
var userTokenPtr = new IntPtr();
if (!WtsApi32.WTSQueryUserToken(sessionId, out userTokenPtr))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
Here's how I'm declaring WTSQueryUserToken in WtsApi32:
[DllImport("Wtsapi32.dll", EntryPoint="WTSQueryUserToken")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool WTSQueryUserToken
(
[In, MarshalAs(UnmanagedType.U8)] ulong sessionId,
[Out] out IntPtr phToken
);
Some facts:
This works perfectly on 64bit Win7, but fails on a 32bit Win7.
There's no way the 10,000 handle limit has been reached when this is executed, it's the first Win32 call in a very small windows service.
I think there might be some underlying Win32 error but some bug overwrote the errorcode with a 0, thus giving me the "success" error message, but I don't know how to confirm or even diagnose this.
When I catch the exception, sessionId is 1 and userTokenPtr is 0. However, GetLastError returns 0 so I have no idea what happened.
Nearly all of the answers I found to this problem had to do with improper disposal of user controls. Since this is a Windows service, this is not the case.
I'm guessing there must be something wrong with my WTSQueryUserToken declaration, since it only fails on 32bit Windows, which leads me to think it's a marshaling problem. However, I still can't see what it might be.
Your sessionId parameter us defined as a c# ulong - an unsigned 64-bit integer, whereas the actual function export is expecting a Win32 ulong - an unsigned 32-bit integer.
c# ulong data type
Win32 data types

Mapping IntPtr into Struct via Marshal.PtrToStructure causing "Access Violation Exception"

I'm trying to use a C++ DLL (3rd party library implementing EMI protocol, having source code available) in .NET. I've succesfully done marshalling, calling the functions and getting everything work fine.
The problem occurs when I want to do marshalling from IntPtr back into the .NET Struct , here's the code (modified as suggested - removed "ref" and changed the AllocHGlobal to allocate just size of emiStruct) :
private EMI emiStruct;
private IntPtr emiIntPtr;
emiIntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(emiStruct));
Marshal.StructureToPtr(emiStruct, emiIntPtr, false);
EMIStruct.Error result = emi_init(emiIntPtr, hostname, portNumber, password, shortNumber, windowSize, throughput);
Marshal.PtrToStructure(emiIntPtr, emiStruct);
The last line (PtrToStructure) causes an exception "Attempted to read or write protected memory. This is often an indication that other memory is corrupt".
Also, I can see a debug output:
A first chance exception of type 'System.AccessViolationException' occurred in mscorlib.dll
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0xc3fffff8.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x01fffff7.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x00001f1d.
I assume the problem is somewhere in allocation of memory for the pointer emiIntPtr. Althought, when I run the code, and there is a problem with connecting to the server (e.g. server not found), the followed marshalling to the Struct emiStruct is done correctly (no exception). The problem only occurs when the connection is succesfully established and server send a respond.
Also, I wrote a C++ sample app using the same DLL library I'm trying to use in .NET, and this application (when I compile it) runs just fine - it means, the C++ DLL should be ok and not causing crashing.
Furthermore, I've found some hints to check/uncheck several properties for the project compilator (using JIT, compile it for x86 cpu, etc.), unfortunately, none of this helped.
Do you have any suggestion where the problem might be or how to do a correct IntPtr inicialization in .NET and mapping between IntPtr and Struct?
Thanks all for your replies:
Here I'm adding the C++ header of the emi_init func:
FUNC( init)( EMI* emi, /* out */
const char* hostname, /* in */
unsigned short port, /* in */
const char* password, /* in */
const char* origin_addr, /* in */
int window_sz, /* in */
int throughput); /* in */
And here is the C# emi_init declaration (I've removed the "ref" attribute for emiPtr as was suggested):
[System.Runtime.InteropServices.DllImport("emi.dll", EntryPoint = "_emi_init")]
public static extern EMIStruct.Error emi_init(
System.IntPtr emiPtr,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string hostname,
ushort port,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string password,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string origin_addr,
int window_sz, int throughput);
However, still getting the same exception.
You are using Marshal.PtrToStructure incorrectly.
The second argument requires a type, iow typeof(EMI).
The return value contains the resulting struct.
So the solution should be:
var s = (EMI) Marshal.PtrToStructure(emiIntPtr, typeof(EMI));
My guess is that you have declared the first parameter incorrectly in the C#. You have declared it as ref IntPtr which is equivalent to EMI** in C++. But I bet the C++ declaration, which you unfortunately did not include, reads EMI*. So simply remove the ref and all should be well.
I expect that emi_init does not read from the EMI parameter, i.e. it has out semantics. In which case you don't need the StructureToPtr call before you call emi_init.

FatalExecutionEngineError while calling dll method

In my program on this line:
int value = MTEConnect(auth_string, err);
I receive such exeption:
FatalExecutionEngineError
The runtime has encountered a fatal error. The address of the
error was at 0x68c8a681, on thread 0x2334. The error code is
0xc0000005. This error may be a bug in the CLR or in the unsafe
or non-verifiable portions of user code. Common sources of this
bug include user marshaling errors for COM-interop or PInvoke,
which may corrupt the stack.
MTEConnect is imported such a way:
[DllImport("mtesrl.dll", CharSet = CharSet.Ansi)]
private static extern int MTEConnect(String pars, StringBuilder err);
What's the problem and how to fix it?
upd: I can reproduce the same problem on another machine, but I got a little more desriptive message:
Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in 'C:\blahblah\MBClient\bin\Debug\MBClient.vshost.exe
Library itself is functional, because it can be used from another applications, I just can't use it from c#
I have solved my problem!
Code doesn't work this way:
StringBuilder err = new StringBuilder();
int value = MTEConnect(auth_string, err);
But it do work this way:
StringBuilder err = new StringBuilder(100);
int value = MTEConnect(auth_string, err);
It seems buffer was too short.
A FatalExecutionEnigneError is often the result of corruption within the core CLR native code that leads to a fatal native exception. When it occurs at the site of a PInvoke call it's a big indicator the PInvoke signature is incorrect.
Could you provide the native signature so we can help diagnose this problem?

Memory AccessViolationException Error Calling DLL From C#

I'm encountering a strange memory read/write error while calling a compiled DLL from C#. I use DllImport to get a handle to the function we need, which writes a return value to a parametric pointer to an int (i.e., int* out). This function is called multiple times within a thread, and runs successfully over the execution life of the first thread. However, if one launches another thread after the first has completed, the call to the external dll throws an AccessViolationException. Since the multiple calls from the first thread execute successfully, I'm thinking this is somehow related to the first thread not releasing the pointers to the relevant integer parameters(?). If so, how can I explicitly release that memory? Or, perhaps someone has a different insight into what might be going on here? Thank you very much.
EDIT: Danny has requested more specifics, and I'm happy to oblige. Here is where the external routine is invoked:
int success = -1;
unsafe
{
int res = 0;
int* res_ptr = &res;
int len = cmd.ToCharArray().Length;
int* len_ptr = &len;
CmdInterpreter(ref cmd, len_ptr, res_ptr);
success = *res_ptr;
}
Where CmdInterpreter is defined as:
[DllImport("brugs.dll", EntryPoint="CmdInterpreter",
ExactSpelling=false, CallingConvention = CallingConvention.StdCall)]
public static unsafe extern void CmdInterpreter(ref string cmd, int *len, int *res);
Please let me know if there is any additional info that would be helpful. Thank you!
Given that the problem only occurs when multiple threads are involved, it may be that the command interpreter DLL is using some sort of thread-local storage and doing it incorrectly. It could also have to do with the COM initialization state of the second thread (the one that generates the error).
It would be interesting to know what happens if you launch your new thread and have it call into the DLL before making any calls into the DLL on your first/main thread. If it works, that might support the thread-local storage theory. If it fails, that would support the COM state theory.
It may be the [DllImport]. If you post the [DllImport] signature, and the DLL's ptototype, maybe we can spot a problem.
I read that the Managed, Native, and COM Interop Team released the PInvoke Interop Assistant on CodePlex. http://www.codeplex.com/clrinterop/Release/ProjectReleases.aspx?ReleaseId=14120

Categories

Resources