C# program (process) will not unload - c#

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.

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

Kill Windows Process and Return Exit Code 0

Is there a way to kill a process with a C# script and have the process's exit code equal 0? I tried using Process.Kill() but that returns exit code -1. I am accessing getting the Excel process with the Process.GetProcessesByName() function. It looks like there is a Win32 API function TerminateProcess that takes an Exit Code as a parameter but I can't find anything equivalent in the Process class.
Edit:
Interesting discovery- when I find the Excel process in the Windows task manager then click "End task" the Excel process exits with code 0. So, it appears that the signal that the Task Manager sends to the process is different then System.Diagnostics.Kill(). Now I just need to figure out what signal the Task Manager is sending and send it.
I solved my problem even though it's a bit dirty. If someone knows a way to do it without DllImport it might be useful to share. Here's what I did:
class MyClass
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern bool TerminateProcess(IntPtr proc, uint uExit);
public void MyFunction()
{
foreach (var process in Process.GetProcesssesByName("Excel")
{
TerminateProcess(my_process.Handle, 0);
}
}
}

Wrong exit code of a Windows process (C#/C++/etc.)?

Our C# application exits with code 0, even though it is explicitly returning -1 in the code:
internal class Program
{
public int Main()
{
....
return -1;
}
}
The same happened if void Main was used:
internal class Program
{
public void Main()
{
....
Environment.Exit(-1);
}
}
As other questions on SO suggested it could have been an unhandled CLR/C++/native exception in some other thread.
However I've added graceful shutdown of all managed/native threads right before this the last one, but the behavior stayed.
What could be the reason?
Turns out this happened because we used JobObjects to make sure that all child process exit when current process exits using this code in C (we actually p-invoked from C#):
HANDLE h = ::CreateJobObject(NULL, NULL);
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
::ZeroMemory(&info, sizeof(info));
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
::SetInformationJobObject(h, JobObjectExtendedLimitInformation, &info, sizeof(info));
::AssignProcessToJobObject(h, ::GetCurrentProcess());
...
::CloseHandle(h);
return -1;
This code adds the current process and all its child processes to a job object which will be closed on current process exit.
BUT it has a side-effect when CloseHandle was invoked it would kill the current process without ever reaching to the line return -1. And since JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag automatically kills all processes there is no way to set a exit code for all processes, so OS exited the process with exit code 0.
In C# we followed standard guidelines to clean-up resources and used SafeHandle-derived class to make sure that CloseHandle is invoked and absolutely the same happened - before CLR actually exited it invoked ::CloseHandle for all SafeHandles ignoring the actual return code set both by return value and Environment.Exit.
However what's even more interesting, is that if an explicit (or not so explicit) call to CloseHandle is removed in both C# and C++, OS will still close all the handles at the process exit after CLR/CRT exited, and the actual exit code will be returned. So sometimes it is good not to clean-up resources :-) or in another words, until a native ::ExitProcess is invoked, you can't guarantee that the exit code will be intact.
So to fix this particular issue I could either call AssignProcessToJobObject whenever a child process is started or removed the explicit (or not so explicit) call to CloseHandle. I chose the first approach.

Multithreading: C# program running C dll - Unresponsive C#

I wrote a C dll that performs two tasks:
1) Relay certain messages to the C# program
2) Perform an intensive task on a different thread
It all works but the C# UI is unresponsive, even though C is running the intensive task on a different thread.
I have also exposed the C function that kicks off the intensive task to C#, allowing C# to attempt to run that function on a different thread.
No matter what, C# gets bogged down and the C# program becomes unresponsive when the intensive task runs.
I forgot to mention that I have written the entire program in C and it works without a problem but I'd like to write a C# library to use this in future .NET projects.
[DllImport(#"C:\projects\math\randomout\Debug\randout.dll", CharSet = CharSet.Auto, EntryPoint = "task_ToggleTask")]
internal static extern bool task_ToggleTask();
__declspec( dllexport ) BOOL task_ToggleTask()
{
if ( _threadStopped )
{
_threadStopped = FALSE;
_t_TaskHandle = ( HANDLE )_beginthread( task_Calculate, 0, NULL );
return TRUE;
}
else
{
_threadStopped = TRUE;
CloseHandle( _t_TaskHandle );
return FALSE;
}
}
static void task_Calculate( void* params )
{
while ( !_threadStopped )
{
WORD nextRestInterval = rand_GetBetween( 15, 50 );
/*
trivial math calculations here...
*/
//next update is at a random interval > 0ms
Sleep( nextRestInterval );
}
_endthread();
}
You need to reduce your thread's priority. I'm assuming though this happens to your system and not just the program. If it happens in your program, are you certain nothing else is going on in your main app thread and that its actually running on a separate thread?
Try reducing the thread's priority - see:
Programmatically limit CPU Usage of a Thread running inside a Service
I'll try a general answer, since you haven't specified which C# UI technology you're using (WPF or Winforms), and haven't given any example of your UI code:
I think you'd better off keep your C code as a simple utility library, without trying to do any threading stuff there, and Let the C# code manage the background thread. .Net UI has many threading techniques to keep the UI responsive while doing some long tasks in the background, e.g.: Backgroundworker, Dispatcher.Invoke, Control.Invoke etc... (take a look at this question for example).

Proper way of passing a pointer for P/Invoke function

Dear skilled. I’m developing an entity which allows user to copy multiple files in async manner with cancellation ability (and reporting progress as well). Obviously the process of copying runs in another thread, different from thread where CopyAsync was called.
My first implementation uses FileStream.BeginRead/BeginWrite with a buffer and reporting progress against number of usages of that buffer.
Later, for education purposes, I was trying to implement the same stuff thru Win32 CopyFileEx function. Eventually, I’ve stumbled upon the following thing: this function takes a pointer to bool value which is treated as cancellation indicator. According to MSDN this value is to be examined multiple times by Win32 during copying operation. When user sets this value to “false” the copying operation is cancelled.
The real problem for me is how to create a boolean value, pass it to Win32 and to make this value accessible for external user to give him an ability to cancel the copying operation. Obviously the user will call CancelAsync(object taskId), so my question is about how to get access to that boolean value in another thread fro my CancelAsync implementation.
My first attempt was to use Dictionary where key is an identifier of async operation and value points to allocated for boolean value memory slot. When user calls “CancelAsync(object taskId)” method, my class retrieves a pointer to that allocated memory from dictionary and writes “1” there.
Yesterday I’ve developed another solution which is based on creating a bool local variable in my method of copying and holding the address of that value in dictionary until copying operation completes. This approach could be described in the following lines of code (very simple and rough, just to illustrate an idea):
class Program
{
// dictionary for storing operaitons identifiers
public Dictionary<string, IntPtr> dict = new Dictionary<string,IntPtr>();
static void Main(string[] args)
{
Program p = new Program();
p.StartTheThread(); // start the copying operation, in my
// implementation it will be a thread pool thread
}
ManualResetEvent mre;
public void StartTheThread()
{
Thread t = new Thread(ThreadTask);
mre = new ManualResetEvent(false);
t.Start(null);
GC.Collect(); // just to ensure that such solution works :)
GC.Collect();
mre.WaitOne();
unsafe // cancel the copying operation
{
IntPtr ptr = dict["one"];
bool* boolPtr = (bool*)ptr; // obtaining a reference
// to local variable in another thread
(*boolPtr) = false;
}
}
public void ThreadTask(object state)
{
// In this thread Win32 call to CopyFileEx will be
bool var = true;
unsafe
{
dict["one"] = (IntPtr)(&var); // fill a dictionary
// with cancellation identifier
}
mre.Set();
// Actually Win32 CopyFileEx call will be here
while(true)
{
Console.WriteLine("Dict:{0}", dict["one"]);
Console.WriteLine("Var:{0}", var);
Console.WriteLine("============");
Thread.Sleep(1000);
}
}
}
Actually I’m a bit new to P/Invoke and all unsafe stuff so hesitating about latter approach for holding a reference to local value in dictionary and exposing this value to another thread.
Any other thoughts on how to expose that pointer to boolean in order to support cancellation of copying operation?
Ah, so that's what that other thread was about. There's a much better way to accomplish this, CopyFileEx() also supports a progress callback. That callback allows you to update the UI to show progress. And it allows you to cancel the copy, just return PROGRESS_CANCEL from the callback.
Visit pinvoke.net for the callback delegate declaration you'll need.
If your goal is to support being able to cancel a file copy operation in progress, I recommend using a CopyProgressRoutine. This gets called regularly during the copy, and allows you to cancel the operation with a return code. It will let you cancel the operation asynchronously without having to deal with pointers directly.
private class FileCopy
{
private bool cancel = false;
public void Copy(string existingFile, string newFile)
{
if (!CopyFileEx(existingFile, newFile,
CancelableCopyProgressRoutine, IntPtr.Zero, IntPtr.Zero, 0))
{
throw new Win32Exception();
}
}
public void Abort()
{
cancel = true;
}
private CopyProgressResult CancelableCopyProgressRoutine(
long TotalFileSize,
long TotalBytesTransferred,
long StreamSize,
long StreamBytesTransferred,
uint dwStreamNumber,
CopyProgressCallbackReason dwCallbackReason,
IntPtr hSourceFile,
IntPtr hDestinationFile,
IntPtr lpData)
{
return cancel ? CopyProgressResult.PROGRESS_CANCEL :
CopyProgressResult.PROGRESS_CONTINUE;
}
// Include p/inovke definitions from
// http://www.pinvoke.net/default.aspx/kernel32.copyfileex here
}
If you do want to use the pbCancel argument, then manually allocating unmanaged memory as you are already doing is probably the safest way to do it. Taking the address of a local variable is a little dangerous because the pointer will no longer be valid once the variable goes out of scope.
You could also use a boolean field in an object rather than a boolean local variable, but you will need to pin it in memory to prevent the garbage collector from moving it. You can do this either using the fixed statement or using GCHandle.Alloc.
Perhaps I'm missing something, but why couldn't you just use the defn already # http://pinvoke.net/default.aspx/kernel32/CopyFileEx.html and then set the ref int (pbCancel) to 1 at cancel time?

Categories