I've searched through the other answers similar to this topic, but haven't found anything completely relevant. I'm trying to assign values to some enumerations in C#, using values that are marked as static const in a C++/CLI file, which are compiled into a DLL and referenced in the C# project. All of that works fine, except that it gives me the "The expression being assigned to 'XXX' must be constant", which I would expect, if the C++/CLI value wasn't a constant. My C++/CLI code is auto-generated from 3rd-party vendor provided files, so my options for changing that side are extremely limited.
Here's some excerpts:
The C++/CLI file:
public ref class SEVERE_LEVEL sealed {
public:
static const System::Int32 VALUE = 200;
private:
SEVERE_LEVEL() {}
};
And the C# file:
public enum LoggerLevel {
SevereLevel = SEVERE_LEVEL.VALUE // This gives the "must be constant" error
}
There are several different log levels, each defined in their own separate class in the C++/CLI file. I want to use the C# enum as a parameter type in some method calls to ensure only valid values are passed in. Any ideas how to make this work or suggestions on alternative designs?
The C++ const keyword doesn't map into anything in .NET.
C++/CLI adds new context-sensitive keywords to match the .NET functionality: initonly and literal.
If you use literal System::Int32 VALUE = 200; then it should work. There's no magic to make the C# compiler define enums using values that aren't marked "literal" in the .NET metadata.
Related
I'm building a C++/CLI DLL to be able to communicate a plain C++ DLL with a C# application. The plain C++ DLL is third party provided and I have no way to modify it.
That plain C++ DLL contains some member function templates, in the way:
plain C++ DLL header file:
class pureCPP
{
template<typename T>
void usefulFunctionA(T &b, T const &a)
{
/* Implementation of the function */
}
}
So my idea would be to reflect that in the CLI DLL header file:
CLI DLL header file:
public ref class CLI_DLL
{
template<typename T>
void usefulFunctionB(T &b, T const &a)
{
pureCppPtr->usefulFunctionA(b, a);
}
PureCPP *pureCppPtr;
}
And then in the C# executable for example simply call:
CLI_DLL cliDLL = new CLI_DLL;
double a, b;
cliDLL.usefulFunctionB<double>(a, b);
Is this doable? Or am I forced to simply instantiate overloads for every possible type of the function template?
I've read C# has something called generics, could I use that technique to achieve something like this? So far, every article I've found refers either to class templates (not just methods within them) or suggests to do explicit instantiation in the CLI of the desired types, which is what I'd like to avoid if possible (suppose each function can be used by 1000 different types...I guess it wouldn't be so nice to replicate the 1000 different instantiations).
I'm a completely newbie to C#, but AFAIU, passing arguments (in this case, a type) from a generic function to a template wouldn't be doable since the former are resolved at runtime while the latter is done at compile time, in which case I'd be forced to change the previous implementation to something like this:
CLI DLL header file:
public ref class CLI_DLL
{
/* Only define the template here */
template<typename T>
void usefulFunctionB(T &b, T const &a);
PureCPP *pureCppPtr;
}
CLI DLL source file:
/* Explicitly instantiate the template in the source file */
template<>CLI_DLL::usefulFunctionB<double>(double &A, double const &B)
{
pureCppPtr->usefulFunctionA<double>(b, a);
}
on so on for every type I need. The other way (template to generic) seems to be possible though, right?
(BTW, and as a side question, is it really necessary to explicit the type being called, "double" in this case? I've never really understood why in some cases, Visual Studio is not able to automatically deduct types from templates, as CLang or GCC are).
Which is what I'd really, REALLY liked to avoid, and instead, I'd love to be able to do something like the first code I exposed.
Thanks a lot in advance.
Keep getting the following error when trying to call a subroutine stored in a Fortran DLL from a C# console application: "An unhandled exception of type 'System.EntryPointNotFoundException' occurred in name.exe Additional information: Unable to find an entry point named 'Fortran_Subroutine' in DLL 'Fortran.dll'" Nearly all of the posts related to this error message pertain to C#/C++. The Fortran project has a post-build event that copies the DLL over to the C# project (CSharp_proj\bin\debug).
The Fortran code uses two calls to !DEC$, do they look OK?:
C
MODULE MF_DLL
C
CONTAINS
C
SUBROUTINE MFNWT_INIT()
C
!DEC$ ATTRIBUTES DLLEXPORT :: MFNWT_INIT
!DEC$ ATTRIBUTES DECORATE, ALIAS: "MFNWT_INIT"
C
USE GLOBAL
...(do stuff)
RETURN
END SUBROUTINE MFNWT_INIT
The C# code that calls the fortran, does the DLLImport call look OK?:
using System.Runtime.InteropServices;
public static class CustomMODSIM
{
public static Model myModel = new Model();
private static SortedList myStreamNodes;
public static void Main(string[] CmdArgs)
{
string FileName = CmdArgs[0];
myModel.Init += OnInitialize;
...(do more stuff)...
//Function call that will invoke "OnInitialize" below
myProgram.RunSolver(myModel);
}
private static void OnInitialize()
{
//call Fortran function
MFNWT_INIT();
//Initialize list of stream nodes
myStreamNodes = new SortedList();
Node m_Node = myModel.FindNode("NonStorage1");
...(do more stuff)
}
//Fortran DLL interface
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern void MFNWT_INIT();
}
Your second compiler directive (the second !DEC$ line) is incorrect - it is missing the :: MFNWT_INIT part that designates which Fortran thing has the nominated attributes (DECORATE and ALIAS). I would expect the compiler to issue a warning about the syntax problem.
For what its worth (assuming you are using a version of ifort >= 11 or so and not one of its ancestors): given you want to use the C calling convention, you are better off getting rid of that second directive completely, and just using the suffix BIND(C,NAME="MFNWT_INIT") on the SUBROUTINE statement.
Most likely the DLL is exporting the function with a decorated name. Find out what that name is and use it on the C# side.
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.Cdecl,
EntryPoint="DecoratedNameGoesHere")]
public static extern void MFNWT_INIT();
To find the exported name use a tool like dumpbin or Dependency Walker.
Are you quite sure that your DLL uses the cdecl calling convention?
In the IVF Help, have a look at Building Applications/Programming with Mixed Languages/Adjusting calling conventions in Mixed Languages/Attributes properties and calling conventions. That is where it is on Version 11. It may have moved in the version you are using. The confusing bit in the help is whether the exported symbol is upper or lowercase. It is only slightly different from the one written for the old MS Fortran 77 compiler (circa 1986). If you are unsure the exported symbols, use depends to find out what they are.
1) If you are not using an alias, then it should look like this on the Fortran side
MODULE MF_DLL
CONTAINS
SUBROUTINE MFNWT_INIT()
!DEC$ ATTRIBUTES STDCALL, DLLEXPORT :: MFNWT_INIT
If STDCALL is used, there will be two exported symbols: MF_DLL_mp_MFNWT_INIT and _MF_DLL_mp_MFNWT_INIT#0. If STDCALL is not specified, it defaults to C. In that case you will only MF_DLL_mp_MFNWT_INIT. The number after the # sign is the number of bytes on the stack that the routine needs to remove before returning to the caller. You will not get this in C decl because it is the responsibility of the caller.
2) On the C# side using stdcall
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.StdCall,
EntryPoint="_MF_DLL_mp_MFNWT_INIT#0")]
public static extern void MFNWT_INIT();
3) On the C# side using Cdecl
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.Cdecl,
EntryPoint="MF_DLL_mp_MFNWT_INIT")]
public static extern void MFNWT_INIT();
The difference is that in C, it does not need to know the number of parameters whereas in stdcall it does. This affects the stacking/unstacking of parameters. If this goes wrong, it will make the call, run the Fortran routine and then crash on exit. In your case, it doesn't really matter because there are no parameters but it is nice to get it right.
4) If an alias is used, the name changes but not the calling convention. In your case, you should have specified
! ,-- This is the name in DLL export
!DEC$ ATTRIBUTES DECORATE, ALIAS: "MFNWT_INIT"::MFNWT_INIT
With C decl, you will get MFNWT_INIT.
With STDCALL, you will get MFNWT_INIT and _MFNWT_INIT#0
On the C# side the entry point is not needed when C Decl is used. It is only needed when STDCALL is used.
5) If the routine is used in both Fortran and C# then it would be better to stick to stdcall.
I have written a C++/CLI library that exports a class with two generic functions:
public ref class TargetInterface
{
public:
static uint32_t buffer_length = 4096;
TargetInterface();
static bool Connect(char* deviceAdress);
static void Disconnect(char* deviceAdress);
generic<typename T>CommunicationState WriteProtobufMessage( T object);
generic<typename T>CommunicationState ReadProtobufMessage([Out] T object);
};
The dll compiles fine. When I try to use this functions in my C# project I get the error:
WavelabsLightsourceSystem.TargetInterface.ReadProtobufMessage<T>(T)' is inaccessible due to its protection level
Here is the c# part where I try to use the Funktions:
pb_MessageHeader header = new pb_MessageHeader();
TargetInterface target = new TargetInterface();
target.ReadProtobufMessage<pb_MessageHeader>(header);
As per Hans Passants comment I had to make the CommunicationState enum public.
Thanks Hans, your Crystall ball was correct. I didn't dream of, that I have to make an enum public.
I ran into the same exact issue, but my problem was actually due to different .NET Frameworks being targeted in different projects, as detailed here:
Why do I get a warning icon when I add a reference to an MEF plugin project?
I've got an existing application written in Borland C++ Builder. My client wants it rewritten in C#/WPF. This requires a lot of work and is a complex task because I need to rewrite the whole (huge) algorithm. I was thinking of a way to reuse the code and to be able to create only GUI in C#/WPF. Is this possible? Would that be easy? How can I make C++ classes visible to .NET ?
If you could give me brief answers with some links/examples I would be grateful.
You can wrap your old C++ code in a C++/CLI wrapper and build it into a DLL file. It should then be visible in any .NET project.
Depending on your algorithm/function structure, this may change a little, but the basic form, and the way I did this, is the following. Keep in mind this is a VERY basic example, but I tried to include the key points:
1. Define the CLI wrapper
using namespace System;
#include "myAlgorithmClass"
public ref class MyCLIWrapperClass //the 'ref' keyword specifies that this is a managed class
{
public:
MyCLIWrapperClass(); //Constructor
//function definitions are the same, though some types,
//like string, change a little. Here's an example:
String ^ GetAString(); //the "String" is the .NET "System.String" and the ^ is sort of a pointer for managed classes
//int, double, long, char, etc do not need to be specified as managed.
//.NET code will know how to handle these types.
//Here you want to define some functions in the wrapper that will call
//the functions from your un-managed class. Here are some examples:
//Say that your functions in the Algorithm class are int Func1, double Func2, and std::string Func3:
int Func1();
double Func2();
String ^ Func3();
private:
//All private functions and members here
myAlgorithmClass algor;
};
2. Implement the wrapper class
using namespace System;
#include <string> //For the string function ex. below
#include "myAlgorithmClass"
MyCLIWrapperClass::MyCLIWrapperClass()
{
algor = myAlgorithmClass(); //create instance of your un-managed class
}
int MyCLIWrapperClass::Func1()
{
return algor.Func1(); //Call the un-managed class function.
}
double MyCLIWrapperClass::Func2()
{
return algor.Func2(); //Call the un-managed class function.
}
String ^ MyCLIWrapperClass::Func3()
{
//Converting a std::string to a System.String requires some conversion
//but I'm sure you can find that somewhere on Google or here on SO
String ^ myString = "";
std::string myUnmanagedString = algor.Func3(); //Call the un-managed class function.
//Convert myUnmanagedString from std::string to System.String here
return myString;
}
After you write the wrapper class and compile it into a class library you can create a reference to the .DLL file in a C# project and C# should see the managed wrapper class and all its public functions.
Another thing to note is that if you are creating new managed objects in C++ you use the keyword "gcnew" instead of "new". So a new string would be String ^ someString = gcnew String();
Finally, here are some links to some things about CLI that may help:
CLI - Wikipedia
CLI - Code Project
CLI - FunctionX
Well, As far as i can remember by head, you can use interops for that matter.
It is in fact better to continue using a code that was for a long time tested, and is stable. With net Interop Services you can create a very good bridge between the new app and the old one.
examples:
http://www.daniweb.com/forums/thread136041.html
http://msdn.microsoft.com/en-us/library/aa645736%28v=vs.71%29.aspx
http://www.codeguru.com/cpp/cpp/cpp_managed/interop/article.php/c6867
So what I have is a C++ API contained within a *.dll and I want to use a C# application to call methods within the API.
So far I have created a C++ / CLR project that includes the native C++ API and managed to create a "bridge" class that looks a bit like the following:
// ManagedBridge.h
#include <CoreAPI.h>
using namespace __CORE_API;
namespace ManagedAPIWrapper
{
public ref class Bridge
{
public:
int bridge_test(void);
int bridge_test2(api_struct* temp);
}
}
.
// ManagedBridge.cpp
#include <ManagedBridge.h>
int Bridge::bridge_test(void)
{
return test();
}
int Bridge::bridge_test2(api_struct* temp)
{
return test2(temp);
}
I also have a C# application that has a reference to the C++/CLR "Bridge.dll" and then uses the methods contained within. I have a number of problems with this:
I can't figure out how to call bridge_test2 within the C# program, as it has no knowledge of what a api_struct actually is. I know that I need to marshal the object somewhere, but do I do it in the C# program or the C++/CLR bridge?
This seems like a very long-winded way of exposing all of the methods in the API, is there not an easier way that I'm missing out? (That doesn't use P/Invoke!)
EDIT: Ok, so I've got the basics working now thanks to responses below, however my struct (call it "api_struct2" for this example) has both a native enum and union in the C++ native code, like the following:
typedef struct
{
enum_type1 eEnumExample;
union
{
long lData;
int iData;
unsigned char ucArray[128];
char *cString;
void *pvoid;
} uData;
} api_struct2;
I think I have figured out how to get the enum working; I've re-declared it in managed code and am performing a "native_enum test = static_cast(eEnumExample)" to switch the managed version to native.
However the union has got me stumped, I'm not really sure how to attack it.. Ideas anyone?
Yes, you are passing an unmanaged structure by reference. That's a problem for a C# program, pointers are quite incompatible with garbage collection. Not counting the fact that it probably doesn't have the declaration for the structure either.
You can solve it by declaring a managed version of the structure:
public value struct managed_api_struct {
// Members...
};
Now you can declare the method as
int bridge_test2(managed_api_struct temp); // pass by value
or
int bridge_test2(managed_api_struct% temp); // pass by reference
Pick the latter if the structure has more than 4 fields (~16 bytes). The method needs to copy the structure members, one-by-one, into an unmanaged api_struct and call the unmanaged class method. This is unfortunately necessary because the memory layout of a managed structure is not predictable.
This is all pretty mechanical, you might get help from SWIG. Haven't used it myself, not sure if it is smart enough to deal with a passed structure.
A completely different approach is to make the wrapper class cleaner by giving it a constructor and/or properties that lets you build the content of an api_struct. Or you could declare a wrapper ref class for the structure, much like you would in managed code.
as it has no knowledge of what a api_struct actually is
You need to define a managed version in a .NET assembly, that uses attributes (like StructLayoutAttribute) to ensure it marshals correctly.
This seems like a very long-winded [...]
The other approach is to create a COM wrapper (e.g. using ATL) around your API. This might be more effort, but at least you avoid the double coding of struct and function definitions needed for P/Invoke.
Correction: You have created a C++/CLI project: so just add correct '#pragma' to tell the compiler this is .NET code, and then the output is an assembly the C# project can just reference.
Yuo are trying to do this way more complicated that it really is. What you want is two different structs. One managed and one unmanaged. You expose the managed version externally (to your C# app). It will be all ".Net-ish" with no concepts of unions or so.
In your bridge you receive the managed version of the struct, manually create the unmanaged struct and write code to move your data, field by field over to the unmanaged struct. Then call your unmanaged code and finally move the data back to the managed struct.
The beautiful thing about C++/CLI is that the managed code also can work with unmanaged code and data (and include the unmanaged .h files).