I have following code
ref class A
{
typedef ref struct All
{
std::string x;
}All_t;
};
in my program I am using it in following manner
A::All_t t;
t.X = "H";
This declaration throwing error as
error C4368: cannot define 'x' as a member of managed 'A::All': mixed types are not supported
I understand that I am declaring native varible inside managed code which is not allowed but now I would like to know changes I will need to make to make my structure suitable to managed project.
Thanks.
I'm assuming you originally had std::string x; not std::string *x (since using the pointer to string does not generate that error). You are not allowed to directly embed a native type in a managed type, but you are allowed to indirectly have one (via a pointer) See:
http://msdn.microsoft.com/en-us/library/xhfb39es(v=vs.80).aspx
After I fixed the compiler errors in your sample, it builds without error:
#include "stdafx.h"
#include <string>
using namespace System;
ref class A
{
public:
typedef ref struct All
{
std::string * x;
}All_t;
};
int main(array<System::String ^> ^args)
{
A::All_t t;
t.x = new std::string("H");
return 0;
}
Related
When I compiled the below code in gcc I get 1408.How does it work.Can we initialise values inside structure?
#include<iostream>
using namespace std;
struct Test {
int i=1408;
};
int main()
{
Test l;
int p=1508;
l.i==p;
cout<<l.i;
}
l.i==p; does nothing. == tests if two things are equal to each other. That's not an assignment.
You must have meant
l.i=p;
It is best to declare structure variable in struct body and intialise values using objects created using structure identifiers in your code identifier is Test.
Initialisation can be in the form of
Test t1 ={ 1408 };
I have created new Win32 project in my VS and have selected Dynamic Library ( *.dll ) for this aim.
I have defined some exporting function in the main file:
__declspec(dllexport)
int TestCall(void)
{
int value = 4 / 2;
std::cout << typeid(value).name() << std::endl;
return value;
}
__declspec(dllexport)
void SwapMe(int *first, int *second)
{
int tmp = *first;
*first = *second;
*second = tmp;
}
When I've looked at the dumpin /exports, I've got:
ordinal hint RVA name
1 0 00001010 ?SwapMe##YAXPEAH0#Z
2 1 00001270 ?TestCall##YAHXZ
I'm calling in the C# version like this:
[DllImport(#"lib1.dll", EntryPoint = "?TestCall##YAHXZ",
CallingConvention = CallingConvention.Cdecl)]
static extern int TestCall();
It's not the correct form of using exported methods. Where did I fail with generating such names for exporting-methods in the C++ dll project?
This is normal, the C++ compiler applies name decoration to functions. The C++ language supports function overloading, much like C# does. So you could write a Foo(int) and a Foo(double) function. Clearly they cannot both be exported as a function named "Foo", the client code wouldn't know which one to call. So the extra characters encode the name so that it is unique for the overload.
You can turn that off by declaring the function extern "C", the C language doesn't support overloading so doesn't require the same kind of decoration.
But it is actually better if you don't. Because it is also an excellent way to catch mistakes. Like changing the function declaration in your C++ code but forgetting to modify the pinvoke declaration in your C# code. You will now get an easy to diagnose "Entrypoint not found" exception instead of a non-descriptive and very hard to diagnose AccessViolationException. Which doesn't necessarily have to be raised in the C++ code, the stack imbalance can also crash your C# code. Looking up the decorated name is a bit painful however, improve that by asking the linker to create a map file (/MAP option).
use extern "C" to specify the linkage to avoid the name mangling:
extern "C" __declspec(dllexport) int TestCall(void);
extern "C" __declspec(dllexport) void SwapMe(int *first, int *second);
I need to expose some unmanaged data using CLIWrapper.
Let's say I have a vector, but there is no null-characters in the middle of the vector (for sure). What would be the best way to do this type of assigment/marshalling?
And just in case.... How whould the same operation looks like if I do assigning from vector to cli::array?
You can directly use the String class constructor. Like this:
#include "stdafx.h"
#include <vector>
using namespace System;
int main(array<System::String ^> ^args)
{
std::vector<wchar_t> example;
example.push_back('x');
String^ str = gcnew String(&example[0], 0, example.size());
Console::WriteLine(str);
return 0;
}
Help!
I'm totally exhausted/frustrated with what seems to be a reasonably easy task. I’m not sure what I'm doing wrong; let alone if I'm doing it correct. I'm "required" to use an existing library (a C static library – over 100,000 lines of straight C code) in developing a WPF application (VS 2010, C# 4.0). Oh, and I can't touch the existing C code - use it as is!
I've read so many postings (advanced topics, how-to, etc), yet I'm so new to C++/CLI that it's just not making sense. From what I've read the best approach is to wrap the C static library as follows:
Unmanaged C static library <---> C++/CLI managed wrapper DLL <--->
managed WPF application
This is the stripped down C header file:
/* Call this function to execute a command. */
int issue_command(int command, long param1, long param2);
/* Completion call back function; you must supply a definition. */
extern int command_completed(int command, long param1, long param2);
struct struct_command_str
{
char command_str[10];
char param1_st[2];
char param2_st[2];
char success;
};
/* You must supply definitions to the following extern items. */
extern int command_status;
extern struct struct_command_str command_str;
The problem(s):
What I can’t seem to do correctly is provide a C++/CLI implementation for the call back functions, and the two extern items (command_status and struct command_str).
Can someone provide a sample C++/CLI implementation for the above missing call back functions and externs?
Thanks in advance for your assistance.
in your C++/CLI managed wrapper project, add 2 files :
a .c file :
extern void doSomething();
int command_status = 0;
struct_command_str command_str = { "command1", "p1", "p2", 't' };
int command_completed(int command, long param1, long param2) {
...
command_status = 1;
...
doSomething();
...
command_status = 2;
...
return 3;
}
a cpp file
void doSomethingManagedWrapper() {
...
call managed code
...
}
void doSomething() {
doSomethingManagedWrapper();
}
when you implement these in your c++/cli module, use the same signature shown in the c header file,but prefixed with extern "C".
also put an extern "C" block around the #include of the C header file.
I am trying to pass an array of ints from C# to C++/CLI. Here's my code:
// SafeArrayTesting_PlusPlus.cpp
#include "stdafx.h"
#include <comdef.h>
using namespace System;
namespace SafeArrayTesting_PlusPlus
{
public ref class MyCppClass
{
public:
MyCppClass();
~MyCppClass();
void SetMyInts(array<int>^ myInts);
};
MyCppClass::MyCppClass(){}
MyCppClass::~MyCppClass(){}
void MyCppClass::SetMyInts(array<int>^ myInts)
{
// Create safearray
SAFEARRAY *safeArrayPointer;
SAFEARRAYBOUND arrayDim[1]; // one dimensional array
arrayDim[0].lLbound= 0;
arrayDim[0].cElements= myInts->Length;
safeArrayPointer = SafeArrayCreate(VT_UNKNOWN,1,arrayDim);
// copy ints to safearray
for (long lo= 0; lo < myInts->Length; lo++)
{
cli::pin_ptr<int> pinnedIntPointer = &(myInts[lo]);
SafeArrayPutElement(
safeArrayPointer,
&lo,
static_cast<void*> (pinnedIntPointer)); // line XX
}
// do something with the safearray here
}
}
// SafeArrayTesting_Main.cs
using SafeArrayTesting_PlusPlus;
namespace SafeArrayTesting_Main
{
class SafeArrayTesting_Main
{
static void Main()
{
var myCppClass = new MyCppClass();
myCppClass.SetMyInts(new[]{42});
}
}
}
When I run this, line XX throws the following exception:
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I have a feeling that I'm doing something basically wrong with the SafeArrayPutElement method. Can you spot the error?
(By the way, I have asked a more complex variation of this question at Passing an array of interfaces from C# to C++/CLI . I think the difference is big enough to warrant two separate questions.)
safeArrayPointer = SafeArrayCreate(VT_UNKNOWN,1,arrayDim);
That creates an array of IUnknown interface pointers. SafeArrayPut() makes sure to increase the reference count of the interface pointer by calling IUnknown::AddRef() since it stores a copy of the pointer in the array.
You can see how that goes kaboom. Create an array of integers instead. Fix:
safeArrayPointer = SafeArrayCreate(VT_I4,1,arrayDim);