C# COM server interop - System.InvalidCastException - c#

I have created a COM server in C# which serves a specific device and is consumed by a C++ COM client (customer application, no source available).
Customer application among other things requires periodic updates, and for that purpose function called Notify() is used. That function is implemented in unmanaged COM client code.
All is well when Notify() is called from within same thread where this notification listener object was created. But this can happen only once since C++ COM client initially asks for data just once.
And even though it asks for data just once, it doesn't seem to tolerate responses which take over a second or so. And my device is kind of slow to react, especially over network, well over a second to get a reading of some sort. Ok, I get that, it wants swift response.
So not only to achieve periodic updates, but also to relieve main thread of waiting for data, I have created a separate thread which probes a device every minute and then reports results back to unmanaged code, by calling Notify().
When this Notify() is called from a different thread, I get a very nasty System.InvalidCastException. The exception was thrown from deep within CLR.
This was on a production system. On my own development system where I have my own C++ COM client mock up, this exception is masked by ContextSwitchDeadlock during debugging session. I can switch this one off, but doesn't change the fact that Notify() doesn't behave well cross thread. In fact, according to logs, function never returns.
What to do next?
From what I could tell from the registry, COM threading model is set to 'Both'.
I have tried to remedy the problem by creating a small C++ dll, which would act as a wrapper for Notify(). So, instead of calling directly into unmanaged COM client code using this:
[MethodImpl(MethodImplOptions.InternalCall)]
void Notify([In] uint dwCount, [In] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.BStr, SizeParamIndex = 0)] string[] psAddresses, [In] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 0)] object[] pvarValues, [In] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.R8, SizeParamIndex = 0)] double[] pdtTimestamps);
I have created small dll with just this function:
extern "C" __declspec(dllexport)
void CppNotify(INotificationListener *pNotifier, unsigned long dwCount, BSTR *psAddresses, VARIANT *pvarValues, DATE *pdtTimestamps)
{
pNotifier->Notify(dwCount, psAddresses, pvarValues, pdtTimestamps);
}
Which gets called using this difinition:
[DllImport("CppNotifier.dll", CallingConvention = CallingConvention.Cdecl)]
extern public static void NotifyCpp([In] [MarshalAs(UnmanagedType.Interface)] INotificationListener pNotifier, uint dwCount, [In] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.BStr, SizeParamIndex = 0)] string[] psAddresses, [In] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 0)] object[] pvarValues, [In] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.R8, SizeParamIndex = 0)] double[] pdtTimestamps);
I was hoping that this would avoid System.InvalidCastException, but no luck yet.
Our C# COM server targets .NET 4.0, while .NET version installed on system is 4.7.1. Could this trigger such a problem?
I have also tried to re-register C# dll using RegAsm.exe, but this didn't seem to have any effect.

You need to marshall a interface to your object from the main thread to the worker thread, and call the Notify method using on this interface.
Define the following two member variables in your class:
IStream* m_StreamThis ;
<your interface>* m_pMarshalledThis ;
Before creating your thread, call the function CoMarshalInterThreadInterfaceInStream().
CoMarshalInterThreadInterfaceInStream ( <your interface>, this, &m_StreamThis ) ;
The second parameter is a pointer to IUnknown. Inside your class, which must implement IUnknown, I think that it is OK to specify "this".
The thread entry point cannot be a class member, so a common practice is to pass the object pointer as the parameter to the thread and then to use it to call a member function. I assume that you are doing this already.
In the thread, after calling a member function, call the function CoGetInterfaceAndReleaseStream().
CoGetInterfaceAndReleaseStream ( m_StreamThis, <your interface>, (void**)&m_pMarshalThis ) ;
When you need to call the Notify function, call it using the marshalled pointer:
m_pMarshalThis->Notify() ;
This will result in the function being called on the main thread.
When your thread terminates, you should of course free up the pointer m_pMarshalThis. You might want to attach it to a smart pointer class.
And of course, you should really check the HRESULT returned by both of the function calls, but that is up to you.
You can certainly find other (and better) examples of how to use these functions on Stack Overflow or other sites.

Related

Getting Ptr Value of a Function

