How to convert a C++ class into a .NET object? - c#

We have a C# programmer that wants a .NET object to do all the underlying work. It should basically be a black box with functions and events.
I had written all this with C++ Builder, using non-visual VCL classes and now it seems like I have to make a .NET object out of it.
I need a simple example of how to create a .NET "box" with one function and one event handler and from there I should be able to implement the rest of it. Should I do this in a COM object? What technology should I use?
Example C++ side.
typedef void __fastcall (__closure *TIntEvent)(int Status);
typedef void __fastcall (__closure *TVoidEvent)(void);
typedef void __fastcall (__closure *TResultEvent)(String cmd, int code);
typedef void __fastcall (__closure *TModeEvent)(int mode, int reason);
class TDevice : public TObject {
private:
// properties
String FPortName;
String FDevice;
String FComment;
String FID;
double FBootware;
double FFirmware;
protected:
public:
// properties
__property String PortName = { read=FPortName };
__property String Device = { read=FDevice };
__property String Comment = { read=FComment };
__property String ID = { read=FID };
__property double Bootware = { read=FBootware };
__property double Firmware = { read=FFirmware };
// event function pointers
TModeEvent OnMode;
TIntEvent OnStatus;
TIntEvent OnSensors;
TVoidEvent OnInfo;
TResultEvent OnResult;
// public interface
bool Connect(void);
void Disconnect(void);
void Reset(void);
void Boot(void);
void GetInfo(void);
void GetTag(void);
};
I have removed all the internal stuff and only left exposed functions, events and properties that should be possible to reach from C#.
From this class I need to create a .NET object like this:
MyLib.IDevice.Connect();
MyLib.IDevice.Disconnect();
MyLib.IDevice.Reset();
MyLib.IDevice.Boot();
MyLib.IDevice.GetInfo();
MyLib.IDevice.GetTag();
I also need C# to connect a function to the Event handlers in the C++ class.
MyLib.IDevice.OnMode = CSharpEventHandler1;
MyLib.IDevice.OnStatus = CSharpEventHandler2;
MyLib.IDevice.OnSensors = CSharpEventHandler3;
MyLib.IDevice.OnInfo = CSharpEventHandler4;
MyLib.IDevice.OnResult = CSharpEventHandler5;
These event handlers are called inside the C++ class to fire the events like this:
if(OnMode != NULL)
{
OnMode(FMode,FReason);
}
There are also a few properties, but these are easy to impalement in a COM interface (if this is what we need)...
Since this is written in C++ Builder and C++ builder can write components (for C++ Builder and Delphi, using ActiveX technology), maybe it is possible to convert a C++ Builder component library into a .Net object/component?
EDIT:
To make it even more clear...
The MyLib.IDevice.Connect() is what I want C# to see... The list of functions are the C++ functions as in a .Net object MyLib with an interface IDevice.
So assuming I have created an instance of MyLib.IDevice as Device, I can call Device.Connect(); from C#.

