Why does C++ CLI force classes to have variables in constructor method? - c++-cli

public ref class masterWeapon{
public :
property int Slot {
int get(){
return 0;
}
}
masterWeapon(){
}
};
OSamp::masterWeapon mw();
int v = mw.Slot; //ERROR error C2228: left of '.Slot' must have class/struct/union
However following code ran fine :
public ref class masterWeapon{
public :
property int Slot {
int get(){
return 0;
}
}
masterWeapon(int useless){
}
};
OSamp::masterWeapon mw(231312);
int v = mw.Slot; //works fine

Why does C++ CLI force classes to have variables in constructor method?
It doesn't, you just have an error in your code.
OSamp::masterWeapon mw();
The error message is slightly misleading; it is the line above that is causing the issue. The compiler is telling you that mw is not an instance of an object. mw is interpreted as a prototype for a function which takes no arguments and returns an OSamp::masterWeapon.
The line should be rewritten as:
OSamp::masterWeapon mw;

Related

How to access private variable in C++/CLI managed class

//MyWrapper.h
#include "arithmetic.h"
#include "mathematics.h"
namespace MyWrapper {
public ref class ClassA
{
public:
ClassA();
~ClassA();
int add(int, int);
private:
MyEngine::Arithmetic *nativeClassA;
}
public ref class ClassB
{
public:
ClassB(ClassA^ arith);
~ClassB();
int pow(int, int);
private:
MyEngine::Mathematics *nativeClassB;
}
}
//MyWrapper.cpp
#include "MyWrapper.h"
My::ClassA::ClassA()
{
nativeClassA = new MyEngine::Arithmetic();
}
My::ClassA::~ClassA()
{
delete nativeClassA;
}
int My::ClassA::add(int a, int b)
{
return nativeClassA->add(a, b);
}
My::ClassB::ClassB(ClassA^ classA)
{
nativeClassB = new MyEngine::Mathematics(classA->nativeClassA); //***Error***
}
My::ClassB::~ClassB()
{
delete nativeClassB;
}
int My::ClassB::pow(int a, int b)
{
int result = nativeClassB->pow(a, b);
return result;
}
Here, Mathematics class need to init with Arithmetic class.
But nativeClassA is private variable in ClassA.
So nativeClassB = new MyEngine::Mathematics(classA->nativeClassA); , it will occurs compile error.
So I changed the nativeClassA to public.
But at that time, nativeClassA will export to c#.
I don't want to export nativeClassA variable to c#.
How can I fix it?
Thanks in advice.
Since you're writing a managed class, you can use all the access modifiers that C# has. This seems like a perfect scenario for internal. (The linked documentation is for C#, but it's the same keyword in C++/CLI.)

Type casting in C++\CLI project

I have project which I am compiling with /clr. I have a class like below..
ref class A
{
public:
void CheckValue(void * test);
typedef ref struct val
{
std::string *x;
}val_t;
};
in my implementation I ahve to use something like below..
void A::CheckValue(void *test)
{
a::val_t^ allVal = (a::val_t^)test;
}
in my main I have used like..
int main()
{
A^ obj = gcnew A();
a::val_t valObj = new std::string("Test");
obj->CheckValue((void*)valObj);
}
I am getting type cast error and two places -
obj->CheckValue((void*)valObj);
and at
obj->CheckValue((void*)valObj);
error C2440: 'type cast' : cannot convert from 'void*' to 'A::val_t ^'
This snippet is just to show behavior at my end and I ahve to use it this way only. Earlier I was running it using non /clr so it compiled fine.
Now question I have how can I make this type casting work in C++/CLI type project?
Replace void * with Object^. You can also write a generic version of CheckValue but then there is not much point of having a weak-typed parameter when you have the type in the generic parameter.
A reference handle represents an object on the managed heap. Unlike a native pointer, CLR could move the object around during a function call, so the behavior of a pointer and a reference handle is different, and a type cast would fail. You can also pin the object being referenced using pin_ptr if you really need a void* so CLR would not be moving the object during the function call.
Here is how I would get around the limitation you are seeing, just remove the struct from the managed object, since it contains native pointer types.
struct val_t
{
char* x;
};
ref class A
{
public:
void CheckValue(void* test);
};
void A::CheckValue(void* test)
{
val_t* allVal = (val_t*)test;
}
int main()
{
A^ obj = gcnew A();
val_t valObj;
valObj.x = "Test";
obj->CheckValue((void*)&valObj);
}
Now, if you absolutely need the struct to be managed, here is how to do it:
ref class A
{
public:
void CheckValue(void * test);
value struct val_t
{
char* x;
};
};
void A::CheckValue(void *test)
{
a::val_t* allVal = (a::val_t*)test;
}
int main()
{
A^ obj = gcnew A();
a::val_t valObj;
valObj.x = "Test";
pin_ptr<a::val_t> valPin = &valObj;
obj->CheckValue((void*)valPin);
}

C++/CLI: Passing C++ class ptr to unmanaged method

