(c++/cli) C++ using C# dll to get any enum member name - c#

I'm using VS2010, I'm try to use a C# dll to get any enum member name in C++,
My C# dll source code:
namespace CSharpFuncion
{
public class CSFun
{
public string GetEnumName(Enum en)
{
return Enum.GetName(typeof(Enum), en);
}
}
}
My C++ code
#using "CSharpFuncion.dll"
using namespace CSharpFuncion;
CSFun ^ csFun = gcnew CSFun;
cout << csFun->GetEnumName(MyTestEnum::E_A) << endl;
Error message:
cannot convert parameter from 'MyTestEnum' to 'System::Enum ^'
How can I fix it?

Rather than
public enum MyTestEnum
{
E_A = 1,
E_B = 2
};
You need to make it
public enum class MyTestEnum
{
E_A = 1,
E_B = 2
};
So just add the class keyword.
And change return Enum.GetName(typeof(Enum), en); to return en.ToString()

you have to give Enum.GetName(typeof(MyTestEnum ), 1); to get the name of value (E_A) in that enum

Related

Converting std::array to C# array using SWIG

I'm trying to wrap a C++ class using std::array. In C# I'd like to use this std::array as a normal array. The C++ class could look like this:
#pragma once
#include <array>
struct Data
{
int member1, member2;
};
class TestClass
{
public:
std::array<Data, 2> GetExampleArray() {
Data item1;
Data item2;
item1.member1 = 0; // Initialize with some boring data
item1.member2 = 1;
item2.member1 = 3;
item2.member2 = 4;
return { item1, item2 };
}
};
Usage in C# would be as follows:
class Program
{
static void Main(string[] args)
{
TestClass testClass = new TestClass();
Data myData = testClass.GetExampleArray()[0];
Console.WriteLine(myData.member1);
}
}
My first thought was "Let's pass a pointer to C# using typemaps!" until I realized that this is no C-style array and even if it was I wouldn't be able to pass the length.
So my question is: Which steps can I take to get its data into a C# array?

Visual Studio 2003 C#, struct compiling erro

I have a problem with struct during compilation. I program in c# and use Visual Studio 2003. From MSDN:
When you create a struct object using the new operator, it gets created and the appropriate constructor is called. Unlike classes, structs can be instantiated without using the new operator. If you do not use new, the fields will remain unassigned and the object cannot be used until all of the fields are initialized.
You can instantiate a struct without new() statement; on my pc it works perfectly while on another pc I see compiling errors (new() required).
Is there some filter or flag on the Visual studio's environment (like TreatWarningsAsErrors) that can generate this behavior?
an example:
using System;
using System.Collections;
namespace myApp.Utils
{
....
public struct StructParam
{
public int iIndex;
public int[] iStartNoteArray;
public int[] iFinalNoteArray;
public int[] iDimension;
public int[] iStartSequence;
public ArrayList m_iRowIncValueArray;
};
....
}
--------------------------------------------------------------
--------------------------------------------------------------
using System;
using System.Collections;
using myApp.Utils;
namespace myApp.Main
{
....
public class frmMain : System.Windows.Forms.Form
{
....
static void Main()
{
....
StructParam oStructParam;
oStructParam.iIndex = 0;
oStructParam.iStartNoteArray = new int[]{0, 0};
oStructParam.iFinalNoteArray = new int[]{0, 0};
oStructParam.iDimension = new int[]{0, 0};
oStructParam.iStartSequence = new int[]{0, 0};
oStructParam.m_iRowIncValueArray = new ArrayList();
ArrayList myArray = new ArrayList();
myArray.Add(oStructParam);
....
}
.....
}
....
}
I don't think the problem is in code but in some Visual Studio's environment variable.
To use a struct without calling new, you must assign all its members first.
For example,
struct Point
{
public int x;
public int y;
public int DoSomething() { return x * y; }
}
Point p;
p.x = 1;
p.y = 2;
p.DoSomething();
Notice x and y here are fields, NOT properties. You must assign all fields before making use of the struct. If you were to include an auto-property, for example, where you didn't have access to the underlying field, then it would not be possible.

Automapper - Mapping Entity to Enum

