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
Related
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.
So I am working with a c# wrapper to a C++ library, and trying to add another function. I have created the function declaration in C# and it is working. But it only works once. When I try to run it the second time, the program hangs.
The interop definitions and declarations are at https://github.com/joshglenn/interception-cs/blob/master/kchordr/Program.cs
the code I am running is here: https://github.com/joshglenn/interception-cs/blob/master/kchordr/InterceptionDemoForm.cs
The function that runs fine the first time but hangs on the second launch is GetHardwareID().
My question is, how can I troubleshoot this? Does this appear to be a memory leak?
to get the error code from the WinAPI call use the Marshal.GetLastWin32Error();
Also remember to decorate your call with "Set Last Error = true";
Here is an example i have for calling a popup on a taskbar icon :
[DllImport("shell32.dll",SetLastError=true)]
public static extern bool Shell_NotifyIcon(uint dwMessage, [In] ref NotifyIconData pnid);
usage:
//call your code like you usually call the method
bool callResult = Caller.Shell_NotifyIcon((uint)NotifyIconMessage.NIM_ADD, ref n);
//afther that call the GetLastError to get the error code
int errorCode = Marshal.GetLastWin32Error();
google the error code and see what it means
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/
I have a C++ DLL that I have source to. It is currently logging to stdout.
I am calling methods in this dll via pinvoke from c#.
I want the c# code to be able to get the log messages, and then forward them to the c# application's own logging mechanism.
I have seen some questions/answers dealing with capturing stdout, but I cannot get them to work. If someone can provide a complete hello world example for this, that would be great.
Otherwise, I was thinking of changing the c++ function to accept a string or stream parameter of some sort and just fill it with messages to be read at the return of the function.
However, how do I use string, since the c++ dll would need to allocate the memory, and what would free it?
Is there a way for me to pass in a stream and read from the stream using normal c# stream mechanics, but inside the dll let it be used just like stdout would be normally?
Help!
This question is close, but I dont want to write it out to a file, if something similar would work to capture into a memorystream that would be great, but I don't see an equivilent SafeHandle etc for memorystream.
Redirect stdout+stderr on a C# Windows service
You could declare your logging function in your C++ DLL as a function pointer, which defaults to a function printing to stdout, and provide a P/Invoke'able function to set it to a different callback.
You can pass a C# method to this function by using Marshal.GetFunctionPointerForDelegate.
Example (untested!)
C++ DLL (pseudo-code):
delegate void logger(char* msg);
logger log = printf;
void set_logger(logger l) {
log = l;
}
void test() {
log("Hello World!");
}
C# program:
static extern void set_logger(IntPtr l);
static extern void test();
static Action<IntPtr> log;
static void LogToConsole(IntPtr msg)
{
Console.WriteLine(Marshal.PtrToStringAnsi(msg));
}
static void Main()
{
log = new Action<IntPtr>(LogToConsole);
set_logger(Marshal.GetFunctionPointerForDelegate(log));
test();
}
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.