It is hard... And ugly... The simplest solution is probably to create a C interface:
extern "C"
{
__declspec(dllexport) __stdcall TDevice* NewDevice()
{
return new TDevice();
}
__declspec(dllexport) void __stdcall DeleteDevice(TDevice *pDevice)
{
delete pDevice;
}
__declspec(dllexport) bool __stdcall ConnectDevice(TDevice *pDevice)
{
return pDevice->Connect();
}
.. and so on
}
In C#:
[DllImport("YourDll.dll", CallingConvention = CallingConvention.Stdcall)]
public static extern IntPtr NewDevice();
[DllImport("YourDll.dll", CallingConvention = CallingConvention.Stdcall)]
public static extern void DeleteDevice(IntPtr pDevice);
[DllImport("YourDll.dll", CallingConvention = CallingConvention.Stdcall)]
public static extern bool ConnectDevice(IntPtr pDevice);
... and so on
If you are ok with this, we can begin talking about passing delegates... and it will be a pain, trust me :-)
Uff... It was quite long... C++ side it is better if you create a wrapper for your class. This because you are using __fastcall __closure for your events. Both of these modifiers are incompatible with C#, so you "proxy" them in the wrapper.
// __fastcall not handled by C#
typedef void __stdcall (*TIntEventFunc)(int Status);
typedef void __stdcall (*TVoidEventFunc)(void);
typedef void __stdcall (*TResultEventFunc)(const wchar_t *cmd, int code);
typedef void __stdcall (*TModeEventFunc)(int mode, int reason);
class TDeviceWrapper {
public:
// You could even use directly a TDevice Device, depending on how your program works.
// By using a TDevice *, you can attach the wrapper to a preexisting TDevice.
TDevice *PDevice;
TModeEventFunc OnModeFunc;
TIntEventFunc OnStatusFunc;
TIntEventFunc OnSensorsFunc;
TVoidEventFunc OnInfoFunc;
TResultEventFunc OnResultFunc;
void __fastcall OnStatus(int status) {
OnStatusFunc(status);
}
void __fastcall OnResult(String cmd, int code)
{
OnResultFunc(cmd.c_str(), code);
}
};
extern "C" {
__declspec(dllexport) TDeviceWrapper* __stdcall NewDevice()
{
auto pWrapper = new TDeviceWrapper();
pWrapper->PDevice = new TDevice();
return pWrapper;
}
__declspec(dllexport) void __stdcall DeleteDevice(TDeviceWrapper *pWrapper)
{
delete pWrapper->PDevice;
delete pWrapper;
}
__declspec(dllexport) const wchar_t* __stdcall GetPortName(TDeviceWrapper *pWrapper)
{
return pWrapper->PDevice->PortName.c_str();
}
__declspec(dllexport) bool __stdcall Connect(TDeviceWrapper *pWrapper)
{
return pWrapper->PDevice->Connect();
}
__declspec(dllexport) void __stdcall SetStatus(TDeviceWrapper *pWrapper, TIntEventFunc statusFunc) {
pWrapper->OnStatusFunc = statusFunc;
if (statusFunc) {
pWrapper->PDevice->OnStatus = pWrapper->OnStatus;
} else {
pWrapper->PDevice->OnStatus = nullptr;
}
}
__declspec(dllexport) void __stdcall SetResult(TDeviceWrapper *pWrapper, TResultEventFunc resultFunc) {
pWrapper->OnResultFunc = resultFunc;
if (resultFunc) {
pWrapper->PDevice->OnResult = pWrapper->OnResult;
} else {
pWrapper->PDevice->OnResult = nullptr;
}
}
}
Then C#-side you have to create another wrapper :-) This time because when you pass a delegate C#->C++, the .NET creates a "thunk", but if you don't save the delegate somewhere, this "thunk" gets garbage collected. So the easiest solution is normally to create a wrapper class where you can save the used delegates. You can even incapsulate the Dispose() pattern in this wrapper :-)
public class TDeviceWrapper : IDisposable
{
// Fastcall not handled by C#
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void TIntEventFunc(int Status);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void TVoidEventFunc();
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public delegate void TResultEventFunc(string cmd, int code);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void TModeEventFunc(int mode, int reason);
IntPtr ptr;
[DllImport("TDevice.dll")]
static extern IntPtr NewDevice();
[DllImport("TDevice.dll")]
static extern void DeleteDevice(IntPtr pWrapper);
[DllImport("TDevice.dll")]
static extern IntPtr GetPortName(IntPtr pWrapper);
[DllImport("TDevice.dll")]
static extern void Connect(IntPtr pWrapper);
[DllImport("TDevice.dll")]
static extern void SetStatus(IntPtr pWrapper, TIntEventFunc statusFunc);
[DllImport("TDevice.dll")]
static extern void SetResult(IntPtr pWrapper, TResultEventFunc resultFunc);
// To prevent the GC from collecting the managed-tounmanaged thunks, we save the delegates
TModeEventFunc modeFunc;
TIntEventFunc statusFunc;
TIntEventFunc sensorsFunc;
TVoidEventFunc infoFunc;
TResultEventFunc resultFunc;
public void Init()
{
ptr = NewDevice();
}
public string PortName
{
get
{
// Important! .NET will try to free the returned
// string if GetPortName returns directly a string.
// See for example https://limbioliong.wordpress.com/2011/06/16/returning-strings-from-a-c-api/
IntPtr ptr2 = GetPortName(ptr);
return Marshal.PtrToStringUni(ptr2);
}
}
public void Connect()
{
Connect(ptr);
}
public void SetStatus(TIntEventFunc statusFunc)
{
this.statusFunc = statusFunc;
SetStatus(ptr, statusFunc);
}
public void SetResult(TResultEventFunc resultFunc)
{
this.resultFunc = resultFunc;
SetResult(ptr, resultFunc);
}
~TDeviceWrapper()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (ptr != IntPtr.Zero)
{
DeleteDevice(ptr);
ptr = IntPtr.Zero;
}
if (disposing)
{
modeFunc = null;
statusFunc = null;
sensorsFunc = null;
infoFunc = null;
resultFunc = null;
}
}
}
Then you can, for example:
public class MyClass
{
public void StatusEvent(int status)
{
Console.WriteLine("Status: {0}", status);
}
public void ResultEvent(string cmd, int code)
{
Console.WriteLine("Resukt: {0}, {1}", cmd, code);
}
}
and
var mc = new MyClass();
using (var wrapper = new TDeviceWrapper())
{
wrapper.Init();
wrapper.SetStatus(mc.StatusEvent);
wrapper.SetResult(mc.ResultEvent);
wrapper.Connect();
}

