Keeping PInvoked method alive - c#

Here's my C code:
LIBRARY_API bool __cdecl Initialize(void (*FirstScanForDevicesDoneFunc)(void));
And here's C# PINvoke code to work with this DLL:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FirstScanForDevicesDoneFunc();
[DllImport("Native.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern bool Initialize(FirstScanForDevicesDoneFunc);
When I call this method like this:
static public void Init() {
Initialize(FirstScanForDevicesDone);
}
static public void FirstScanForDevicesDone() {
//do something
}
At the end of Init() when callback comes I get NullReferenceException. So I use Thread to keep it and everything works fine, but I'm not happy with this solution:
static public bool Working = true;
static public void Init() {
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
Initialize(FirstScanForDevicesDone);
while (Working)
{
Thread.Sleep(1000);
}
}).Start();
}
Is there a more sophisticated way to keep this working?

So I use Thread to keep it and everything works fine
No, the thread doesn't actually fix the problem. It only looks like it does, a side-effect of testing the Debug build and using a debugger. It will still crash the exact same way after you ship the Release build to your customer. Worst kind of failure of course. Why it seems like the thread solves it is explained in this post.
You need to fix the real problem, you are passing a delegate object to the native code but after the Init() method completes there is no visible reference to the object anymore. The garbage collector cannot peek inside the native code to see it in use. So the next garbage collection is going to destroy the object, kaboom when the native code makes the callback after that. Do note that you normally get a strongly worded warning about that from a debugger assistant, do make sure you didn't solve the problem by shooting the messenger.
Proper fix is:
static FirstScanForDevicesDoneFunc callbackDelegate;
static public void Init() {
callbackDelegate = new FirstScanForDevicesDoneFunc(FirstScanForDeviceDone);
Initialize(callbackDelegate);
}
The callbackDelegate variable ensures that the GC can always see a reference to the object. You set it back to null when the native code cannot make callbacks anymore. Typically never.

Related

Calling managed function inside CommandBuffer hang domain reload

I'am trying to call managed function inside CommandBuffer via IssuePluginEventAndData. It accepts (void* function pointer, int eventId, void *data).
Here's the function:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public unsafe delegate void PluginDelegate(int eventId, void* data);
[MonoPInvokeCallback(typeof(PluginDelegate))]
private static unsafe void MakeGraphicsCallback(int eventId, void* data)
{
//Completely empty.
}
Then store delegate inside non-static MonoBehaviour class and add it to CommandBuffer:
//Prevent delegate to be garbage collected.
private static PluginDelegate makeCallbackDelegate;
public void Start()
{
makeCallbackDelegate = MakeGraphicsCallback;
cmdBuffer.IssuePluginEventAndData(
Marshal.GetFunctionPointerForDelegate(makeCallbackDelegate),
0, IntPtr.Zero);
}
Everything works fine (even if function is not empty), but then, when game is stopped, and runned again it hang on domain reload, here's how editor log ends:
Reloading assemblies for play mode.
Begin MonoManager ReloadAssembly
Then goes nothing, and the only way to make editor work again is to restart it.
I've also tried to call this function from my C++ native plugin function, and also tried to call it from C++ with different calling conventions (cdecl and stdcall explicitly stated in typedef, changed accordingly for UnamangedFunctionPointerAttribute):
typedef void (__stdcall *PluginCallback)(int32_t eventId, void *data);
auto func = static_cast<PluginCallback>((void*)funcPtr);
func((int32_t)eventIdValue, (void*)dataValue);
Result is always the same.
When function is called from main thread -- everything goes fine, but once it called from another thread (unmanaged) by pointer -- assembly reload hangs forever.
Ok, I found the solution. The thing is that if function pointer obtained by GetFunctionPointerForDelegate is called from non-managed thread, you need to first initialize a thread with mono_attach_thread(domain).
So before calling function by pointer, you need to somehow call mono_attach_thread before, as stated in Mono Embedding Guide.
If your application creates threads on its own, and you want them to be able to interact with Mono, you have to register the thread so that the runtime knows about it.
To do so, call the mono_thread_attach() function before you execute any other Mono API or before manipulating any managed object.
Here's my workaround native plugin for this.
https://github.com/Meetem/ManagedRenderEvent

Why are C# callbacks only executed when the python module uses cv.imshow()?

