Click here to Skip to main content
15,895,084 members
Please Sign up or sign in to vote.
3.67/5 (3 votes)
See more:
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
Updated 10-Mar-11 6:34am
v5
Comments
Sergey Alexandrovich Kryukov 9-Mar-11 1:11am    
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 1:43am    
Actually, we both are looking a answer for this. He is registered in msdn and me in code project...
Sergey Alexandrovich Kryukov 9-Mar-11 3:35am    
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 7:33am    
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 7:48am    
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...

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:

C++
virtual void WorkspaceMessage(int workspaceToken, System::String^ description, EnumNotificationCode code, EnumNotificationType type, System::String^ source, EnumNotificationReply %action)
{
}


...

In the .h, write the following:
C++
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:
C++
#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;
}
 
Share this answer
 
v3
Comments
Sergey Alexandrovich Kryukov 9-Mar-11 13:34pm    
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 3:57am    
Thank you. I agree. It is strange that they used the "class" word for enums.
Sergey Alexandrovich Kryukov 10-Mar-11 4:05am    
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#:

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:

C++
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:

C++
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
 
Share this answer
 
v2
Comments
Kedar Kumbhar 11-Mar-11 2:01am    
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...
Sergey Alexandrovich Kryukov 11-Mar-11 2:32am    
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
Sergey Alexandrovich Kryukov 11-Mar-11 3:45am    
By the way: _this_ is the real Answer, with code.
Will you formally accept it?
Thank you.
--SA
Kedar Kumbhar 11-Mar-11 4:39am    
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:
C++
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.
 
Share this answer
 
v8
Comments
Olivier Levrey 9-Mar-11 4:28am    
OP is declaring the method because he is implementing an interface. But I agree about everything else. Voted 4.
Sergey Alexandrovich Kryukov 9-Mar-11 13:11pm    
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
Sergey Alexandrovich Kryukov 9-Mar-11 13:19pm    
Answer updated.
Olivier Levrey 10-Mar-11 3:59am    
My 5 now ;)
Sergey Alexandrovich Kryukov 10-Mar-11 4:07am    
Great, thank you.
--SA

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900