I'm trying to map an entity to a enum. As I was searching for a source I found this:
using Should;
public enum OrderStatus : short
{
InProgress = 0,
Complete = 1
}
public enum OrderStatusDto
{
InProgress = 0,
Complete = 1
}
[Test]
public void Example()
{
Mapper.Map<OrderStatus, OrderStatusDto>(OrderStatus.InProgress)
.ShouldEqual(OrderStatusDto.InProgress);
Mapper.Map<OrderStatus, short>(OrderStatus.Complete).ShouldEqual((short)1);
Mapper.Map<OrderStatus, string>(OrderStatus.Complete).ShouldEqual("Complete");
Mapper.Map<short, OrderStatus>(1).ShouldEqual(OrderStatus.Complete);
Mapper.Map<string, OrderStatus>("Complete").ShouldEqual(OrderStatus.Complete);
}
but I think this works for only enum-to-enum mapping. because when I try to use .ShouldEqual, intellisense can't find it. In that codeblock, there is a reference that's called Should but I couldn't find its reference anywhere.
Any ideas about how to use automapper to map between enum and entity/class?
Any ideas about using Should?
#I updated the question because without seeing the actual code, it's harder to consider a solution. Here is the code snippet that might be needed:
public class ParameterEnum
{
/// <summary>
/// Enum Sayisi: 2650, Son Guncelleme Tarihi: 21.2.2013 09:40:37
/// </summary>
public enum Parameters : int
{
...
IsEmriTuruIsTalebi = 138,
<summary>
Adi: Kalite Öneri; ID: 2218; Seviyesi: 3; Aciklamasi: ; Aktif Mi: True
</summary>
...}}
and this is where normal mapping done:
isEmriEntity.IsEmriTuruId = (int)ParameterEnum.Parameters.IsEmriTuruIsTalebi;
You should look into ITypeConverter. Something like this should do the job:
Mapper.CreateMap<OrderStatus, OrderStatusDto>().ConvertUsing(new OrderStatusConverter());
and your converter would look like so:
public class OrderStatusConverter: ITypeConverter<OrderStatus, OrderStatusDto>
{
public OrderStatusDto Convert(OrderStatus source)
{
return (OrderStatusDto)source;
}
}
That should be enough to apply the same approach to any other cross-type mappings in your DTOs.
EDIT:
On your enum conversion error, using this as an example for clarity (an enum is not a DTO):
public enum ExampleEnum : short
{
SomeValue,
SomeOtherValue,
BigValue = 100,
}
public enum AnotherEnum
{
Foo,
Bar,
}
This should make the enum conversion clearer (don't cast to int at all).
private void Test()
{
// Casting to int only works when the value is 0
// This works (SomeValue = 0)
AnotherEnum example = (int) ExampleEnum.SomeValue;
// This won't even compile (SomeOtherValue = 1)
AnotherEnum example2 = (int) ExampleEnum.SomeOtherValue;
// Casting to another enum works fine
AnotherEnum example2 = (AnotherEnum) ExampleEnum.SomeOtherValue;
// Just be careful of values that don't exist in the target enum
// This will compile even though it won't work at run-time (BigValue = 100)
AnotherEnum example2 = (AnotherEnum) ExampleEnum.BigValue;
}

Cannot Add class in Enum.Extensions namespace, because Enum type (System) is then inavailable

I have two projects.
1) One (library) that contains Enum extension methods in namespace:
namespace Enum.Extensions
{
public static class EnumerationExtensions
{
public static bool Has<T>(this System.Enum type, T value)
{
try
{
return (((int)(object)type & (int)(object)value) == (int)(object)value);
}
catch
{
return false;
}
}
}
}
2) Second, Console Applications which has a reference to the library above and tries to use
its new methods:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Enum.Extensions;
namespace XMLExtensionsTest
{
public enum ProcesInfo
{
ifCreate = 1,
ifRun1 = 2,
IfRun2 = 4,
IFRun3 = 8
}
class Program
{
static void Main(string[] args)
{
ProcesInfo enumInfo = ProcesInfo.ifCreate;
enumInfo = enumInfo.Add(ProcesInfo.IfRun2);
bool value = enumInfo.Has(ProcesInfo.ifCreate);
bool value2 = enumInfo.Has(ProcesInfo.ifRun1);
bool value3 = enumInfo.Has(ProcesInfo.IfRun2);
bool value4 = enumInfo.Has(ProcesInfo.IFRun3);
}
}
}
Now, because of that Extensions class all standard Enum types are not accessible.
i cannot write:
public void Test(Enum test)
{
}
but need:
public void Test(System.Enum test)
{
}
There are thousands of places where Enum is used without "System".
How to add Extensions class without touching existing Enum class calls?
Thanks!
You can do any one of the following three options, #3 is your best bet if you do not/cannot change the namespace
Rename your Enum.Extensions name space
Prefix it with something like MyStuff.Enum.Extensions
Alias it like using MyAlias = Enum.Extensions
You will need to change the namespace of the Enum Library. Which is your first library project having Extensions.
Enum is the Type name and you are using it as a namespace and hence there is ambiguity.

passing an array of structs from c# to C++ using com callable wrapper