I have an API function in my application:
<Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True, CharSet:=Runtime.InteropServices.CharSet.Ansi, ExactSpelling:=True)>
Private Shared Function GetProcAddress(ByVal hModule As IntPtr, ByVal procName As String) As IntPtr
End Function
I just want to learn the pointer 'IntPtr' value of this function. How can I do it?
Note: I will show you the exact thing that I want in C++
void* fnGetProcAddress;
fnGetProcAddress = GetProcAddress;
Well, you can continue using P/Invoke...
(Note, this is in C#, but easily convertible)
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string moduleName);
var hModule = GetModuleHandle("kernel32.dll");
var procAddress = GetProcAddress(hModule, "GetProcAddress");
I want to get this address and write it in a BinaryStream as UInt32
This is a very troublesome plan. Short from the wrong data type, you have no guarantees whatsoever that the address you write is still valid when you read the stream:
The DLL might simply not be loaded when you read the stream. It does require making the LoadLibrary() call to get it in the process. So at a very minimum you'd also have to serialize the DLL path.
DLLs do not promise to get loaded at the exact same address again. The load address embedded in the DLL header is merely a request, it is very common that the requested address is already in use by another DLL, forcing Windows to relocate the DLL. That relocated address is not predictable. A far bigger problem is that relocation is intentionally done on modern Windows versions. A feature called Address Space Layout Randomization, enabled when the DLL was linked with the /DYNAMICBASE linker option. It is an anti-malware feature, making it intentionally hard for malware to patch code.
Surely there's a better way to do what you want to do. You however made the common mistake of not explaining your reasons, it is impossible to guess at.

P/Invoke sometimes cause Win32 1008 Error with StringBuilder parameters

I have a DLL from which I need to P/Invoke the following C method:
int DAStart(
HANDLE hOpen,
char* IPAddress,
int IPPort,
int threadPriority,
char* name,
char* password,
char* userName)
Using the P/Invoke Assistant and my own research, I've come up with the following C# signature:
[DllImportAttribute("<libName>", EntryPoint="DAStart")]
static extern int DAStart(
IntPtr hOpen,
[MarshalAs(Unmanaged.LPStr)] StringBuilder IPAddress,
int IPPort,
int threadPriority,
[MarshalAs(Unmanaged.LPStr)] StringBuilder name,
[MarshalAs(Unmanaged.LPStr)] StringBuilder password,
[MarshalAs(Unmanaged.LPStr)] StringBuilder userName);
Now, I'm doing the call in the following way:
int port = 3000;
int threadPriority = 20;
DAStart(
this.nativeDllHandle, // an IntPtr class field
new StringBuilder("10.0.10.1"),
int port,
int threadPriority,
new StringBuilder("admin"),
new StringBuilder("admin"),
new StringBuilder("admin"));
Now, sometimes this works just fine, but something I get a Win32 Error 1008 - An attempt was made to reference a token that does not exist on following calls to this library.
Could it be that my StringBuilder objects get garbage collected so that the reference no longer exist if the native code tries to use it? Should I keep a reference for each one of them?
Would an IntPtr be better solution for passing my strings in that case?
** UPDATE **
This is all the API documentation I have for DAStart:
Inputs
HANDLE hInfo The handle returned by the DAOpen
char *IPAdress_in IP Address of the TMEE Server
int IPPort Console Port of the TMEE Server (default is port 3000)
int threadPriority The thread priority for the send file thread.
char *name Not used in Hardware DLL
char *password Not used in Hardware DLL
char *username Not used in Hardware DLL
Returns
ERROR_SUCCESS 0
ERROR_BAD_HANDLE -1
ERROR_BIND_FAILED -10
Comments
The DAStart API connects the client dll to the active TMEE Server service. The client thread is started with a priority set to the threadPriority parameter. The IP address parameter must be set to the address of the TMEE Server. The port parameter must be set to the port the TMEE Server listens on for Console connections (the default port the Consoles use is 3010). The Console thread is started with a priority set to the threadPriority parameter.
In the comments you indicate that the DLL takes a copy of the char* pointers (and not the contents of the strings) and then modifies the contents of the strings after DAStart returns.
In the face of this very unconventional interface design your only option is to take charge of the marshaling of the string parameters. You cannot use StringBuilder since the char* passed to the native code is valid only during the pinvoke call. It cannot be relied upon to be valid after the pinvoke call returns.
So your only solution is to pass the string parameters as IntPtr. Allocate the memory with Marshal.StringToHGlobalAnsi. Pass the resulting IntPtr to DAStart. When you are sure the DLL is done with the pointer, deallocate with Marshal.FreeHGlobal.
References outside the managed environment are unknown to the Garbage collector.
Thus you need to keep an additional reference somewhere as long as you need to the object - easiest is via a static property in the calling class.
An IntPtr does not make a difference - it will get collected as well.