I couldn't come up with a better more descriptive title as it involves 3 languages which I'll explain now.
I wrote a C++ wrapper around a Python module, which works just fine in C++ by the way. I made a DLL out of this wrapper and exposed some functionalities as a C and used them in a C# application.
The issue is, the C# application just hangs if I do not display the webcam feed.
That is in Python module there is this condition:
if self.debug_show_feed:
cv2.imshow('service core face Capture', frame)
and when set True, will display the webcam feed.
This is mostly a debug thing I put and for actual production it needs to be disabled. On C++ its fine
I can set this to false (through the constructor) and all is fine.
However, On C#, this behavior doesn't happen, if I try to use the module without setting the webcam feed to true, The C# app hangs, and that's because the Start() which calls the main operation becomes a blocking call and none of the callbacks are returned.
my DllImport are as follows by the way:
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Initialize(bool showFeed);
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void Start(bool async);
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void Stop();
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetCpuAffinity(int mask);
public delegate void CallbackDelegate(bool status, string message);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void AddCallback(IntPtr fn);
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void RemoveCallback(IntPtr fn);
And this is my C# callback:
private CallbackDelegate del;
public void SetUpCallback()
{
txtLog.Text += "Registering C# callback...\r\n";
del = new CallbackDelegate(callback01);
AddCallback(Marshal.GetFunctionPointerForDelegate(del));
txtLog.Text += "Calling passed C++ callback...\r\n";
}
bool status;
string id;
public void callback01(bool status, string id)
{
this.status = status;
this.id = id;
}
And this is the main python modules that are executed :
def start(self):
try:
self.is_running = True
self._main_loop()
except Exception as ex:
path='exceptions-servicecore.log'
track = traceback.format_exc()
exception_time = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
with open(path, 'a') as f:
f.writelines(f'\n{exception_time} : exception occured {ex.args} \n{track}')
def start_async(self):
st = threading.Thread(target=self.start)
st.start()
def _main_loop(self):
name = None
is_valid = False
while self.is_running and self.cap.isOpened():
is_success, frame = self.cap.read()
if is_success:
name="sth"
is_valid=True
self._execute_callbacks(is_valid, name, frame)
self._execute_c_callbacks(is_valid, name)
if self.debug_show_feed:
cv2.imshow('service core face Capture', frame)
if self.save:
self.video_writer.write(frame)
if (cv2.waitKey(1)&0xFF == ord('q')) or (not self.is_running):
break
self.cap.release()
if self.save:
self.video_writer.release()
cv2.destroyAllWindows()
Knowing this only happens in C# and not C++, I may have some issues in my marshaling or the way I'm trying to use the C# callback in this scenario.
Here is a Visual Studio with a minimal example that demonstrates this: https://workupload.com/file/epsgzmMMVMY
What is the problem here? Why is cv.imshow() causes this behavior?
I found the reason why callbacks on C# side didn't output anything. The callbacks are all executing as they should, but since the main loop on Python side is a blocking method, they only start their execution when the blocking method is over (just like a recursive function where the outputs don't get to be returned until the very end).
I then noticed cv2.imshow() creates a short pause and in that time, the C# client gets the chance to update the output and what it has been sent to. I first tried to pause the current running thread in Python, and it actually kind of worked, the output started to popup on C# side, but still the app was not responsive.
I noticed I can actually make the callback outputs show up in C# by simply using a cv2.waitkey(1) or cv2.imread('') in the else clause when showFeed is False:
while (self.is_running):
...
if self.showFeed:
cv2.imshow("image", frame)
else:
#cv2.imread('')
# or
cv2.waitkey(1)
...
And by writing :
while (self.is_running):
...
if self.showFeed:
cv2.imshow("image", frame)
else:
cv2.namedWindow('image', cv2.WINDOW_OPENGL)
cv2.waitKey(1)
cv2.destroyAllWindows()
...
The outputs are showing just fine and the application is responsive again, However, constantly creating and destroying an empty Opencv window is not a solution as it flickers and is just very bad.
I need to add that, using a timer() control event on c# to print the output and keep the app responsive doesn't work, creating a new thread also doesn't seem to work. it seems the marshaled callbacks this way can't be used like this (I am happy to hear that I am wrong though).
I'll update this answer when I find better solutions than these both C# wise (running the callbacks on a thread) or on Python side, making a visible window or altogether fix this issue.
Update
I removed the changes on Python side and implemented the threading on C# part. The reason the initial threading didn't work was because, all interops had to be called in the same thread, meaning all of the imported methods such as Initialize, Start and AddCallback had to be setup and run from within the same thread.

Can't execute statement with VS Debugger Interop

