managed C++ and C# - c#

I have a class in managed C++ that has all its member variables initialized inside the constructor. The member of interest is an array. I am calling it from the .cs file of a C# project, having linked the two projects with the dll of the first one. However, the function says that one or more of the parameters are incorrect and therefore, cannot be used successfully.
The class declaration and the function declaration is as follows. Both are in the .h file.
Now, I would like to call the function in the .cs file as follows:
var Driver = new Driver();
long status = Driver.Config2("CAN0", 8, Driver.AttrIdList, Driver.AttrValueList);
Console.WriteLine(status);
If the function Config executes correctly, it should output a 0. However, I am getting a negative number and upon the lookup with the table provided by the vendor, it states that one or more of the parameters are not setup correctly. I have no idea how to get past this point since I'm a newbie to managed C++. All help would be greatly appreciated.
Thanks.
The code declaration is as follows:
public ref class Driver
{
public:
NCTYPE_STATUS Status;
NCTYPE_OBJH TxHandle;
MY_NCTYPE_CAN_FRAME Transmit;
array<NCTYPE_UINT32>^ AttrIdList;
array<NCTYPE_UINT32>^ AttrValueList;
array<char>^ Data;
NCTYPE_UINT32 Baudrate;
public:
Driver()
{
Baudrate = 1000000;
TxHandle = 0;
AttrIdList = gcnew array<NCTYPE_UINT32>(8);
AttrValueList = gcnew array<NCTYPE_UINT32>(8);
AttrIdList[0] = NC_ATTR_BAUD_RATE;
AttrValueList[0] = Baudrate;
AttrIdList[1] = NC_ATTR_START_ON_OPEN;
AttrValueList[1] = NC_TRUE;
AttrIdList[2] = NC_ATTR_READ_Q_LEN;
AttrValueList[2] = 0;
AttrIdList[3] = NC_ATTR_WRITE_Q_LEN;
AttrValueList[3] = 1;
AttrIdList[4] = NC_ATTR_CAN_COMP_STD;
AttrValueList[4] = 0;
AttrIdList[5] = NC_ATTR_CAN_MASK_STD;
AttrValueList[5] = NC_CAN_MASK_STD_DONTCARE;
AttrIdList[6] = NC_ATTR_CAN_COMP_XTD;
AttrValueList[6] = 0;
AttrIdList[7] = NC_ATTR_CAN_MASK_XTD;
AttrValueList[7] = NC_CAN_MASK_XTD_DONTCARE;
interior_ptr<NCTYPE_UINT32> pstart (&AttrIdList[0]);
interior_ptr<NCTYPE_UINT32> pend (&AttrIdList[7]);
Data = gcnew array<char>(8);
for (int i=0; i<8;i++)
Data[i]=i*2;
}
I also have another method right underneath the Config function that is declared as follows:
NCTYPE_STATUS Config2 (String^ objName, int numAttrs, array<unsigned long>^ AttrIdList, array<unsigned long>^ AttrValueList )
{
msclr::interop::marshal_context^ context = gcnew msclr::interop::marshal_context();
const char* name = context->marshal_as<const char*>(objName);
char* name_unconst = const_cast<char*>(name);
return ncConfig (name_unconst, 8, nullptr, nullptr);
delete context;
}
The program compiles and builds, this is a run-time error. I am guessing it has something to do with the two nullptr passed in the function Config2, but if I replace these with the parameters AttrIdList and AttrValueList, the compiler gives an error:
cannot convert parameter 3 from 'cli::array^' to 'NCTYPE_ATTRID_P'
BTW: NCTYPE_STATUS is unsigned long, while NCTYPE_ATTRID_P is unsigned long*.

cannot convert parameter 3 from 'cli::array^' to 'NCTYPE_ATTRID_P'
NCTYPE_ATTRID_P is unsigned long*
You can't pass a managed array to a pure native C++ function, you first need to 'convert' it to a fixed unsigned long* pointer.
Here's a way to do it:
unsigned long* ManagedArrayToFixedPtr(array<unsigned long>^input)
{
pin_ptr<unsigned long> pinned = &input[0];
unsigned long* bufferPtr = pinned;
unsigned long* output = new unsigned long[input->Length];
memcpy_s(output, input->Length, bufferPtr, input->Length);
return output;
}
Testing the function:
array<unsigned long>^ larray = gcnew array<unsigned long> {2,4,6,8,10,12,14,16};
unsigned long* lptr = ManagedArrayToFixedPtr(larray); //returns pointer to 2
Edit:
Rememer to #include "windows.h" to be able to use the memcpy_s function!

Related

Wrong values passed as parameter to C library using SWIG

Following my three previous posts, I can now pass a managed array of struct to my wrapped method. Here is an extract from the files:
// packer.i
typedef struct {
int width; // input
int height; // input
frame_t view; // output
frame_t dest; // output
} image_t;
CSHARP_ARRAYS(image_t, image_t)
%apply image_t INOUT[] { image_t *images }
int pack(image_t *images, int nb_images, parameters_t params);
Which generates a function with this signature:
// packer_cs.cs
public static int pack(image_t[] images, int nb_images, parameters_t arg2)
Which I call like this:
// Program.cs
var files = Directory.GetFiles("./images");
var images = new image_t[files.Length];
for (var f = 0; f < files.Length; f++)
{
using (var imgInfo = Image.FromFile(files[f]))
{
var imgStruct = new image_t()
{
width = imgInfo.Width,
height = imgInfo.Height,
dest = new frame_t(),
view = new frame_t()
};
images[f] = imgStruct;
}
}
var result = packer_cs.pack(images, images.Length, new parameters_t());
All is well and done, but when I run the pack() method, I have a protected memory access problem (System.AccessViolationException). Thankfully I have access to the source code of the C library, and Visual Studio automagically opens it for debugging and stepping through as soon as I enable unmanaged code debugging.
So, if I add a breakpoint at the start of the pack() function, and I use a watch to check images[x], I can see that the width and height values have nothing to do with what is provided (sometimes it's even 0 or negative). What's going on ? If I inspect my managed array on the C# side, the values are correctly stored and retrieved. Why doesn't C get the right values ? The other parameters (nb_images and params) don't have any problem.
Thank you !
Do the following:
Check that images[f].width and height have the values you expect
If yes, then check the SWIG-generated code to verify that those fields are properly copied.
If you can't spot any problem by looking at the code, you should break on packer_cs.pack and use the debugger to look at the wrapper code that copies the C# array to the C++ array, see what is wrong.
It is probably something in the typemaps that is incorrect. Once you know what that is, you can copy the typemaps code from SWIG source (the csharp_array.i file) to a new typemap in your .i and fix as required.

C# - When I use task::wait() method it throwing the exception

I programming Windows Store App, and I have following problem.
I use this code to record the array of numbers to a file:
auto item = KnownFolders::PicturesLibrary;
task<StorageFile^> getFileTask(item->CreateFileAsync(filename, CreationCollisionOption::ReplaceExisting));
getFileTask.then([=](StorageFile^ storageFile)
{
return storageFile->OpenAsync(FileAccessMode::ReadWrite);
}).then([](IRandomAccessStream^ m_istream)mutable
{
unsigned char a[] = { 1, 2, 3 };
auto arr = ref new Array<unsigned char>(a, sizeof(a));
auto outs = m_istream->GetOutputStreamAt(0);
auto dw = ref new DataWriter(outs);
dw->WriteBytes(arr);
return dw->StoreAsync();
}).wait();
Code is successfully compiled, but it provide an error:
MyTest.exe has triggered a breakpoint.
And it point to _REPORT_PPLTASK_UNOBSERVED_EXCEPTION(); line, that be found in ppltasks.h.
If I use .then([](DataWriterStoreOperation^){}) instead .wait(), My application don't compile with this error:
error C2338: incorrect parameter type for the callable object in 'then';
consider _ExpectedParameterType or task<_ExpectedParameterType> (see below).
Why is that? I using VS2013. Please help me.
I found the solution of this problem!!!
Right code:
unsigned char a[] = { 1, 2, 3 };
auto arr = ref new Array<unsigned char>(a, sizeof(a));
auto m_istream = ref new InMemoryRandomAccessStream();
auto outs = m_istream->GetOutputStreamAt(0);
auto dw = ref new DataWriter(outs);
dw->WriteBytes(arr);
task<unsigned int>(dw->StoreAsync()).then([=](unsigned int)
{
return item->CreateFileAsync(filename, CreationCollisionOption::ReplaceExisting);
}).then([=](StorageFile^ storageFile)
{
return storageFile->OpenAsync(FileAccessMode::ReadWrite);
}).then([=](IRandomAccessStream^ new_stream)
{
return RandomAccessStream::CopyAsync(m_istream->GetInputStreamAt(0), new_stream->GetOutputStreamAt(0));
}).then([=](UINT64 copiedBytes)
{
return;
});

Google C++ code example explanation, translating to C#

I'm working with the Google DoubleClick ad exchange API. Their examples are in C++ and well, I'm pretty awful at C++. I'm trying to convert this to C# for something I'm working on and really, I think I just need some explanation of what is actually happening in certain blocks of this code sample. Honestly I kind of know what should happen over all but I'm not sure I am getting it 'right' and with encryption/decryption there isn't a 'sort of right'.
This is the full example from their API site:
bool DecryptByteArray(
const string& ciphertext, const string& encryption_key,
const string& integrity_key, string* cleartext) {
// Step 1. find the length of initialization vector and clear text.
const int cleartext_length =
ciphertext.size() - kInitializationVectorSize - kSignatureSize;
if (cleartext_length < 0) {
// The length can't be correct.
return false;
}
string iv(ciphertext, 0, kInitializationVectorSize);
// Step 2. recover clear text
cleartext->resize(cleartext_length, '\0');
const char* ciphertext_begin = string_as_array(ciphertext) + iv.size();
const char* const ciphertext_end = ciphertext_begin + cleartext->size();
string::iterator cleartext_begin = cleartext->begin();
bool add_iv_counter_byte = true;
while (ciphertext_begin < ciphertext_end) {
uint32 pad_size = kHashOutputSize;
uchar encryption_pad[kHashOutputSize];
if (!HMAC(EVP_sha1(), string_as_array(encryption_key),
encryption_key.length(), (uchar*)string_as_array(iv),
iv.size(), encryption_pad, &pad_size)) {
printf("Error: encryption HMAC failed.\n");
return false;
}
for (int i = 0;
i < kBlockSize && ciphertext_begin < ciphertext_end;
++i, ++cleartext_begin, ++ciphertext_begin) {
*cleartext_begin = *ciphertext_begin ^ encryption_pad[i];
}
if (!add_iv_counter_byte) {
char& last_byte = *iv.rbegin();
++last_byte;
if (last_byte == '\0') {
add_iv_counter_byte = true;
}
}
if (add_iv_counter_byte) {
add_iv_counter_byte = false;
iv.push_back('\0');
}
}
Step 1 is quite obvious. This block is what I am really not sure how to interpret:
if (!HMAC(EVP_sha1(), string_as_array(encryption_key),
encryption_key.length(), (uchar*)string_as_array(iv),
iv.size(), encryption_pad, &pad_size)) {
printf("Error: encryption HMAC failed.\n");
return false;
}
What exactly is happening in that if body? What would that look like in C#? There are a lot of parameters that do SOMETHING but it seems like an awful lot crammed in a small spot. Is there some stdlib HMAC class? If I knew more about that I might better understand what's happening.
The equivalent C# code for that block is:
using (var hmac = new HMACSHA1(encryption_key))
{
var encryption_pad = hmac.ComputeHash(iv);
}
It's computing the SHA1 HMAC of the initialization vector (IV), using the given encryption key.
The HMAC function is actually a macro from OpenSSL.
Just as a comment, I think it would be easier to implement this from their pseudocode description rather than from their C++ code.

Can anyone explain the major features of a VDPROJ file?

I'm sure there must be some documentation on MSDN somewhere, but I couldn't find it. It looks like some subset/variation of JSON. Really, this question grew out of something that has always bugged me: what do all the 8:s and 3:s mean? Is this some a version number of some kind? Maybe a typing scheme? Every VDPROJ excerpt I've ever seen is filled with these "eight-colon" and "three-colon" prefixes, but this is not the sort of question search engines are really good for.
"DeployProject"
{
"VSVersion" = "3:800"
"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}"
"IsWebType" = "8:FALSE"
"ProjectName" = "8:ProjectNameRedacted"
"LanguageId" = "3:1033"
"CodePage" = "3:1252"
"UILanguageId" = "3:1033"
"SccProjectName" = "8:"
"SccLocalPath" = "8:"
"SccAuxPath" = "8:"
"SccProvider" = "8:"
"Hierarchy"
{
"Entry"
{
"MsmKey" = "8:_02F97BB7BD104F1AAA1C97C854D5DC99"
"OwnerKey" = "8:_UNDEFINED"
"MsmSig" = "8:_UNDEFINED"
}
...
If anyone just wants to berate my pitiful Google-fu, that's fine too.
As #R. Matveev pointed out, the prefix numbers likely indicate the type of data stored in the property. This would be useful when deserializing the file into an object structure.
I doubt the source code which Visual Studio used to read/write the files was ever made open source, so it's no wonder that web searches returned nothing.
The best I could find was this page on OLE Automation data types, which may not have been the actual constants, but the data types seem to match the values in the *.vdproj file.
2.2.7 VARIANT Type Constants
typedef enum tagVARENUM
{
VT_EMPTY = 0x0000,
VT_NULL = 0x0001,
VT_I2 = 0x0002,
VT_I4 = 0x0003, // 4-byte signed integer
VT_R4 = 0x0004,
VT_R8 = 0x0005,
VT_CY = 0x0006,
VT_DATE = 0x0007,
VT_BSTR = 0x0008, // BSTR (string data)
VT_DISPATCH = 0x0009,
VT_ERROR = 0x000A,
VT_BOOL = 0x000B, // Boolean value
VT_VARIANT = 0x000C,
VT_UNKNOWN = 0x000D
...
} VARENUM;

Embedding Mono in Objective-c project: How to handle returned List<>

I'm embedding Mono in an MacOSX app written in Objective-c.
I'm accessing a C# lib (DDL), which only contains a bunch of static methods returning different types.
So far I can successfully get returned int, double and string, but I'm having trouble retrieving a returned array...
For exemple, here's how I retrieve an int:
MonoDomain *domain = mono_jit_init("TestDomain");
NSBundle* mainBundle = [NSBundle mainBundle];
NSString* dll = [mainBundle pathForResource:#"TestLib86" ofType:#"dll"];
MonoAssembly* assembly = mono_domain_assembly_open(domain, [dll UTF8String]);
MonoImage* image = mono_assembly_get_image(assembly);
// Get INTEGER
// get a method handle to whatever you like
const char* descAsString = "MiniLib86.Show:GetInt()";
MonoMethodDesc* description = mono_method_desc_new(descAsString,TRUE);
MonoMethod* method = mono_method_desc_search_in_image(description, image);
// call it
void* args[0];
MonoObject *result = mono_runtime_invoke(method, NULL, args, NULL);
int int_result = *(int*)mono_object_unbox (result);
// See the result in log
NSLog(#"int result %i", int_result);
The method in C# that returns an List looks like this:
public static List<int> GetListInt()
{
return new System.Collections.Generic.List<int>{1,2,3,4,5};
}
Any help would be really appreciated !
Take a look at mono_runtime_invoke_array.

Categories