Click here to Skip to main content

How to convert from C# ref type to CLI\C++ ^% type…

Sign Up to vote bad
good
See more: C++/CLI
I am writing an application in Managed C++ (CLI\C++). In which I am using a library (.dll file) which was written in C#.
In a part I am encountering a problem.
I am trying to implement functions of an interface written in the library.
 
The declaration of a function in the library is as given below:
COMWORKSPACELib.IWorkspaceEvents.WorkspaceMessage(int, string, COMWORKSPACELib.EnumNotificationCode, COMWORKSPACELib.EnumNotificationType, string, ref COMWORKSPACELib.EnumNotificationReply);
 
When I write the same code in CLI\C++ the declaration is like:
WorkspaceMessage(int workspaceToken, String ^description, EnumNotificationCode ^code, EnumNotificationType ^type, String ^source, EnumNotificationReply ^%action);
 
Here, the compiler is giving me error that the “class must provide an implementation for the interface method”. Because the parameters passed in both function declarations are syntactically different.
 
Is there any alternative way to match the library declaration?
 
If I remove the “^’ & ‘%’ to match the library declaration then it gives further errors in the code.
 

Below I am writing a sample code depicting the way actual code is written...
 
Interface ISampleInter C#: -
namespace LibraryName
{
    public interface ISampleInter
    {
        Void Method1(int nfir, String str, ref EnumType type);
        Void Method2(int nsec, EnumCode code, String str, ref EnumType type);
    }
}
 
Note: - A Library containing this interface is added as a reference to the main project...
 
MyCode C++/CLI: -
MyCode.h
using namespace LibraryName;
 
namespace WorkSpace
{
    private ref class WorkMyClass : ISampleInter
    {
        public:
            virtual Method1(int nfir, String str, EnumType %type);
            virtual Method2(int nsec, EnumCode code, String str, EnumType %type);
    };
}
 
MyCode.cpp
#included "MyCode.h"
 
using namespace LibraryName;
 
namespace WorkSpace
{
    void Method1(int nfir, String str, EnumType %type)
    {
        //Some Code;
    }
 
    void Method2(int nsec, EnumCode code, String str, EnumType %type)
    {
        //some Code;
    }
}
Posted 8 Mar '11
Edited 10 Mar '11
SAKryukov385K