I'm writing a debugger extension VSPackage in which I want to execute a statement in the debugged process when a breakpoint is hit. In my extension code I have this:
void Initialize()
{
// ...standard vspackage init code omitted...
Globals.Init((DTE2)GetService(typeof(DTE)));
Globals.DebuggerEvents.OnEnterBreakMode += (dbgEventReason reason, ref dbgExecutionAction action) =>
{
try
{
var e1 = Globals.Application.Debugger.GetExpression("1+2");
Debug.WriteLine(e1.Value); // Prints "3"
Globals.Application.Debugger.ExecuteStatement("x = 1+2", 1000);
Debug.WriteLine("OK"); // Never prints this
}
catch (Exception ex)
{
Debug.WriteLine("Error: "+ex); // Nor this
}
}
}
When debugging this extension in a VS instance I load a trivial program looking like this
static void Main()
{
int x = 5;
Console.WriteLine("X is "+x); // Breakpoint on this line
}
When the breakpoint is hit in the debugged process the handler is called and the output window for the extension shows "3", so evaluating expressions works, but it never succeeds executing the statement. Nothing more is printed to the output window. No exception or timeout occurs and I can't continue debugging the process, the debugger appears to have crashed.
The globals class just holds the DTE and DebuggerEvents
public static class Globals
{
public static void Init(DTE2 dte)
{
Application = dte;
DebuggerEvents = dte.Events.DebuggerEvents;
}
public static DTE2 Application { get; private set; }
public static DebuggerEvents DebuggerEvents { get; private set; }
}
What am I doing wrong, or misunderstanding here?
This is an old question, but there is so little on Google about these issues, I thought I'd offer some help. Some important considerations:
Use GetExpresssion3(TreatAsStatement:=True), if possible, instead of ExecuteStatement (I could not get ExecuteStatement working properly).
The thread calling your delegate (OnEnterBreakMode) is the same thread that will need will to run again in order to execute your expression or statement. Therefore, call your GetExpression method on a new thread (Task.Run..)
You will have to monitor and manage the Reason value for OnEnterBreakMode. The initial Reason is UnwindFromException for the actual unhandled exception. Then, it is expected you are setting a variable, such as tempStack = New System.Diagnostics.StackTrace(True). OnEnterBreakMode will be called again following execution of this statement, but this time with Evaluation for the Reason. At this point you now call all of your GetExpressions to collect all of your data without additional OnEnterBreakMode calls.
Dim dte2 As EnvDTE80.DTE2 = GetGlobalService(GetType(EnvDTE.DTE))
Dim debugger5 as EnvDTE100.Debugger5 = Dte2.Debugger
Interesting design observation: System.Diagnostics.StackTrace is a very strangely designed class in the context of the rest of the .NET framework until you have to work on this project where you are extracting the StackTrace through this very technique and see the benefit of its otherwise odd design.
I was tinkering a lot with Visual Studio debugging, and the ultimate cause of freezing was always related to thread handling: VS allows any piece of code to run while debugging only in the main thread. Every other thread is disabled and in case your debug code depends on a different thread it will freeze too.
My guess: You initialized your DTE in a different thread than what you are debugging.
Assumed result: Delegate method tries to load the context of the initializing thread which is different from the debugged thread, and thus it is bound to get frozen.
Proposed solution: Don't use delegate method. They implicitly refer back to the original execution context. Instead register a regular method, and reinitialize your DTE in that context.

How does one make function calls or trigger events from a Native component into a C#/XAML component?