Creating C# to C++ bridge: Why do I get a AccessViolationException when calling DLL?

I'm exploring the idea of building a bridge between a DLL plugin for a 3rd party app and a C# app. I'm writing both the plugin DLL and the C# application. The plugin will be loaded into the 3rd party app and then I want to use call the plugin from C# to indirectly get data from the 3rd party app.
I am able to successfully call an exported function from the DLL from C#. For example:
C++ DLL:
extern "C" __declspec(dllexport) char * HelloFromDll()
{
char *result;
result = "Hello from my DLL";
return result;
}
C#:
using System.Runtime.InteropServices;
[DllImport(#"MyDll.dll")]
private static extern string HelloFromDll();
I can then call this DLL function from C# and display the string in the UI. However, as soon as I create an export function that calls a function from my 3rd party app, I get an AccessViolationException. For example,
extern "C" __declspec(dllexport) char * GetData()
{
char *result;
result = 3rdPartyLibrary::SomeFunction();
return result;
}
Through some testing, the error seems to occur as soon as I make a call to a 3rd party function. How can I fix this?
This function is very difficult to use in a C program as well. Returning strings from functions is a poorly supported scenario. There's a memory management problem, it isn't clear who owns the string. In most cases the caller is expected to take ownership of the string and free it after using it. That's not going to work out well for your function, the program will crash since you returned a string literal.
The .NET pinvoke marshaller needs to solve this problem as well. With the extra problem that it cannot use the allocator that's used by the C code. It is going to call CoTaskMemFree (the COM allocator). That causes an undiagnosable memory leak on XP, a crash on Vista and Win7.
Just don't write C code like this. Always let the caller pass the buffer for the string. Now there's no guessing who owns the memory. Like this:
extern "C" __declspec(dllexport) void HelloFromDll(char* buffer, int bufferSize)
{
strcpy_s(result, bufferSize, "Hello from my DLL");
}
With your C# code like this:
[DllImport("foo.dll", CharSet = CharSet.Ansi)]
private static extern void HelloFromDll(StringBuilder buffer, int bufferSize);
...
var sb = new StringBuilder(666);
HelloFromDll(sb, sb.Capacity);
string result = sb.ToString();
From your question it seems that this is the scenario:
ProcessA (3rd party App) --> loads X.DLL --> initializes the plugin --> does other stuff.
ProcessB (Your C# App) --> loads X.DLL --> calls GetData();
Does X.DLL loaded in ProcessA have any mechanism to talk to X.DLL loaded in ProcessB?
if not then this approach is flawed. Your code probbably crashes because "3rdPartyLibrary" class hasn't been initialised in your C# app as it is completely different copy of the DLL.
For you to extract this data you need a query interface defined by X.DLL which can talk across processes, maybe sockets?
Then ProcessB talks to this interface and extracts the data. if using sockets, then your X.DLL would implement both server and client code, where your GetData() would use this mechanism (maybe sockets) and query the data and return it.
So : X.DLL in ProcessA should act like a server.
And: X.DLL (or write a Y.DLL) in ProcessB should act like a client and get this information from ProcessA.
btw, if the query is only needed to be done once, just hard code this is in X.DLL and dump to disk, and then explore at your convinience :-)
Generally, a returned char* needs to be returned as an IntPtr:
[DllImport(#"MyDll.dll")]
private static IntPtr HelloFromDll();
Then, you'll need to convert that IntPtr into a string:
string retVal=Marshal.PtrToStringAnsi(HelloFromDll());
Strings are a bit difficult in P/Invoke. My general rule of thumb is:
Input char* parameter = c# string
Return char * = IntPtr (use PtrToStringAnsi)
Output char* parameter = c# StringBuilder - and be sure to pre-allocate it large enough
before (ie = new StringBuilder(size)) calling the function.

Call a function from an injected DLL

First off I would like to say, that I am not trying to hack a game. I am actually employed by the company whose process I am trying to inject. :)
I would like to know how to call a function from an already injected DLL.
So, I have successfully injected and loaded my DLL in the target using CreateRemoteThread(). Below you can see a snippet of the injection:
private static bool Inject(Process pToBeInjected, string sDllPath,out string sError, out IntPtr hwnd, out IntPtr hLibModule)
{
IntPtr zeroPtr = (IntPtr)0;
hLibModule = zeroPtr;
IntPtr hProcess = NativeUtils.OpenProcess(
(0x2 | 0x8 | 0x10 | 0x20 | 0x400), //create thread, query info, operation ,write, and read
1,
(uint)pToBeInjected.Id);
hwnd = hProcess;
IntPtr loadLibH = NativeUtils.GetProcAddress( NativeUtils.GetModuleHandle("kernel32.dll"),"LoadLibraryA");
IntPtr dllAddress = NativeUtils.VirtualAllocEx(
hProcess,
(IntPtr)null,
(IntPtr)sDllPath.Length, //520 bytes should be enough
(uint)NativeUtils.AllocationType.Commit |
(uint)NativeUtils.AllocationType.Reserve,
(uint)NativeUtils.MemoryProtection.ExecuteReadWrite);
byte[] bytes = CalcBytes(sDllPath);
IntPtr ipTmp = IntPtr.Zero;
NativeUtils.WriteProcessMemory(
hProcess,
dllAddress,
bytes,
(uint)bytes.Length,
out ipTmp);
IntPtr hThread = NativeUtils.CreateRemoteThread(
hProcess,
(IntPtr)null,
(IntPtr)0,
loadLibH, //handle to LoabLibrary function
dllAddress,//Address of the dll in remote process
0,
(IntPtr)null);
uint retV= NativeUtils.WaitForSingleObject(hThread, NativeUtils.INFINITE_WAIT);
bool exitR = NativeUtils.GetExitCodeThread(hThread, out hLibModule);
return true;
}
Note: Error checking and freeing resources were removed for brevity, but rest assured I check all the pointers and free my resources.
After the function above exits, I have a non-zero module handle to my DLL returned by LoadLibrary through hLibModule, meaning that the DLL was loaded correctly.
My DLL is a C# class library meant to show a message box (for testing). I have tried testing the function and the message box pops up. It looks like this:
public class Class1
{
public static void ThreadFunc(IntPtr param )
{
IntPtr libPtr = LoadLibrary("user32.dll");
MessageBox(IntPtr.Zero, "I'm ALIVE!!!!", "InjectedDll", 0);
}
[DllImport("kernel32", SetLastError = true)]
public static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int MessageBox(IntPtr hWnd, String text, String caption, int options);
}
I compile it from Visual Studio and the DLL appears in the Debug folder. I then pass the full path of my DLL to the injector.
After injection into the target process, I don't know how to call my ThreadFunc from the injected DLL, so it never executes.
I cannot use GetProcAddress(hLibModule,"ThreadFunc") since I am out of process, so the answer must lie into calling CreateRemoteThread() somehow. Also, I have read that DllMain is no longer allowed for .NET DLLs, so I cannot get any free execution that way either.
Does anyone have any idea how to call a function from an injected DLL?
Thank you in advance.
Well, you already got a thread running inside that process. You make it do something boring, it only loads a DLL. This works completely by accident, LoadLibrary just happens to have to correct function signature.
It can do much more. That however better be unmanaged code, just like LoadLibrary(), you cannot count on any managed code running properly. That takes a heckofalot more work, you have to load and initialize the CLR and tell it to load and execute the assembly you want to run. And no, you cannot load the CLR in DllMain().
Keywords to look for are CorBindToRuntimeEx() and ICLRRuntimeHost::ExecuteInAppDomain(). This is gritty stuff to get going but I've seen it done. COM and C++ skills and generous helpings of luck required.

Issue with callback method in SetTimer Windows API called from C# code

I'm currently involved in a project that is migrating some old VB6 code to C# (.Net Framework 3.5). My mandate is to just do the migration; any functional enhancements or refactoring is to be pushed to a later phase of the project. Not ideal, but there you go.
So part of the VB6 code makes a call out to the Windows API SetTimer function. I've migrated this and cannot get it to work.
The migrated project builds as a DLL; I've created a small WinForms test harness that links to the DLL and calls the code in question. Very simple, just to prove that the call can be made.
The relevant code in the migrated DLL is as follows:
[DllImport("user32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public extern static int SetTimer(int hwnd, int nIDEvent, int uElapse, AsyncObjectCallerDelegate lpTimerFunc);
public delegate void AsyncObjectCallerDelegate(int hwnd, int uMsg, int idEvent, int dwTime);
static public int StartTimer( AsyncGeoServer.GeoWrapper AsyncObj)
{
m_objGeoWrapper = AsyncObj;
int lngReturn = SetTimer(0, 0, 1, new AsyncObjectCallerDelegate(AsyncObjectCaller));
// When the line below is removed, the call functions correctly.
// MessageBox.Show("This is a temp message box!", "Temp Msg Box", MessageBoxButtons.OKCancel);
return lngReturn;
}
static private void AsyncObjectCaller(int hwnd, int uMsg, int idEvent, int dwTime)
{
// Perform processing here - details removed for clarity
}
static public void StopTimer( int TimerID)
{
try { KillTimer(0, TimerID); }
catch { }
}
The above calls are wrapped by the DLL in an outer DoProcessing() method; this creates an event using CreateEvent before calling StartTimer (both Windows Kernel calls), then calls WaitForSingleObject before continuing processing. The AsyncObjectCaller function will set the event as part of its execution to allow processing to continue.
So my issue is this: if the code is called as listed above, it fails. The AsyncObjectCaller callback method never gets triggered and the WaitForSingleObject call times out.
If, however, I uncomment the MessageBox.Show call in StartTimer, it works as expected... sort of. The AsyncObjectCaller callback method gets triggered immediately after the call to MessageBox.Show. I've tried putting MessageBox.Show in various locations in the code, and it's the same no matter where I put it (as long as it's called after the call to SetTimer) - the callback function doesn't get triggered until the messagebox is displayed.
I'm completely stumped, and none too familiar with either VB6 or Windows API coding, coming from a mainly .Net background.
Thanks for any help!
Your AsyncObjectCallerDelegate is incorrect. It might work in 32-bit code, but will fail miserably in 64-bit. The Windows API function prototype is:
VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
In C#, that would be:
delegate void AsyncObjectCallerDelegate(IntPtr hWnd, uint uMsg, IntPtr nIDEvent, uint dwTime);
Also, your managed prototype should be:
static extern IntPtr SetTimer(IntPtr hWnd, IntPtr nIDEvent, uint uElapse, AsyncObjectCallerDelegate lpTimerFunc);
That said, I'd echo what Alex Farber said: you should use one of the .NET timer objects for this. Since this doesn't appear to be a UI timer (you're passing 0 for the window handle), I'd suggest System.Timers.Timer or System.Threading.Timer. If you want the timer to raise an event, use System.Timers.Timer. If you want the timer to call a callback function, use System.Threading.Timer.
Note that the event or callback will be executed on a pool thread--NOT the program's main thread. So if the processing will be accessing any shared data, you'll have to keep thread synchronization issues in mind.
The problem is that your program is not pumping a message loop or is not letting the UI thread go idle. An API function like SetTimer() requires a message loop to work. Application.Run() in a Windows Forms project for example. The callback can only run when the your main thread is inside the loop, dispatching Windows messages.
It works when you use MessageBox.Show(), that's a function that pumps its own message loop. So that the message box can respond to the user clicking the OK button. But of course, that will only work for as long as the box is up.
You'll probably need to restructure your program so it is based on a Windows Forms project template. Calling Application.DoEvents() in a loop is a very imperfect workaround.
public extern static int SetTimer(int hwnd, int nIDEvent, int uElapse, IntPtr lpTimerFunc);
int lngReturn = SetTimer(0, 0, 1, Marshal.GetFunctionPointerForDelegate(new AsyncObjectCallerDelegate(AsyncObjectCaller)));
I understand that your mandate is to just do the migration, but i any case, it is better to use Windows Forms timer instead of this, it wraps native SetTimer API, and there is no need in these interoperability tricks.

Categories

Resources