MFC Object serialization in C# - c#

I am trying to read a binary file in C# which has been written actually using CArchive. I have done most of the part but stuck in reading an object. Instead of writing bool, int, double object has been written into binary.
http://msdn.microsoft.com/en-us/library/3bfsbt0t(v=vs.110).aspx
So original code is something like this.
MyClass myObject;
if (archive.IsStoring()
archive << myObject;
else
archive >> myOjbect;
So question is how can I translate this piece of code in C#.
void Read(BinaryReader reader)
{
// Read MyClass object here.
}

You'll need to create a comparable C# object (you might want to use C++/CLI) and construct it from the file.
It would help if you specified what myObject is.

Related

How to create structure at runtime and convert byte[] pointer to created structure?

Usually we create structure at design time, create the object and assign the data at runtime. But I would like to create the structure at runtime.
I have the structure members and it's types as shown below.
Name, String
Age , Int32
Hobies[], sring[]
Height, float
temp[], byte[]
etc...
Now by using the above structure members, create the structure at runtime.
We will have the byte array which will contain the data. I should Marshal it and convert it into created structure using PointerToStructure or something else.
Thank you in advance.
If you really want to create a type at runtime, use System.Reflection.Emit to create types at runtime.
But if the code that need to access the structure is native code, you can just write the byte array to the pointer with Marshal.Copy and it works fine with the native code that handles it as a structure, as long as the memory structure matches. The native code would never check if a provided pointer to a memory block is a defined structure or something else, just accesses the members with pointer offsets.
Please comment the actual need, and I will edit the answer to give more detailed help if you need.

How to use a class defined in c# dll from c++ code

I have a dll that was written in c#, and I used this dll in my c++ code(exactly MFC). I can use dll function with return value int, string... But I need to use a function with return value c# class! I don't know what kind of data type in MFC for putting in the function's return value in c# dll. c# return value object is convert to _variant_t in MFC. Please help me. Thank you for reading my question
C# code (abstract)
[Guid(" - - - - ")]
public interface ITestClass
{
object Func();
}
[Guid(" - - - - ")]
public class TestClass : ITestClass
{
public object Func()
{
Project1.Class1 data = dataList[0];
return data ;
}
}
MFC code (abstract)
ITestClass *ptc = NULL;
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(CLSID_TestClass, NULL, CLSCTX_INPROC_SERVER, IID_ITestClass, reinterpret_cast<void**>(&ptc));
int sum = ptc->Sum(5, 30); // It is perfect
data = ptc->Func(); // I don't know what data type is
you will have to have same class defined in C++. It's kind of hard and may be buggy. So I would try with CLI.
Or there is a simpler way. Don't do that :)
Exept, use old, good mechanism, like:
int objectHandle = ptc->CreateObject();
int data = ptc->GetSomeIntData(objectHandle);
ptc->DoSomeOperation(objectHandle);
ptc->ReleaseObject(objectHandle);
The idea is that you don't have a class on C++ side. The object is created on C# side and has its unique object handle (it may be hashcode). You return this handle in CreateObject and on C# side you can store your object in a dictionary:
Dictionary<int, MyClass>
Then on C++ side you call functions with your objectHandle.
It's far more easier way to acomplish the same result.
But if you really want to use this class, you can try this:
- make sure that you C# lib is com compatible (Register for COM interop option)
- After compiling C# lib, there should be a tlb file. Import it in c++:
#import "path\to\lib.tlb"
next you can use it like this:
CoInitialize(NULL);
ClassNamespace::ITestClassPtr myClass(__uuidof(ClassNamespace::TestClass));
myClass->Func();
CoUninitialize();
You can also wrap all that functionality in C++ class. That of course creates more work and makes you have to keep two similar codes (real class and wrapper class). But may be more friendly to use.
If you want to return other class, you would have to do it in similar way. Create com interface, use it in c++ and return it in c#.

A List<Tuple<int, float>> in managed C++

I'm working on some software that is written in native C++ with a managed C++ wrapper and the user interface in C#. I need to pass some information from the native code all the way up to the interface. The best way I can think to pass my information is in a list of tuples. I understand that in the native C++ I need to use a list<tuple<..>> and that works fine. What I want to do now, is take that output in the wrapper, and return a List<Tuple<..>> which is the System::Collections::Generic::List and System::Tuple instead of the stl ones from the native. I know the lists are very different syntactically but that shouldn't be the issue. In the C# code a List<Tuple<..>> is accepted by the compiler but in the managed C++ code it is not. Am I doing this wrong/am I using the wrong data types? Any help would be awesome!
Try something like this:
using namespace System::Collections::Generic;
// A List<Tuple<int, float>> in managed C++
public ref class TupleTest
{
public:
static List<Tuple<int, float>^>^ GetTuple() {
List<Tuple<int, float>^>^ ret = gcnew List<Tuple<int,float>^>();
Tuple<int,float>^ t = gcnew Tuple<int,float>(5, 2.6);
ret->Add(t);
return ret;
}
};
Note: you could use Int32 and Single (or Double) instead of int/float if you like.
EDIT: Notice the ^ operators. Those denote C++/CLI reference types. You'll be using them a lot! (It's kinda like * for pointers in regular C++, but means GC'ed reference type)

VARIANT datatype of C++ into C#

What is equivalent of the VARIANT datatype of C++ in C#?
I have code in C++ which uses the VARIANT datatype. How can I convert that code in C#?
Well, there are actually two variant's in C++: boost::variant and COM variant. The solution follows more or less the same idea, but the former is more complex. I expect you mean to use the latter.
Let me first start by telling that this is something you just shouldn't use if possible. That said, this is how you do it :-)
Variants and interop
Variants are sometimes used in interop of if you need the byte representation to be the same.
If you're dealing with interop, make sure to check out the VariantWrapper class on MSDN and make it work like that.
Variants and porting considerations
Variants are mostly used in APIs, and usually like this:
void Foo(SomeEnum operation, Variant data);
The reason it's done like this in C++ is because there is no base object class and you therefore need something like this. The easiest way to port this is to change the signature to:
void Foo(SomeEnum operation, object data);
However, if you're porting anyway, you also seriously want to consider these two, since they are resolved at compile-time and can save you the big 'switch' that usually follows in method Foo:
void SomeOperation(int data);
void SomeOperation(float data);
// etc
Variants and byte consistency
In rare cases you need to manipulate the bytes themselves.
Essentially the variant is just a big union of value types wrapped in a single value type (struct). In C++, you can allocate a value type on the heap because a struct is the same as a class (well sort-of). How the value type is being used is just a bit important but more on that later.
Union simply means you are going to overlap all the data in memory. Notice how I explicitly noted value type above; for variant's this is basically what it's all about. This also gives us a way to test it - namely by checking another value in the struct.
The way to do this in C# is to use the StructLayout attribute in a value type, which basically works as follows:
[StructLayout(LayoutKind.Explicit)]
public struct Variant
{
[FieldOffset(0)]
public int Integer;
[FieldOffset(0)]
public float Float;
[FieldOffset(0)]
public double Double;
[FieldOffset(0)]
public byte Byte;
// etc
}
// Check if it works - shouldn't print 0.
public class VariantTest
{
static void Main(string[] args)
{
Variant v = new Variant() { Integer = 2 };
Console.WriteLine("{0}", v.Float);
Console.ReadLine();
}
}
C++ variant's can also be stored on the heap as I noted earlier. If you do this, you probably still want the memory signature to be the same. The way to do this is to box the Variant struct we build earlier by simply casing it to object.
This is a tricky question.
From C# 4, you can use dynamic to indicate that the type is known at run-time.
By my personal understanding, however, c++ requires the type known at compile time. Thus you might consider to use object, but object in C# is an existent type.
For the concept of multi-type, single value (AKA polymorphism) of VARIANT, you would not need to find a corresponding type in C#, just define your classes and interfaces. You can always reference an object as its interface which the class implements.
If you are porting the code, and to figure out a syntax that you can simply use in LHS and for the considering of the type is known at compile time, then use var.
When .NET implements a COM interface, just use VARIANT* instead.
Then bypass marshalling on the .NET receiving side by using a IntPtr type to receive the pointer.
public class ComVariant
{
[StructLayout(LayoutKind.Sequential)]
public struct Variant
{
public ushort vt;
public ushort wReserved1;
public ushort wReserved2;
public ushort wReserved3;
public Int32 data01;
public Int32 data02;
}
private Variant _variant;
private IntPtr _variantPtr;
public ComVariant(int variantPtr) : this(new IntPtr(variantPtr))
{
}
public ComVariant(IntPtr variantPtr)
{
_variant = (Variant)Marshal.PtrToStructure(variantPtr, typeof(Variant));
_variantPtr = variantPtr;
}
public VarEnum Vt
{
get
{
return (VarEnum)_variant.vt;
}
set
{
_variant.vt = (ushort)value;
}
}
public object Object
{
get
{
return Marshal.GetObjectForNativeVariant(_variantPtr);
}
}
}
then if you are accessing a VT_UNKNOWN pointing to a COM interface object instance, just
var variant = new ComVariant(variantPtr);
var stream = variant.Object as IStream; // will not be null if type is correct
var obj = variant.Object as IObj; // in general...
will do the trick, but pay attention not to use a newly allocated VARIANT and giving its ownership to the .NET implementation without deallocating it somewhere...
For more complex code you might read this article which also talks about memory management.
Let's take a step back. Sooner or later, we want the actual data in the VARIANT. A VARIANT is just a holder for meaningful data. Suppose we converted the VARIANT to some sort of Object in C# that had the variant type and some raw buffer under the .NET hood (e.g. .NET strings can expose the raw buffer). At that point, the VARIANT type would need to be determined from the object and the raw data converted or cast to the data type specified by the variant, and then create a new Object e.g. string/int/etc. from the raw data.
So, rather than worry about passing the VARIANT to C#, look at the variant data type and convert it in C++ to the actual data type and pass that to C#.
For example, if the VARIANT type is VT_INT, then get the int from the variant and can use something like:
VARIANT var;
Int^ returnInt = gcnew Int(var.intVal);
returnInt can be returned as an Out parameter from a C++ function in a C++ dll that can be called from C#. The C++ dll needs to use /clr option.
Function would look like:-
void ThisFunctionReturnsAnInt(Runtime::InteropServices::OutAttribute Int^ % returnIntValue)
{
VARIANT var;
Int^ returnInt = gcnew Int(var.intVal);
}
Can use similar approach for other data types. It's only natural, a VARIANT of VT_INT is really just like an int, it's not as if there's some major conversion going on, you're just taking the actual value out of the VARIANT at the time when you're interested in it as you would if you were passing a straight integer value from C++ to C#. You would still need to do the gcnew anyway.

Can a managed C++ assembly return an object to C#?

I'm writing a C# application that must read the video properties of video files. The only way I've found to do this is with the Microsoft Media Foundation which requires C++.
So far, I've made some progress:
I've created a managed C++ assembly which compiles to a DLL.
I can call it, with a parameter, from the C# code.
It executes and prints the video file properties.
What I would like to do next is have the DLL return an object of video properties (width, height, duration, etc.). Given I'm using C++ managed code, is there a simple way to define an object type and use it to pass data between C# and C++ or do I have to use the Marshal class?
Certainly! If you define a public object in your managed C++ (Also called C++/CLI):
public ref class MyManagedClass{
. . .
}
and then reference the dll from your c# project, you'll be able to use the object just like you had defined it in c#.
You can access C++ objects/dlls either by COM Interop or C++/CLI. Using C++/CLI you can create your own wrapper objects/classes which is directly usable in C#. Knowing both C++ and C#, the syntax will be somewhat familiar to you (and there are good resources online).
C++/CLI may require a bit more work as you need to write the CLI wrappers, but will keep things clearer in your C# code (my opinion).
This following article should get you started: Quick C++/CLI - Learn C++/CLI in less than 10 minutes
A more in-depth article: http://msdn.microsoft.com/en-us/magazine/cc163852.aspx
A code example (show casing the syntax) to make things more exciting, borrowed from above. Student is your C++ class, StudentWrapper is th CLI wrapper to be used in your C# code:
public ref class StudentWrapper
{
private:
Student *_stu;
public:
StudentWrapper(String ^fullname, double gpa)
{
_stu = new Student((char *)
System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(
fullname).ToPointer(),
gpa);
}
~StudentWrapper()
{
delete _stu;
_stu = 0;
}
property String ^Name
{
String ^get()
{
return gcnew String(_stu->getName());
}
}
property double Gpa
{
double get()
{
return _stu->getGpa();
}
}
};

Categories