I am developing a WP8 application with a Native (DirectX/D3D) component and a C#/XAML component.
The Native component draws to a UI element and the C#/XAML component has the controls of the app (and other things) surrounding it. Usually, I send information from the C#/XAML component down to the Native component. But there are certain times when I would like to trigger events in the C#/XAML component based on when processing is done in the Native component. In one planned feature, I envision a C#/XAML progress bar that is kept up to date by events triggered in the Native component.
Unfortunately, despite some mediocre attempts to get information passed from the Native component to the C#/XAML one, I haven't made much progress and I feel dead in the water.
I would greatly appreciate any guidance on this. Thanks for reading.
After much poking around (and much help from some of the guys that answered in this thread!) I was able to find this solution: Calling C# method from C++ code in WP8
I will reproduce it here for simplicity's sake:
After a lot of headaches trying to figure out the required code, I think it's worth posting the final version here
C++/CX
//.h
[Windows::Foundation::Metadata::WebHostHidden]
public interface class ICallback
{
public:
virtual void Exec( Platform::String ^Command, Platform::String ^Param);
};
//.cpp
ICallback ^CSCallback = nullptr;
void Direct3DInterop::SetCallback( ICallback ^Callback)
{
CSCallback = Callback;
}
//...
if (CSCallback != nullptr)
CSCallback->Exec( "Command", "Param" );
C#
public class CallbackImpl : ICallback
{
public void Exec(String Command, String Param)
{
//Execute some C# code, if you call UI stuff you will need to call this too
//Deployment.Current.Dispatcher.BeginInvoke(() => {
// //Lambda code
//}
}
}
//...
CallbackImpl CI = new CallbackImpl();
D3DComponent.SetCallback( CI);
This is because your not able to have your C++ code call into C#.
You can only have C# call (and return) into C++.
http://social.msdn.microsoft.com/Forums/wpapps/en-us/a850b680-6052-41c5-825a-d764d3369fe9/calling-c-code-from-c-in-windows-phone-8
Something you can do is keep a function pointer to a function in C#. You can from C# call the native C++ to store the function pointer then you can call it whenever you want. The function as to be static.
for instance in C#
[DllImport( #"SomeDLL.dll" )]
static extern void SetAchievementUnlocked( AchievementUnlockCallBack callback );
public delegate int AchievementUnlockCallBack( AchievementsType id, IntPtr message );
static AchievementUnlockCallBack mAchievementUnlockCallBack = AchievementUnlocked;
static int AchievementUnlocked( AchievementsType id, IntPtr pMessage )
{
string achievementName = Marshal.PtrToStringAnsi( pMessage );
DisplayAchievement( achievementName );
MainWindowHandler.Context.Focus();
return 1;
}
and have in the constructor maybe
SetAchievementUnlocked( mAchievementUnlockCallBack );
then in C++
typedef int (*AchievementUnlockCallBack)(AchievementsType pType, char* pMessage);
AchievementUnlockCallBack globalCallback = NULL;
__declspec(dllexport) void SetAchievementUnlocked( AchievementUnlockCallBack callback )
{
globalCallback = callback
}
Then anywhere you have access to that variable you can do
void Achievement::Unlock()
{
if(globalCallback)
{
globalCallback(this->getType(), this->getName().c_str());
}
}
Hopefully this can help you. If you are not using dll and interops services, it probably would work, but I haven't tested and don't have examples unfortunatly.
The other way around is what works.
You can call native code from C# (managed code) through COM interops: http://msdn.microsoft.com/en-us/library/aa645736%28v=VS.71%29.aspx
I don't think it is possible to call managed code from native. What are you trying to do?
You can pass a delegate from your C# to the C++ Component.
In your C++ Component you'll define a delegate and a method call to set that delegate, like this:
public delegate void SomeDelegate(Platform::String^ args);
public ref class Component sealed
{
public:
void SetDelegate(SomeDelegate^);
private:
Platform::Agile<SomeDelegate> m_delegate;
}
Then in your C# you can create a function that matches the delegate signature, and pass it down to your component:
public void DelegateFunction(string args)
{
// run C# code that was invoked from C++
}
// elsewhere in your C# code
component.SetDelegate(DelegateFunction);
Then in your C++ you can just invoke the delegate method whenever you need to.
Edit: I wrote a blog post about this topic - http://robwirving.com/2014/07/21/calling-c-methods-c-winrt-components/

C# program (process) will not unload

I have a C# program that uses a class from another assembly, and this class calls an unmanaged DLL to do some processing. Here is a snippet:
public class Util
{
const string dllName = "unmanaged.dll";
[DllImport(dllName, EntryPoint = "ExFunc")]
unsafe static extern bool ExFunc(StringBuilder path, uint field);
public bool Func(string path, uint field)
{
return ExFunc(new StringBuilder(path), field);
}
...
}
Util util = new Util();
bool val = util.Func("/path/to/something/", 1);
The problem I'm having is that if I call "Func" my main C# program will not unload. When I call Close() inside my main form the process will still be there if I look in Task Manager. If I remove the call to "Func" the program unloads fine. I have done some testing and the programs Main function definitely returns so I'm not sure what's going on here.
It looks like your unmanaged library is spawning a thread for asynchronous processing.
Odds are it supports a cancel function of some sort; I suggest that you attempt to call that at program shutdown. If your program is just completing before the asynchronous call happens to complete, look for a "wait for completion" function and call that before returning from your "Func" method.
It might dispatch a non background thread that is not letting go when your main application closes. Can't say for sure without seeing the code but that is what I would assume.
It's probably less then ideal, but if you need a workaround you could probably use:
System.Diagnostics.Process.GetCurrentProcess().Kill();
This will end your app at the process level and kill all threads that are spawned through the process.
Do you have the source code to unmanaged.dll ? It must be doing something, either starting another thread and not exiting, or blocking in it's DllMain, etc.

Categories