.NET object design: hardware handles & garbage collection - c#

I'm developing a .NET library for easy use of LibTiePie by .NET code.
Relevant library code (C#):
using Handle = UInt32;
public static class API
{
[DllImport(#"libtiepie.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void DevClose(Handle device);
};
public class Device
{
protected Handle _handle;
public Device(Handle handle)
{
_handle = handle;
}
~Device()
{
API.DevClose(_handle);
}
}
Program code (C#):
Device dev = new Device( some_valid_open_handle );
// Do something useful with dev
dev = null; // How can I make sure that the handle is closed now, as the GC may not cleanup it directly?
I can add Close method the Device class which can be called before releasing the reference. But wonder is there is a better .NET way of implementing this?

Implement the IDisposable interface.
Consumers can then do:
using (Device d = new Device(handle))
{
...
}
This will give deterministic closing of the underlying handle. Also see documentation on the using keyword.
Instead of calling API.DevClose(_handle) in the finalizer, you'd then do it in Dispose(). The MSDN link has a nice example of how this pattern can be used to close native handles.

Related

Problems with managing shared ownership of IDisposable objects

[There is a similar question Shared ownership of IDisposable objects in C# but the accepted answer suffers from similar design problems which my solution has]
I have been trying to think around this problem having seen many designs taking a blind leap of faith in garbage collector when working in c#. Reason being many times its easy to ignore that one need to handle the IDisposable rather carefully making them close equivalent of resource allocation in c++. I understand that pedantically speaking Dispose is not the equivalent of c++ destructor but if you are holding on to native resources which needs to be cleaned in a deterministic manner it becomes very similar.
But if the object is shared by multiple resources (for eg. an HttpClient object which is meant to be created and used concurrently for performance), who owns the responsibility of calling Dispose since there is no single owner? To solve this problem I came up with a SharedOwner library which has a similar interface as shared_ptr.
Code snippet:
SharedOwner:
public static SharedHandle<T> MakeSharedHandle(Func<T> createSharedOwner)
{
var obj = new SharedHandle<T>(createSharedOwner());
return obj;
}
public SharedHandle(T obj)
{
AddReference();
m_object = obj;
}
public Handle<T> GetHandle()
{
AddReference();
return new Handle<T>(this);
}
internal void Decrement()
{
if (Interlocked.Decrement(ref m_refCounter) == 0)
{
m_object.Dispose();
m_object = default(T);
}
}
internal T GetInternalHandler() { return m_object; }
private void AddReference()
{
Interlocked.Increment(ref m_refCounter);
}
~SharedHandle()
{
m_object.Dispose();
}
Handle
is a transparent wrapper that manages the ref counting calls keeping that abstracted from consumers.
public sealed class Handle<T> : IDisposable where T : IDisposable
{
private SharedHandle<T> m_handle;
bool disposed = false;
internal Handle(SharedHandle<T> handle) { m_handle = handle; }
public void Dispose()
{
if (!disposed)
{
m_handle.Decrement();
GC.SuppressFinalize(this);
disposed = true;
}
}
~Handle()
{
if (!disposed)
{
m_handle.Decrement();
}
}
The typical usage pattern that I imagined would be:
using (var sharedClient = this.m_sharedClient.GetHandle()) // m_sharedClient is the SharedHandle passed
{
var httpClient = (HttpClient)sharedClient;
// use httpClient
}
Now I see two issues with this approach which deviate it from the original motivation of simulating shared_ptr behavior:
The first reference is held by SharedHandle itself. So even when all Handles are out of scope one reference would still be held by SharedHandle thereby making the if block in Decrement unreachable.
The final Dispose happens when the SharedHandle dies which in lot of sense is no better than not calling Dispose on the underlying object itself. Hence making the solution much less valuable.
I am thinking of moving the reference counting to Handle and using SharedHandle as the control block in shared_ptr but then that means that one may end up with a valid SharedHandle object holding on to a Disposed internal object.
Another alternative that I can think of is making SharedHandle derive from IDisposable and just call Decrement in Dispose. But then this brings other set of design issues. Is there anything that can be done to solve this problem in a more elegant way?

Events in native library created by "Unmanaged Exports" in C#

I have written the following code that uses .net4 to run. Since I am using this code in Unity3D that doesn't support .net4 I had to convert it to native code. I am using "Unmanaged Exports" to export it to a native library.
I can call this function from Unity3D and it works fine.
Now I want to add events to my library and then access these events from another C# code in Unity3D.
My question is: How to create a callback event and register a function in my library to call when it is done? I know how to create an event in a Managed c# code. But note that here I am exporting it to native code and I need to use the event in the native code. So, My library does something as a native code and then I want it to fire a callback function to tell Unity3D that it is done.
Here is my library code:
[DllExport("SayText", CallingConvention = CallingConvention.Cdecl)]
public static void SayText()
{
var task = new Task(() =>
{
var synth = new SpeechSynthesizer();
synth.SetOutputToNull();
synth.SetOutputToWaveFile("D:\\test3.wav");
synth.SpeakCompleted += SynthOnSpeakCompleted;
synth.SpeakAsync("This is a test text");
});
task.Start();
}
private static void SynthOnSpeakCompleted(object sender, SpeakCompletedEventArgs speakCompletedEventArgs)
{
var synth = (SpeechSynthesizer)sender;
synth.SpeakCompleted -= SynthOnSpeakCompleted;
synth.SetOutputToDefaultAudioDevice();
// I want to trigger an event here so the application knows that the file has been created.
}
And here is how I'm calling this function from Unity3D:
[DllImport("mylib", EntryPoint = "SayText")]
public static extern void SayText();
I can't be sure it will solve your issue but I tried something similar with ios plugin.
Here is the C# side of the plugin:
public class CSharpWrapper
{
// Create delegate type
public delegate void TestDelegate();
// Connection with the native side
[DllImport("__Internal")]
private static extern void externMethod( TestDelegate onCompletion);
private static Action callback = null;
// This is most likely the part you are looking for.
// That method is marshalled so it will pass its address to the native side
// When native calls it we can add any code within
[MonoPInvokeCallback(typeof(TestDelegate))]
private static void ManagedTest()
{
if(callback != null) { callback(); }
callback = null;
}
#endif
public static void CallMethod(Action<string> onCompletion)
{
callback = onCompletion;
// Here we pass our own method that is marshalled for native side
externMethod(ManagedTest);
}
}
Then I have a C section in the .m file.
extern "C"
{
typedef void (*TestCallback)();
void externMethod(TestCallback testCallback)
{
// Here communication with Objective-C code
}
}
Maybe this will get you somewhere near completion. It is also possible to add parameters, just list them as usual and the marshalling attribute will do it all for you.

enhanced write filter api c#

I'm using Visual Studio 2010 and coding in c#.
public partial class App : Application
{
[DllImport("ewfapi.dll")]
public static extern IntPtr EwfMgrOpenProtected(string lpVolume);
[DllImport("ewfapi.dll")]
public static extern bool EwfMgrCommit(IntPtr hDevice);
public static bool EWFcommit()
{
temp = true;
string strVolumeName = "C:";
hProVol = EwfMgrOpenProtected(strVolumeName);
temp = EwfMgrCommit(hProVol);
return temp;
}
}
The problem I'm having is that these commands do not work on the machine with the EWF enabled.
I've attempted to get the Volume Name from ewfmanager instead of hardcoding it to "C:". However, I'm still learning and I'm having trouble using the command "EwfMgrGetProtectedVolumeList". This api command will return the VolumeName I need to run the other ewfapi commands. However, this command returns "PEWF_VOLUME_NAME_ENTRY " variable which I need to define. This is where I get stuck.
In C++, the header file defines this variable, but in c# header files are non existent. Would I have to convert C++ code to c# code in order to use structures defined in the header file?
Currently, I'm using a work around by executing the commands via command prompt which works flawlessly. But, I'm curious and want to learn the "right"/best way to do this in c#.
Please let me know of any experience using api commands in C#. Thank you.
This is the code I'm trying to convert to C#. I'm unsure how to convert the Declarators in C++ to C#.
typedef struct _EWF_VOLUME_NAME_ENTRY
{
struct _EWF_VOLUME_NAME_ENTRY* Next;
WCHAR Name[1];
} EWF_VOLUME_NAME_ENTRY, * PEWF_VOLUME_NAME_ENTRY;
This is the converted C# code without the declarators:
public struct EWF_VOLUME_NAME_ENTRY
{
/// _EWF_VOLUME_NAME_ENTRY*
public System.IntPtr Next;
/// WCHAR[1]
public string Name;
}
Your attempt was actually really close, it just needed some attributes to help the compiler along (in fact it may have worked without them)
[StructLayout(LayoutKind.Sequential)]
public struct EWF_VOLUME_NAME_ENTRY
{
/// _EWF_VOLUME_NAME_ENTRY*
public System.IntPtr Next;
/// WCHAR[1]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=1)]
public string Name;
}
To use it, the P/Invoke signature of your method would be.
[DllImport("ewfapi.dll")]
public static extern IntPtr EwfMgrGetProtectedVolumeList();
You also need a few more functions
[DllImport("ewfapi.dll")]
public static extern void EwfMgrVolumeNameListDelete(IntPtr list);
[DllImport("ewfapi.dll")]
public static extern bool EwfMgrVolumeNameListIsEmpty(IntPtr list);
[DllImport("ewfapi.dll")]
public static extern void EwfMgrVolumeNameEntryPop(ref IntPtr list);
You could then get the list of protected volumes like so.
public IEnumerable<string> GetProtectedVolumeNames()
{
var listptr = EwfMgrGetProtectedVolumeList();
if(listptr == IntPtr.Zero)
throw new Win32Exception(); //the default constuctor calls Marshal.GetLastWin32Error() for you.
try
{
while(!EwfMgrVolumeNameListIsEmpty(listPtr))
{
var currentStruct = Marshal.PtrToStructure<EWF_VOLUME_NAME_ENTRY>(listPtr);
// Pre .NET 4.5.1 version
// var currentStruct = (EWF_VOLUME_NAME_ENTRY)Marshal.PtrToStructure(listPtr, typeof(EWF_VOLUME_NAME_ENTRY));
yield return currentStruct.Name;
EwfMgrVolumeNameEntryPop(ref listPtr);
}
}
finally
{
if(listptr != IntPtr.Zero)
EwfMgrVolumeNameListDelete(listptr);
}
}
Note this code was written in the browser and is untested, but I think it should work.
EDIT: Important note, if you use this function outside of a foreach and instead manually go through the IEnumerable be sure to dispose of it, otherwise the finally block will not execute and you will have a memory leak (a foreach automatically calls dispose for you when you leave the scope of the loop).
On a side note you may want to check out this old MSDN Magazine article: "Making PInvoke Easy". It includes a link to a program that you can give it the C/C++ signature and it will give you back a rough version of the .NET P/Invoke signature.
Minor tweak to Scotts answer. The name is a null terminated string, so increase the SizeConst to get the rest of the characters of the name:
[StructLayout(LayoutKind.Sequential)]
public struct EWF_VOLUME_NAME_ENTRY
{
/// _EWF_VOLUME_NAME_ENTRY*
public System.IntPtr Next;
/// WCHAR[1]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=300)]
public string Name;
}

C# Mono/.NET differential CAD software retrievement

OK, I will try to do my best, but I think that my English is still too bad when it comes to complex subjects/phrases.
I have to build a class (as for now it's not static) that retrieves the information about the external application (software available on customers PC).
The Linux class was really easy to code, but now I have to implement it on Windows.
Basically I've encountered some difficulties with x64 registry reading from x86 version of my application: you can do it only by using [DllImport("advapi32.dll")].
From the beginning I knew that software retirement is strongly depending on target OS, so I've created 4 classes:
public abstract ExternalApplications that defines some basic methods and it is derived by ExternalApplicationsWin, ExternalApplicationsMac and ExternalApplicationsUnix.
Inmy application I create an instance of ExternalApplications and assign it by switching the operating system type:
ExternalApplications ex = null;
switch (Environment.OSVersion.Platform)
{
case PlatformID.Win32NT:
goto default;
case PlatformID.MacOSX:
_ex = new ExternalApplicationsMac(); break;
case PlatformID.Unix:
_ex = new ExternalApplicationsUnix(); break;
default:
_ex = new ExternalApplicationsWin(); break;
}
I this way the method call will be dispatched automatically to the right ExternalApplicationsXXX type.
Now by introducing [DllImport("advapi32.dll")] I'm obligated to:
change the class structure (to static extern)
it will probably brake Mono compilation on Unix/Mac OS X compilation (with
DllNotFoundException)
There are several options:
(1) I can create 3 parallel projects (.cproj) with the same target assembly name for Linux, Mac and Windows. The projects will contain the same classes and methods so I can reference it inside my application without any problem.
This option sucks, it lacks of automation: everything is done manually.
(2) I can accomplish a preventive "DllImport" code exclusion by using C# directives like
#if !MONO
...
#endif
I'm sure that there are many other methods like DLLMAP and others.
I think that more experienced programmers will tell me what is the most elegant/reliable solution.
EDIT 1:
I've just discovered that x64 registry hive reading from an x86 application is possible, however only in .NET 4.0 and higher (according to my source, still need to test).
string registryBranchPath = "SOFTWARE\MySoft";
RegistryKey regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
regKey = regKey.OpenSubKey(registryBranchPath);
This solves only one part of my question, the other part (regarding the possibility to use DllImport in Windows specific non-static classes) is still to be confirmed / tested.
Your class doesn't need to be static, only the imported external method is marked as such. Also, the imported method should be marked private, as nothing except the importing class should call it directly.
You don't need any fancy compilation tricks / code splitting, the DllImport is not checked until it's actually invoked.
An example from MSDN documentation for DllImport:
using System;
using System.Runtime.InteropServices;
class Example
{
// Use DllImport to import the Win32 MessageBox function.
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int MessageBox(IntPtr hWnd, String text,
String caption, uint type);
public void MessageBox()
{
// Call the MessageBox function using platform invoke.
MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0);
}
}
So the final solution for me will look like this simplified snippet:
public static class UsageClass
{
private static ExternalApplications _extApps;
public static void Initialize()
{
_extApps = null;
switch (Environment.OSVersion.Platform)
{
case PlatformID.Win32NT:
goto default;
case PlatformID.MacOSX:
_extApps = new ExternalApplicationsMac(); break;
case PlatformID.Unix:
_extApps = new ExternalApplicationsUnix(); break;
default:
_extApps = new ExternalApplicationsWin(); break;
}
}
internal abstract class ExternalApplications
{
public abstract string[] DoSomething();
}
internal class ExternalApplicationsWin : ExternalApplications
{
public abstract void DoSomething()
{
// Windows code
RegistryKey regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
(Environment.Is64BitOperatingSystem) ? RegistryView.Registry64 : RegistryView.Registry32).OpenSubKey("SOFTWARE\MySoft");
...
}
}
internal class ExternalApplicationsUnix : ExternalApplications
{
public abstract void DoSomething()
{
// Unix code
}
}
internal class ExternalApplicationsMac : ExternalApplications
{
public abstract void DoSomething()
{
// Mac code
}
}
}

Calling a method on Object exposed by Word Add-in throws RemotingException

I am writing a (Shared) Word Add-In in C# and want to communicate with it by exposing an object through the Object property of the COMAddIn class.
Because I want my code to be executed on the UI thread I derive my add-in and exposed object from the StandardOleMarshalObject class. This should take care of the marshaling as described here and here.
But by doing this I get different behavior when i compile against .NET 2.0 or.NET 4.0. When compiling against .NET 4.0 my exposed object is of type __ComObject and lets itself be cast to my publicly comvisible defined interface. This in turn lets me call methods on the object and works perfectly.
When compiling against .NET 2.0 the exposed object is of type __TransparentProxy. This can also be cast to my interface but when i try to call a method it wil throw a System.Runtime.Remoting.RemotingException with the message:
This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server.
When I do not inherit from StandardOleMarshalObject it does seem to work but then my code would execute on an arbitrary RPC thread which is not what i'm looking for.
I have searched the internet but was not able to find a solution or reason why this is not working in .NET 2.0. I did find some similar problems, but they all seem to address Excel.
At this moment I'm not in the position of switching to .NET 4.0 so i'm really hoping this can be solved for .NET 2.0.
Does anyone have a solution for this problem, or at least an explanation?
Here is my test code :
[ComVisible(true)][Guid("...")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IService
{
void Hello();
}
[ComVisible(true)][Guid("...")]
[ClassInterface(ClassInterfaceType.None)]
public class MyService : StandardOleMarshalObject, IService
{
public void Hello()
{
MessageBox.Show("Hello");
}
}
public class MyAddIn : StandardOleMarshalObject, IDTExtensibility2
{
public void OnConnection(object application, ext_ConnectMode connectMode,
object addInInst, ref Array custom)
{
_service = new MyService();
((COMAddIn)addInInst).Object = _service;
}
//Rest of the IDTExtensibility2 implementation
}
public class Test
{
public static void Main(string[] args)
{
Application app = new Application();
app.Visible = true;
COMAddIn addIn = app.COMAddIns.Item("MyAddin");
IService service = addIn.Object as IService;
if (service != null)
service.Hello(); // <-- RemotingException happening here
}
}
So I found a workaround for my problem that is acceptable and works perfectly with .NET2.0. I don't find it as elegant as it could have been, but it works. I'm using a little hidden "proxy" window that lets me marshal calls made from an out-of-proc client to the UI thread of Word. I'm not planning to have many methods exposed through COM so the extra lines of code won't be a problem. I've added the important pieces of code below.
/// <summary>
/// HiddenForm can be used to marshal calls to the UI thread but is not visible
/// </summary>
public class HiddenForm : Form
{
public HiddenForm()
{
//Making a dummy call to the Handle property will force the native
//window handle to be created which is the minimum requirement for
//InvokeRequired to work.
IntPtr hWnd = Handle;
}
}
/// <summary>
/// AddInService will be exposed through the Object property of the AddIn but does NOT derive
/// from StandardOleMarshalObject but instead uses a <see cref="HiddenForm"/> to marshal calls
/// from an arbitrary RPC thread to the UI thread.
/// </summary>
public class AddInService : IAddInService
{
private readonly Form _invokeForm;
public AddInService()
{
//create an instance of the HiddenForm which allows to marshal COM
//calls to the UI thread.
_invokeForm = new HiddenForm();
}
public void HelloOutOfProc()
{
if(_invokeForm.InvokeRequired)
{
_invokeForm.Invoke(
new Action<object>(o => HelloOutOfProc()), new object()); //not really elegant yet but Action<> was the only "out of the box" solution that I could find
}
else
{
MessageBox.Show("HelloOutOfProc on thread id " + Thread.CurrentThread.ManagedThreadId);
}
}
}
/// <summary>
/// AddIn Class which DOES derive from StandardOleMarshalObject so it's executed on the UI thread
/// </summary>
public class Connect : StandardOleMarshalObject, IDTExtensibility2
{
private IAddInService _service;
public void OnConnection(object application, ext_ConnectMode connectMode,
object addInInst, ref Array custom)
{
//create service object that will be exposed to out-of-proc processes
_service = new AddInService();
//expose AddInService through the COMAddIn.Object property
((COMAddIn)addInInst).Object = _service;
}
}
Tested on Window 7, Office 2007. Hope this helps others.
I do still like to know WHY it's working in .NET4.0 and not .NET2.0. So if anyone has a answer to this, it is still appreciated.

Categories

Resources