Comments
SAKryukov - 9 Mar '11
Why this post is identical to this: http://social.msdn.microsoft.com/Forums/is/vclanguage/thread/d3245004-1064-4c23-b72d-ed381870f159, except this one is signed by Rajesh G Manwani?! --SA
Kedar Kumbhar - 9 Mar '11
Actually, we both are looking a answer for this. He is registered in msdn and me in code project...
SAKryukov - 9 Mar '11
Thank you. You both can rely on my Answer. Please ask a follow-up Question if you need. (Please don't post is as Answer (common very annoying mistake), use "Improve question" or "Add comment" or "Reply") --SA
Olivier Levrey - 10 Mar '11
You again have problems with pointers and references... See my answer: I wrote what you should put in your .h file and SA agrees with that.
Kedar Kumbhar - 10 Mar '11
Hi Olivier, It is done the same way as yuo mentioned. But, still it is giving error. I am sure that now syntacticaly I am not wrong. The problem is in meta file in has created 2 conflicting definition. One from the inherited interface & other that is written locally... But I am not sure ha...
Olivier Levrey - 10 Mar '11
Can you give the error message?

Even though SA's answer is a little bit harsh, he's right. After referencing the assembly, intellisense will show you the expected types.
 
Since an enum is a value type, you don't need to pass it with ^. Try this:
 
virtual void WorkspaceMessage(int workspaceToken, System::String^ description, EnumNotificationCode code, EnumNotificationType type, System::String^ source, EnumNotificationReply %action)
{
}
 
...
 
In the .h, write the following:
using namespace LibraryName;
namespace WorkSpace
{
    private ref class WorkMyClass : ISampleInter
    {
        public:
            virtual void Method1(int nfir, System::String^ str, EnumType %type);
            virtual void Method2(int nsec, EnumCode code, System::String^ str, EnumType %type);
    };
}
In the .cpp, write the following:
#include "MyCode.h"
using namespace LibraryName;
using namespace WorkSpace;
void WorkMyClass::Method1(int nfir, System::String^ str, EnumType %type)
{
    //Some Code;
}
 
void WorkMyClass::Method2(int nsec, EnumCode code, System::String^ str, EnumType %type)
{
    //some Code;
}
  Permalink  
Comments
SAKryukov - 9 Mar '11
This is correct, provided EnumeNotificationReply is a value type. It it is declared in C# as a class (reference type), which is less likely, as it would not not make much sense, it would be "EnumNotificationReply ^%action". Agree? My 5, anyway. --SA
Olivier Levrey - 10 Mar '11
Thank you. I agree. It is strange that they used the "class" word for enums.
SAKryukov - 10 Mar '11
I don't really know if EnumNotificationReply. Does not matter. By the way, did you pay attention of one popular way to of a spectacular failure in naming styles. Common sense says that is it extremely stupid to name application as "AppXXXX" or class as "ClassXXX" or enumeration type "EnumXXXXX", but this is exactly what some people do. In fact using keywords and concept names like that in fine, but only to express some meta-concepts like TypeDictionary or ClassDescriptor, etc. Thank you. --SA
Answering a follow-up Question after the sample code is submitted:
 
You have done good number of bugs; most principal one is wrong syntax in method implementation part. Both products would not compile. Here is what should be:
 
Interface ISampleInter C#:
 
namespace LibraryName {
    using System; //added

    public enum EnumType { None, Some, } //fake, just to make code compile
    public enum EnumCode { Good, Bad, } //fake, just to make code compile

    //"void" was incorrectly capitalized, fixed:
    public interface ISampleInter {
        void Method1(int nfir, String str, ref EnumType type);
        void Method2(int nsec, EnumCode code, String str, ref EnumType type);
    } //interface ISampleInter

} //namespace LibraryName
 
A side note: two parameters by ref make no sense, make them return values; why using void? However, our goal is to check-up techniques, so let's proceed:
 
MyCode.h:
 
using namespace LibraryName;
using namespace System; //added

namespace WorkSpace
{
    private ref class WorkMyClass : ISampleInter
    {
        public:
            //two problems:
            //1) added "void":
            //2) added "^" for String -- this is reference type

            virtual void Method1(int nfir, String ^str, EnumType %type);
            virtual void Method2(int nsec, EnumCode code, String ^str, EnumType %type);
    };
}
 
MyCode.cpp:
 
using namespace LibraryName;
using namespace System; //added

namespace WorkSpace {
 
    //two problems:
    //1) added "^" for String -- this is reference type
    //2) added "WorkMyClass::" common C++ syntax

    void WorkMyClass::Method1(
        int nfir,
        String ^str,
        EnumType %type)
    {
        //Some Code;
    }
    void WorkMyClass::Method2(
        int nsec,
        EnumCode code,
        String ^str,
        EnumType %type)
    {
        //some Code;
    }
 
}
 
Now it's correct. If some of the types I don't know is a reference type, you need to use "^%" instead of "%" for a parameter by reference.
 
I would say, case closed.
 
—SA
  Permalink  
Comments
Kedar Kumbhar - 11 Mar '11
Thanks SA. Thanks Olivier. Corrected the code as you suggested. The void problem was a typo. Changed the code to match completely with library declaration. Next problem was in the Meta file. Some how it has created to declarations of the functions. The compiler created slightly different metadata in two modules with same type. At link time, when this metadata is merged, the error is thrown because the name for the type is the same, but there is some discrepancy in the rest of the metadata describing that type. I resolved the ambiguity removing the multiple definition and loading the library again. With this to thing resolved the code is running now...
SAKryukov - 11 Mar '11
You're welcome. It looks like the problem of metadata is again a result of some subtle bug. Workaround is not right thing, you need to fix is and be 100% confident. I suggest you reproduce the problem with minimal code again and ask a separate Question. Good luck. --SA
SAKryukov - 11 Mar '11
By the way: _this_ is the real Answer, with code. Will you formally accept it? Thank you. --SA
Kedar Kumbhar - 11 Mar '11
Ohh... Done... Acepted... Thanks ...Kedar
No wonder you code does not compile: if you're implementing the interface, you need to write implementation of every method and property. Probably, your own problem in writing matching declaration of all parameters.
 
It looks like you completely mixing up all possible combinations of references, pointers and address operators, managed and unmanaged, all together. You need to learn the difference between '*', '&' (unmanaged) and '^', '%' managed. But right now you can simply let rely on intellisense: before you write implementation, try to declare the interface reference to the object instance and write a call to its method. As soon as you type an open bracket intellisense will show you all what's expected.
 
In brief, you will see:
C#, value type passed by value: (int a) — C++/CLI: the same: (int a)
C#, value type passed by ref: (ref int a) — C++/CLI: the same: (int %a)
C#, reference type passed by value: (string a) — C++/CLI: (string ^a)
C#, reference type passed by ref: (ref string a) — C++/CLI: (string ^%a).
 
The last case is kind of stupid, but formally you can use it.
 
There is also out parameter in C#, which is similar to ref but always requires assignment in the method body. In C#, matching ref and out parameter modifiers are also used in the call, which makes C# syntax more fool-proof; but they are not used in C++/CLI.
 
Also, '%' is the analog of "address" operator used to get a reference from value of a reference type:
ref class Demo {
    void Test() {
        Demo demoVal;
        Demo^ demoRef = %demoVal;
        Demo^ demoHeapRef = gcnew Demo();
    }
};
The value semantic with classes demonstrated on the example of demoRef is unique to C++/CLI. There is no such thing in C#, so all reference types are allocated on heap and only addressed by reference, so the variable declaration equivalent to demoRef is not possible (but possible with structures, which are value types).
 
Now you need to learn what all four cases mean semantically and only then try to understand the notation.
Trying different combination in hope it will compile and even run miraculously is… what's the politically correct expression?.. counterproductive…
 
Good luck,
—SA

 
[EDIT] Answering follow-up Question after code samples are submitted: see another Answer.
  Permalink  
Comments
Olivier Levrey - 9 Mar '11
OP is declaring the method because he is implementing an interface. But I agree about everything else. Voted 4.
SAKryukov - 9 Mar '11
Thank you very much for the note, I missed a word about interface (OP could put couple more lines in code to mark it). I'll change the text; the difference is minor. --SA
SAKryukov - 9 Mar '11
Answer updated.
Olivier Levrey - 10 Mar '11
My 5 now ;)
SAKryukov - 10 Mar '11
Great, thank you. --SA
SAKryukov - 9 Mar '11
Please also see the Answer by Olivier and my comment (I did not put interface method declaration because you did not provide all other declarations, see). Anyway, using intellisense works in all cases. Thank you for accepting my Answer. Good luck, --SA
Kedar Kumbhar - 10 Mar '11
Hi SAKryukov, Your post is actually a solution for my problem. But, when i remove all the declaration from the .h file and keep only defination in the .cpp file, the compiler reports same error "Class must provide an implementation for interface". Even when i give the full specifier (COMWORKSPACE::IWorkSpaceEven::WorkSpaceMessage(...) then the compiler gives error "Explicit override of method WorkSpaceMessage". If i go with my previous implementation of declaration in .h & definition in .cpp, the code gets compiled. But, later gives linkUp errors LNK2022 - MetaData Operation failed - "Inconsistent method declaration in duplicated types". I guess I am not able to implement the interface methods properly...
SAKryukov - 10 Mar '11
It's hard to see by this description. Make three files: C#, *.h and *.cpp, with one interface and one interface method, make it simple, use only primitive-type and string parameters (say, int and string) and post in using "Improve question", so I could see how are you doing it. Believe me, this is the fastest way. The goal of these two project is to make them compile (or manifest your problem) without any other codes. Make sure there are no other errors. (By the way, I check up all my Answers like that using real compilers. You should to the same with you Questions, not just use your original code). Also, such "research project" approach helps to pin-point or even immediately solve the problem by yourself, in many situations. So please do it and let's see. You basically will need some 15 minutes, I think. --SA
Kedar Kumbhar - 10 Mar '11
Hi SA, Added the sample code. I have written the code in similer way. Even i have sensed that cli-c++ compiler in .net is week...
SAKryukov - 10 Mar '11
I did not feel it's too week, maybe old versions. OK, thanks for the post, let me take a look... --SA
SAKryukov - 10 Mar '11
Hey, I need to know the types EnumCode and EnumType. You don't have to put mode code, just explain informally. I need to tell reference type from value type, that's all. --SA
SAKryukov - 10 Mar '11
I already see you bug... wait a bit...
SAKryukov - 10 Mar '11
OK, see the fixed code in a separate Answer. See my comments on your bugs in code blocks. Done. --SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

add
  Print Answers RSS
Your Filters
Interested
Ignored
     
  1. OriginalGriff (1,245)
  2. Sandeep Mewara (1,037)
  3. VJ Reddy (545)
  4. SAKryukov (473)
  1. Sandeep Mewara (13,934)
  2. OriginalGriff (12,986)
  3. SAKryukov (8,004)
  4. VJ Reddy (5,145)
  5. losmac (5,065)


Advertise | Privacy | Mobile
Web01 | 2.5.120515.1 | Last Updated 10 Mar 2011
Copyright © CodeProject, 1999-2012
All Rights Reserved. Terms of Use
Layout: fixed | fluid