I've been given a third party C/C++ library (.dll, .lib, .exp and .h) that I need to use in our C# app.
ThirdPartyLibrary.h contains...
class AClass {
public:
typedef enum {
green = 7,
blue = 16
} Color;
virtual int GetData()=0;
virtual int DoWork(Color, char *)=0;
};
void * Func1(int, AClass **aClass);
In my C++/CLI code I have done this...
#include "ThirdPartyLibrary.h"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Wrapper {
public ref class MyBridgeClass
{
private:
AClass* pAClass;
public:
// C# code will call this method
void AMethod (int x)
{
int y = x+10;
Func1 (y, &(this->pAClass)); // <-- error!
}
}
}
I get a build error that reads...
cannot convert parameter 2 from 'cli::interior_ptr<Type>' to 'AClass **'
with
[
Type=AClass *
]
Cannot convert a managed type to an unmanaged type
Any ideas? Maybe I need #pragma manage/unmanged tags in my C++/CLI?
The reason you're getting that error is because of how managed memory works.
In your managed class, you've got a pointer defined. The address of that pointer is part of the managed object, and can change when the garbage collector runs. That's why you can't just pass &pAClass to the method, the GC can change what that address actually is.
There's a couple things you can do to fix this:
You could create an unmanaged helper class to hold the AClass* member. I'd do this if that pointer needs to stay valid beyond the invocation of this method, or if you have a lot of unmanaged pointers to hold.
struct UnmanagedHolder
{
AClass* pAClass;
};
public ref class MyBridgeClass
{
private:
// must create in constructor, delete in destructor and finalizer.
UnmanagedHolder* unmanaged;
public:
// C# code will call this method
void AMethod (int x)
{
int y = x+10;
Func1 (y, &(this->unmanaged->pAClass));
}
};
If you only need the pointer to be valid within AMethod, and the pointer doesn't need to remain valid after the call to Func1, then you can use a pin_ptr.
void AMethod (int x)
{
int y = x+10;
pin_ptr<AClass*> pin = &(this->pAClass);
Func1 (y, pin);
}

C++/CLI managed VS. unmanaged short

I have an unmanaged library which I want to use from a managed class. The interface of the function is:
GetProgress(short* value);
So I wrote in my managed class:
short val = 0;
GetProgress(&val);
I got the following error:
Error C2664: 'GetProgress' : cannot convert parameter 1 from 'cli::interior_ptr' in 'short *' with [ Type=short ]
I read this topic, so I changed my code into:
short val = 0;
pin_ptr<short*> pVal = &val;
GetProgress(pVal);
And in addition to the previous error I get
Error C2440: 'initialisation' : cannot convert from 'short *' to 'cli::pin_ptr' with [ Type=short * ]
How can I fix this?
That's an interesting one.
The following code produces C2664 because val can only be a managed type:
using namespace System;
void GetProgress(short* value)
{
// unmanaged goodness
}
ref class XYZ : System::Object
{
short val;
void foo()
{
GetProgress(&val);
}
};
but if you declare a local variable first, it all works fine...
using namespace System;
void GetProgress(short* value)
{
// unmanaged goodness
}
ref class XYZ : System::Object
{
short val;
void foo()
{
short x;
GetProgress(&x);
val = x;
}
};
Not exactly the answer you were looking for, but I thought I'd include it since it's a simple fix.

Rhino.Mocks how to test abstract class method calls

I'm trying to test if the method I want to test calls some external (mock) object properly.
Here is the sample code:
using System;
using Rhino.Mocks;
using NUnit.Framework;
namespace RhinoTests
{
public abstract class BaseWorker
{
public abstract int DoWork(string data);
}
public class MyClass
{
private BaseWorker worker;
public BaseWorker Worker
{
get { return this.worker; }
}
public MyClass(BaseWorker worker)
{
this.worker = worker;
}
public int MethodToTest(string data)
{
return this.Worker.DoWork(data);
}
}
[TestFixture]
public class RhinoTest
{
[Test]
public void TestMyMethod()
{
BaseWorker mock = MockRepository.GenerateMock<BaseWorker>();
MyClass myClass = new MyClass(mock);
string testData = "SomeData";
int expResponse = 10;
//I want to verify, that the method forwards the input to the worker
//and returns the result of the call
Expect.Call(mock.DoWork(testData)).Return(expResponse);
mock.GetMockRepository().ReplayAll();
int realResp = myClass.MethodToTest(testData);
Assert.AreEqual(expResponse, realResp);
}
}
}
When I run this test, I get:
TestCase 'RhinoTests.RhinoTest.TestMyMethod'
failed: System.InvalidOperationException : Invalid call, the last call has been used or no call has been made (make sure that you are calling a virtual (C#) / Overridable (VB) method).
at Rhino.Mocks.LastCall.GetOptions[T]()
at Rhino.Mocks.Expect.Call[T](T ignored)
RhinoTest.cs(48,0): at RhinoTests.RhinoTest.TestMyMethod()
The exception is thrown on the Expect.Call line, before any invocation is made.
How do I approach this - i.e. how to check if the method under test properly forwards the call?
This is .Net 2.0 project (I can no change this for now), so no "x =>" syntax :(
I have to admit, I'm not entirely sure what's going on here, but using Rhino.Mocks 3.6 and the newer syntax, it works fine for me:
[Test]
public void TestMyMethod()
{
MockRepository mocks = new MockRepository();
BaseWorker mock = mocks.StrictMock<BaseWorker>();
MyClass myClass = new MyClass(mock);
string testData = "SomeData";
int expResponse = 10;
using (mocks.Record())
{
//I want to verify, that the method forwards the input to the worker
//and returns the result of the call
Expect.Call(mock.DoWork(testData)).Return(expResponse);
}
using (mocks.Playback())
{
int realResp = myClass.MethodToTest(testData);
Assert.AreEqual(expResponse, realResp);
}
}
It doesn't have anything to do with the Rhino.Mocks version. With the old syntax, I get the same error as you're getting. I didn't spot any obvious errors in your code, but then again, I'm used to this using syntax.
Edit: removed the var keyword, since you're using .NET 2.0.