Currently I'm using a third party DLL for a printer. It's a C# wrapper for a C++ DLL, so it can be used in a C# application. The method for printing contains a callback function that should be called when printing is done. However, I can't get it to work, so I'm wondering if I'm implementing it correctly.
The (shortened) method of this print and callback function is:
public class PrinterWrapper
{
public uint Print(CallbackFunction callbackFunction);
public delegate void CallbackFunction();
}
In another class I'm using the print function and try to test the callback this way:
class Foo {
private void callback() {
{
Console.WriteLine("Test");
}
public void Print() {
{
PrinterWrapper wrapper = new PrinterWrapper();
wrapper.Print(this.callback);
wrapper.Print(new PrinterWrapper.CallbackFunction(this.callback));
}
}
I've tried both version of calling the Print method (both should be the same), but I'm not getting a callback. Instead, I get an APPCRASH just when the print is ready. Did some searching, found out I could catch the exception with the setting
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true" />
</runtime>
It tells me it's a read/write memory protection exception. The event log also shows an error, right before my application crashes:
Application: Application.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
So it looks like the third party DLL is trying to access memory it doesn't have access to. The documentation says that the callback argument is a pointer (that's for the original C++ DLL). There is no documentation for the C# wrapper DLL.
With this info, did I correctly make use of the callback function or do I have to change something to get it working?
Had a wrong implementation of the callback delegate. Fixed it and it now works.
Related
OK, so I have the C# DLL method:
public void DeletePublisher(string strName)
{
try
{
if (_PublisherData.PublisherDictionary.ContainsKey(strName))
_PublisherData.PublisherDictionary.Remove(strName);
}
catch (Exception ex)
{
SimpleLog.Log(ex);
}
}
It works fine. If there is a exception it is detected and added to the log.
At the moment, the above is called via MFC in my C++ project using a wrapper:
bool CMSATools::DeletePublisher(CString strPublisher)
{
bool bDeleted = false;
if (m_pInterface != nullptr)
{
CComBSTR bstrPublisher = strPublisher.AllocSysString();
throw_if_fail(m_pInterface->DeletePublisher(bstrPublisher));
bDeleted = true;
}
return bDeleted;
}
They both work fine. The issue is that fact that the CPP method currently has no knowledge of the C# method having failed. Now, in this particular instance I know I could change the signature of the DLL method to return false for a exception failure occurring and examine that return value in the CPP file.
But, in other instances I am already using the return value and thus, it would seem for consistency to me, that I pass in a bool bExceptionRaised parameter instead to my methods in the DLL.
That way, I can test that value when the method seemed to complete and if it is false act accordingly.
At the moment my application doesn't realise that an exception occurred and that is confusion.
Can I assume that either of these methodologies are the simplest approach to what I am trying to detect?
Update
Based on the answer provided I have tried to follow this tutorial and I am getting confused. I have tried to follow it and I can't create a CLR DLL and build it that is a bridge to my C# DLL file.
Whilst I appreciate the answer I feel like it is breaking up everything I have worked on since the C# DLL already handles and logs it's exceptions. Whilst I would like to learn how to build this bridge for the future, I still think perhaps at the point in time just changing my signatures is sufficient. Either way, my attempt a basic build of a bridge is failing.
Use a C++/CLI wrapper for the access of the managed component.
With C++/CLI you can directly use the C# component can catch the managed exception and you can throw a native exception or even return true or false... whatever you want.
void DoManagedStuff(SOMEDATA somedata)
{
try
{
auto sm = ConvertToSomeDataToManaged(somedata);
CallManagedCode(sm);
}
catch (Exception^ e)
{
throw CMyNativeException();
}
}
I’ve compiled libsass 3.3.6 into a DLL with VS 2015 using the included solution files. Running the code below causes the program to crash immediately with no output.
using System;
using System.Runtime.InteropServices;
namespace Sass.Cli {
static class Sass {
[DllImport(#"C:\...\libsass\win\bin\libsass.dll")]
public static extern String libsass_version();
}
class Program {
static void Main(string[] args) {
Console.WriteLine(Sass.libsass_version());
}
}
}
The source for the invoked function is at sass.cpp:61.
const char* ADDCALL libsass_version(void)
Both the DLL and the above code were compiled for x86. Running the VS debugger on crash gives me the following exception: Unhandled exception at 0x771A9841 (ntdll.dll) in Sass.Cli.exe: 0xC0000374: A heap has been corrupted (parameters: 0x771DC8D0).
Is this something that can be fixed or that I’ve overlooked? Or is it just the case that libsass DLLs aren’t currently working?
When a string is used as a return type then the framework assumes it was allocated by calling CoTaskMemAlloc. It then copies the content of the string and deallocation by calling CoTaskMemFree. That is the explanation for your error.
Solve it by changing the return value to IntPtr and getting the string content with Marshal.PtrToStringAnsi. You won't need to deal located anything since this version string will be static.
I can't tell what the calling convention is. You should check the code and docs to find out. Still, this function is so simple that it behaves the same way for both cdecl and stdcall so that can't explain the error. Still, you will need to get it right for the rest of the library.
Note that I am guessing a little here. You've not provided full details. You should consult the code and docs to double check my guesswork.
I'm using Marshal.GetFunctionPointerForDelegate to get a function pointer to a native function. I then pass this function pointer to some unmanaged code via the regular DllImport mechanism. I'm using this for callbacks; the native code calls back into the managed (C#) code. Everything works fine as long as the callback happens on the same thread. If I attempt to call the managed function from a thread I created via CreateThread it fails.
Is it possible to call back into managed code from a native thread simply via the function pointer that GetFunctionPointerForDelegate returns?
C#:
//in class definition
[DllImport("SomeDll")]
public static extern void SetCallback(System.IntPtr function);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public void delegate SomeDelgateType();
public SomeDelgateType OnCallback;
//a function to implement the callback
public void Callback()
{
}
//inside a setup function
OnCallback = new SomeDelgateType(Callback);
SetCallback(Marshal.GetFunctionPointerForDelegate(OnCallback);
The problem occurs when I call the function pointer from C++. If it's on the original thread that made the SetCallback function everything works. If I create a native thread with CreateThread and then try to call the function via the pointer, I get the following exception:
Unhandled exception at 0x76674598 (KernelBase.dll) in MissionControl.exe: 0xE0434352 (parameters: 0x80070057, 0x00000000, 0x00000000, 0x00000000, 0x73DB0000).
With the following stack trace:
KernelBase.dll!_RaiseException#16() Unknown
clr.dll!RaiseTheExceptionInternalOnly(class Object *,int,int) Unknown
clr.dll!IL_Throw(class Object *) Unknown
02bbc34b() Unknown
[Frames below may be incorrect and/or missing]
[External Code]
native_function_on_different_thread();
Turns out that you can actually call from an unmanaged thread. The catch is that if you're debugging your managed application, no break points inside the callback will actually ht in the debugger, but your code will still be executed. To get your breakpoints to work, you'll need to enable "native code debugging" (even though your breakpoint is in managed code!) by going to Project -> Properties -> Debug -> Enable native code debugging.
I found out about the error because I saw it in the windows built-in event viewer:
Description: The process was terminated due to an unhandled exception.
Exception Info: System.MissingMethodException
Stack:
at Injection.Main.DrawText_Hooked(...)
I have a c# application using easyhook. My dll critical code:
public void Run(RemoteHooking.IContext InContext, String InChannelName)
{
// Install system hook to detect calls to DrawTextExW that is made by the client and call the function DrawText_Hooked when ever this happens
try
{
DrawTextExHook = LocalHook.Create(LocalHook.GetProcAddress("user32.dll", "DrawTextExW"), new DDrawTextEx(DrawText_Hooked), this);
DrawTextExHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
}....
And my delegate to handle the hooked function is:
int DrawText_Hooked(...)
{
Interface.Read(hdc, lpString, cchText, dwDTFormat);
return DrawTextExW(hdc, lpString, cchText, ref lprc, dwDTFormat, ref dparams);
}
When I shut down my main application everything works fine unless I use Interface.Read(...): in this case, the hooked application crashes. I've read it's probably because Interface.Read(...) doesn't exist anymore once I exit my app but I don't know how to tell my dll to stop doing that or simply unload so that it doesn't try to do Interface.Read(...) and finds out it doesn't actually exist anymore. How shall I do it?
Two days looking for the answer and after posting it I discover it myself after 10':
What I did was to declare the hook static:
static LocalHook DrawTextExHook;
So from my main code, on exit, I could call a static method that points it to null, therefore stopping calling my Interface.Read(...).
public static void stopIt()
{
DrawTextExHook = null;
}
quick question. I want to find out if a DLL is present in the system where my application is executing.
Is this possible in C#? (in a way that would work on ALL Windows OS?)
For DLL i mean a non-.NET classic dll (a Win32 dll)
(Basically I want to make a check cause I'm using a DLL that may or may not be present on the user system, but I don't want the app to crash without warning when this is not present :P)
Call the LoadLibrary API function:
[DllImport("kernel32", SetLastError=true)]
static extern IntPtr LoadLibrary(string lpFileName);
static bool CheckLibrary(string fileName) {
return LoadLibrary(fileName) == IntPtr.Zero;
}
When using platform invoke calls in .NET, you could use the Marshal.PrelinkAll(Type) method:
Setup tasks provide early initialization and are performed
automatically when the target method is invoked. First-time tasks
include the following:
Verifying that the platform invoke metadata is correctly formatted.
Verifying that all the managed types are valid parameters of platform
invoke functions.
Locating and loading the unmanaged DLL into the process.
Locating the entry point in the process.
As you can see, it performs additional checks other than if the dll exists, like locating the entry points (e.g if SomeMethod() and SomeMethod2() actually exist in the process like in the following code).
using System.Runtime.InteropServices;
public class MY_PINVOKES
{
[DllImport("some.dll")]
private static void SomeMethod();
[DllImport("some.dll")]
private static void SomeMethod2();
}
Then use a try/catch strategy to perform your check:
try
{
// MY_PINVOKES class where P/Invokes are
Marshal.PrelinkAll( typeof( MY_PINVOKES) );
}
catch
{
// Handle error, DLL or Method may not exist
}
Actually it does not throw FileNotFoundException.
Also for that one needs to check in multiple places for path, for the LoadLibrary
There is a standard exception in .net the is derived from TypeLoadException, that is DllNotFoundException.
Best way is to wrap a method/PInvoke call in try..catch and handle the DllNotFoundException since .net will check for application path as well as any other paths set as part of PATH OS Environment variable.
[DllImport("some.dll")]
private static void SomeMethod();
public static void SomeMethodWrapper() {
try {
SomeMethod();
} catch (DllNotFoundException) {
// Handle your logic here
}
}
Call LoadLibrary.
http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx
I'm assuming this is a PInvoke call?
If so the easiest way to make this determine if it's present is to make the call and catch the exception that results if the file does not exist.
[DllImport("some.dll")]
private static void SomeMethod();
public static void SomeMethodWrapper() {
try {
SomeMethod();
} catch (DllNotFoundException) {
// Do Nothing
}
}