Consider the code below that is meant to be accessed by C++ using com
namespace MarshalLib
{
//define an interface for account services
[ComVisible(true)]
[Guid("39B8A693-79BB-4638-92DE-245A88720953")]
public interface IAccountStructLookup
{
AccountStruct RetrieveAccount(int acctId);
void UpdateBalance(ref AccountStruct account);
Alias[] GetRef();
}
//Implement an account struct
[ComVisible(true)]
[Guid("DB48C5B6-9646-491A-B030-C0CADCFC03E0")]
public struct AccountStruct
{
public int AccountId;
[MarshalAs(UnmanagedType.BStr)]
public string AccountName;
[MarshalAs(UnmanagedType.Currency)]
public decimal Balance;
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
//[MarshalAs(UnmanagedType.SafeArray)]
//public Alias[] Aliases;
}
[ComVisible(true)]
[Guid("9829CAB3-4020-47EA-BE72-86EC7CFFAE1D")]
public struct Alias
{
public string Name;
}
//implement a class to provide account services
//using an AccountStruct
[ComVisible(true)]
[Guid("CEFE5CAA-5C7E-464F-8020-E0FC78180D9B")]
[ClassInterface(ClassInterfaceType.None)]
public class DniNetStructsObj : IAccountStructLookup
{
public AccountStruct RetrieveAccount(int acctId)
{
AccountStruct result = new AccountStruct();
if (acctId == 123)
{
result.AccountId = acctId;
result.AccountName = "myAccount";
result.Balance = 1009.95M;
//result.Aliases = new Alias[5];
//result.Aliases[0].Name = "1";
//result.Aliases[1].Name = "2";
//result.Aliases[2].Name = "3";
//result.Aliases[3].Name = "4";
//result.Aliases[4].Name = "5";
}
return result;
}
public void UpdateBalance(ref AccountStruct account)
{
//update the balance
account.Balance += 500.00M;
}
public Alias[] GetRef( )
{
Alias[] al= new Alias[2];
al[0].Name = "1";
al[1].Name = "2";
return al;
}
}
And the C++ side of things
#include "stdafx.h"
#include "ConsoleApplication1.h"
#import "D:\Source Code\MarshalLib\MarshalLib\bin\Debug\MarshalLib.tlb" raw_interface_only
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// The one and only application object
CWinApp theApp;
using namespace std;
using namespace MarshalLib;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
try
{
CoInitialize(NULL);
IAccountStructLookupPtr api(__uuidof(DniNetStructsObj));
api->GetRef();
CoUninitialize();
}
catch (...)
{
}
}
}
else
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}
I get an error when I call api-GetRef() to get an array of structs. Please help me return an array of structs from c# and use it in c++.
thanks in advance.
The problem with returning the array is that in the C++ you will see a pointer to struct and have no information about array size. You can try to marshal it as a SAFEARRAY, but IMO, SAFEARRAYs are pain in the neck.
I prefer to model it as this:
[ComVisible(true)]
[Guid("C3E38106-F303-46d9-9EFB-AD8A8CA8644E")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct MyStruct
{
public int Value;
// I marshal strings as arrays! see note at the bottom
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string Unit
}
[ComVisible(true),
Guid("BD4E6810-8E8C-460c-B771-E266B6F9122F"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
]
public interface IMyService
{
int GetData([MarshalAs(UnmanagedType.LPArray)] out MyStruct[] data);
}
The client code is like this:
Lib::MyStruct* data;
long size = svc->GetData(&data);
for(size_t i = 0; i < size; ++i)
{
Lib::MyStruct& current = data[i];
long val = current.Value;
bstr_t unit = current.Unit;
// ...
}
// now you need to release the memory. However, if you marshal
// strings in struct as BSTRs, you need to first release them by
// calling SysFreeString. This is why I prefer to marshal strings
// as arrays whenever I can: you can still easily construct a bstr_t
// in your client code, but you don't need to release them explicitly
CoTaskMemFree(data);
With regard to comment about SAFEARRAYs: they are required only if the interface must be automation compliant i.e. late-bound i.e. an IDispatch interface i.e. marked as ComInterfaceType.InterfaceIsIDispatch. If this is not the case (and I declared the interface as custom i.e. ComInterfaceType.InterfaceIsIUnknown) using the standard arrays is perfectly fine and they are equally well supported as SAFEARRAYs. Furthermore, working with SAFEARRAYs of custom structs brings some additional complexity which I prefer to avoid. If you don't need late binding, there is no reason to fight with SAFEARRAYs.
With regard to CComSafeArray, as documented, it doesn't support VT_RECORD which is required to support arrays of structs (another option is to marshal it as VT_VARIANT with IRecordInfo but I won't even go into that).
You first need to expose your managed code via an interface and register it using regasm and create type library (tlb file). Then you can use this in your unmanaged code.
Refer to this article: http://blogs.msdn.com/b/deeptanshuv/archive/2005/06/26/432870.aspx

Categories