Related

Using an object as the parameter of an external function in C#

Let's say I have a timer object in C#:
public class Timer {
private int currentTime;
private int lastTime;
public int GetTimePassed() {
}
}
Is it possible to use this object as a parameter in an external function? Like so:
public class Program {
[DllImport("example.dll"), CallingConvention = CallingConvention.Cdecl]
extern void ExampleFunction(Timer arg);
}
#include <stdio.h>
extern "C" {
__declspec(dllexport) void ExampleFunction(Timer arg) {
}
}

How to fix 'EntryPointNotFoundException'

I'm trying to import external c++ methods into my C# code.
I have modified a Windows driver which I'm using to access memory. To invoke the driver, I'm using c++ interface. Finally, to invoke the the interface connecting me to the driver, I use C# code.
The problem I'm facing is that during the runtime, I get following error System.EntryPointNotFoundException: Unable to find an entry point named 'GetTargetPid' in DLL 'API.dll'.
Now, The interface itself consists only of single header file. I thought that maybe that is the problem, however from what I've read online, using single header file even for implementation is perfectly fine.
This is my import in C#
[DllImport("API.dll")]
public static extern IntPtr GetTargetPid();
and here I Invoke the method
IntPtr processID = IntPtr.Zero;
...
ProcessID = GetTargetPid();
So my C# code is nothing special.
Now here is my API.dll
extern "C"
{
...
class CDriver
{
public:
//Handle to the driver
HANDLE hDriver;
//Initialization of the handle
CDriver::CDriver(LPCSTR RegistryPath)
{
hDriver = CreateFileA(RegistryPath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
}
...
__declspec(dllexport)
ULONG_PTR GetTargetPid()
{
if (hDriver == INVALID_HANDLE_VALUE)
return false;
PVOID Id = 0;
ULONG_PTR Result;
DWORD Bytes;
if (DeviceIoControl(hDriver, IO_GET_PROCESS_ID, NULL, NULL,
Id, sizeof(Id), &Bytes, NULL)) {
Result = (ULONG_PTR)Id;
return Result;
}
else
return false;
}
Most of the examples I'v read online are using static methods, is that of any importance? what I need is working import, i think this should be trivial, however I can't figure it out.
You have two problems. First problem __declspec(dllexport) ULONG_PTR GetTargetPid() compiles just fine and exports CDriver::GetTargetPid. You don't want that.
In reading your CDriver code I'm convinced that it's not a singleton. If you really want to P/Invoke:
extern "C" {
__declspec(dllexport)
CDriver *CreateCDriver(LPCSTR RegistryPath)
{
return new CDriver(RegistryPath);
}
__declspec(dllexport)
ULONG_PTR GetTargetPid(CDriver *driver)
{
return driver->GetTargetPid();
}
__declspec(dllexport)
CDriver *DestroyCDriver(CDriver *driver)
{
delete driver;
}
} // extern "C"
Second problem: you are P/Invoking a C function. Need Cdecl declarations in C#:
[DllImport("API.dll", CallingConvention=Cdecl, CharSet=CharSet.????)]
public static extern IntPtr CreateCDriver(string name);
[DllImport("API.dll", CallingConvention=Cdecl)]
public static extern IntPtr GetTargetPid(IntPtr cdriver);
[DllImport("API.dll", CallingConvention=Cdecl)]
public static extern IntPtr DestroyCDriver(IntPtr cdriver);
I can't tell from your code whether you compile ANSI or Unicode; fill in CharSet.???? correctly.
The usage of this stuff is like this:
IntPtr cdriver = null;
try {
cdriver = CreateCDriver("whatever");
var pid = GetTargetPid(cdriver);
// do whatever with pid
} finally {
DestroyCDriver(cdriver);
}
The moment you have to move a cdriver reference off the stack you need Dispose() and Finalize().
internal class CDriver : IDisposable {
private IntPtr cdriver;
public CDriver(string registry)
{
cdriver = CreateCDriver("whatever");
}
public void Dispose()
{
Dispose(true);
GC.SupressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
DestroyCDriver(cdriver);
cdriver = IntPtr.Zero;
}
}

typedef equivalent in C# to use C++ DLL

I'm trying to call a C++ structure, exported to a DLL, from C#-Code
This is the C++ interface to the Method I want to call:
typedef void *Handle;
typedef void (*Callback)(Info *info);
typedef void (*Timeout)(Info *info);
typedef struct {
WORD port;
WORD flag;
char name[16];
} Info;
__declspec(dllexport) Handle open(Info *info, Callback c,
Timeout timeout);
This article teached me how to declare the info-struct in C#:
[StructLayout(LayoutKind.Explicit,
Pack=1,Size=36)]
public struct Info
{
[FieldOffset(0)]
public ushort port;
[FieldOffset(2)]
public ushort flag;
[FieldOffset(4)]
public char name;
}
Then I would import the Method in C#:
[DllImport ("MyDLL")] private static extern void Handle open(Info
*info, Callback c, Timeout timeout);
Then I'm stucked, because I don't know how to transfer the typedefs of Handle, Callback and Timeout to C#. Any suggestions?
It is quite complex... Try this... It will probably go boom but then you can tell me how it did go boom and I can help you:
public class MyDllhelper
{
[StructLayout(LayoutKind.Sequential)]
public unsafe struct Info
{
public ushort port;
public ushort flag;
public fixed byte name[16];
public unsafe string Name
{
get
{
fixed (byte* ptr = name)
{
IntPtr ptr2 = (IntPtr)ptr;
return Marshal.PtrToStringAnsi(ptr2, 16).TrimEnd('\0');
}
}
set
{
fixed (byte* ptr = name)
{
IntPtr ptr2 = (IntPtr)ptr;
byte[] bytes = Encoding.Default.GetBytes(value);
int length = Math.Min(15, bytes.Length);
Marshal.Copy(bytes, 0, ptr2, length);
ptr[length] = 0;
}
}
}
}
public VoidRefInfoDelegate C { get; set; }
public VoidRefInfoDelegate Timeout { get; set; }
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void VoidRefInfoDelegate(ref Info info);
[DllImport("MyDLL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr open(ref Info info, VoidRefInfoDelegate c, VoidRefInfoDelegate timeout);
public IntPtr Open(ref Info info, VoidRefInfoDelegate c, VoidRefInfoDelegate timeout)
{
C = c;
Timeout = timeout;
return open(ref info, C, Timeout);
}
}
Note that you'll have to do something like:
public void CMethod(ref MyDllhelper.Info info)
{
Console.WriteLine("C method called");
}
public void TimeoutMethod(ref MyDllhelper.Info info)
{
Console.WriteLine("Timeout method called");
}
var info = new MyDllhelper.Info();
info.Name = "012345678901234567890"; // Use Name, not name!
info.flag = 1;
info.port = 2;
var helper = new MyDllhelper();
IntPtr handle = helper.Open(ref info, CMethod, TimeoutMethod); // Use Open, not open!
You will need to compile the code with the Properties->Build->Allow unsafe code.
There are two or three interesting points in the code: the C array has been converted to a fixed byte array. I've added a getter/setter Name to handle the conversion from Ansi/ASCII to Unicode and back.
The C function has two callback methods (c and timeout). To use them, you need to "save" somewhere C#-side the delegates you'll use, because otherwise the garbage collector will free the delegates, and you'll receive an exception (see for example https://stackoverflow.com/a/6193914/613130). The C and Timeout properties are used for this.
Those typedefs are for callback functions that will be called from the open(..) method that you are calling. Each of those callback functions is going to take a *Info argument. See answers for calling C++ functions containing callbacks in C# for some examples of how those functions are declared. Of course, you're going to need to do more than just declare them; you're going to have to write the code for doing the work in those functions, too.

Will be C++ classes exported to C# deleted by the garbage collector?

The idea is to create and export a wrapper for the C++ class and then use it from C# like following:
First, let us create the C++ class itself:
File : MyClass.cpp
class myclass
{
public:
int funct(int val)
{
return val + 1;
}
~myclass(){}
};
Then, we create a wrapper:
File wrapper.cpp
extern "C" __declspec(dllexport) myclass* expConst()
{
return new myclass();
}
extern "C" __declspec(dllexport) void expDispose(myclass * obj)
{
delete obj;
}
extern "C" __declspec(dllexport) int expfunct(myclass* obj, int val)
{
return obj->funct(val);
}
Now, we come to c#:
public class CsClass : IDisposable
{
//Import the functions from dll
[DllImport("ExportedLib.dll")]
public static extern IntPtr expDispose(IntPtr obj);
[DllImport("ExportedLib.dll")]
public static extern IntPtr expConst();
[DllImport("ExportedLib.dll")]
public static extern int expfunct(IntPtr obj, int val);
IntPtr objPtr;
public CsClass()
{
objPtr = expConst();
}
public int funct(int q)
{
return expfunct(objPtr, q);
}
public void Dispose()
{
expDispose(objPtr);
}
}
Finally, we ecxecute this by
File:Program.cs
class Program
{
static void Main(string[] args)
{
CsClass v = new CsClass();
Console.WriteLine(v.Func(1));
}
}
I tested this simple things and the program printed 2 as it was expected.
The question is, whether the garbage collector of C# will move the created C++ object and, thus, making the objPtr to point to some wrong place in memory?
Are there any other principal obstacles here? I mean some unsolvable problems which make such an approach impossible.
Thanks in advance.
No, the garbage collector only goes to work for managed memory. Your class created in C++ is not managed memory and will not be touched, for good or for bad. You will need to manage it yourself as you already did.

How to make C (P/invoke) code called from C# "Thread-safe"

I have some simple C-code which uses a single global-variable. Obviously this is not thread-safe, so when I call it from multiple threads in C# using P/invoke, things screw up.
How can I either import this function separately for each thread, or make it thread-safe?
I tried declaring the variable __declspec(thread), but that caused the program to crash. I also tried making a C++/CLI class, but it doesn't allow member-functions to be __declspec(naked), which I need (I'm using inline-assembly). I'm not very experienced writing multi-threaded C++ code, so there might be something I'm missing.
Here is some example code:
C#
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SomeFunction(int parameter1, int parameter2);
C++
extern "C"
{
int someGlobalVariable;
int __declspec(naked) _someFunction(int parameter1, int parameter2)
{
__asm
{
//someGlobalVariable read/written here
}
}
int __declspec(dllexport) SomeFunction(int parameter1, int parameter2)
{
return _someFunction(parameter1, parameter2);
}
}
[Edit]: The result of SomeFunction() must go in some prescribed order based on someGlobalVariable (think of eg. a PRNG, with someGlobalVariable as the internal state). So, using a mutex or other sort of lock is not an option - each thread must have its own copy of someGlobalVariable.
A common pattern is to have
a function that allocates memory for the state,
a function that has no side-effects but mutating the passed-in state, and
a function that releases the memoy for the state.
The C# side would look like this:
Usage:
var state = new ThreadLocal<SomeSafeHandle>(NativeMethods.CreateSomeState);
Parallel.For(0, 100, i =>
{
var result = NativeMethods.SomeFunction(state.Value, i, 42);
Console.WriteLine(result);
});
Declarations:
internal static class NativeMethods
{
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern SomeSafeHandle CreateSomeState();
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SomeFunction(SomeSafeHandle handle,
int parameter1,
int parameter2);
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int FreeSomeState(IntPtr handle);
}
SafeHandle magic:
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
internal class SomeSafeHandle : SafeHandle
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public SomeSafeHandle()
: base(IntPtr.Zero, true)
{
}
public override bool IsInvalid
{
get { return this.handle == IntPtr.Zero; }
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.FreeSomeState(this.handle) == 0;
}
}
You can either make sure what you only call _someFunction once at a time in your C# code or change the C code to wrap the access to the global variable in a synchronization primitive like a critical section.
I would recommend changing the C# code rather than the C code, as the C# code is multi-threaded, not the C code.
Personally if the C code was to be called elsewhere I would use a mutex there. If that doesn't float your boat you can lock in .Net quite easily:
static object SomeFunctionLock = new Object();
public static int SomeFunction(int parameter1, int parameter2){
lock ( SomeFunctionLock ){
return _SomeFunction( parameter1, parameter2 );
}
}
[DllImport("MyDll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int _SomeFunction(int parameter1, int parameter2);
[Edit..]
As pointed out, this serializes access to the function which you can't do yourself in this case. You have some C/C++ code that (wrongly IMO) uses a global for state during the call to the exposed function.
As you have observed that the __declspec(thread) trick doesn't work here then I would try to pass your state/context back and forth as an opaque pointer like so:-
extern "C"
{
int _SomeOtherFunction( void* pctx, int p1, int p2 )
{
return stuff;
}
// publically exposed library function
int __declspec(dllexport) SomeFunction(int parameter1, int parameter2)
{
StateContext ctx;
return _SomeOtherFunction( &ctx, parameter1, parameter2 );
}
// another publically exposed library function that takes state
int __declspec(dllexport) SomeFunctionWithState(StateContext * ctx, int parameter1, int parameter2)
{
return _SomeOtherFunction( ctx, parameter1, parameter2 );
}
// if you wanted to create/preserve/use the state directly
StateContext * __declspec(dllexport) GetState(void) {
ctx = (StateContext*) calloc( 1 , sizeof(StateContext) );
return ctx;
}
// tidy up
void __declspec(dllexport) FreeState(StateContext * ctx) {
free (ctx);
}
}
And the corresponding C# wrapper as before:
[DllImport("MyDll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int SomeFunction(int parameter1, int parameter2);
[DllImport("MyDll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int SomeFunctionWithState(IntPtr ctx, int parameter1, int parameter2);
[DllImport("MyDll", CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr GetState();
[DllImport("MyDll", CallingConvention = CallingConvention.Cdecl)]
internal static extern void FreeState(IntPtr);
The good news, you can create a __declspec(naked) function as a member of C++ (non-CLI) class:
class A {
int n;
public:
A() { n = 0; }
void f(int n1, int n2);
};
__declspec(naked) void A::f(int n1, int n2)
{
n++;
}
The bad news, you will need COM to be able to use such class. That's right: asm wrapped in C++, wrapped in COM, wrapped in RCW, wrapped in CLR...

Categories