IJW C# to MC++ to C++ transfer array of strings to char** - c++-cli

Does anyone know how to pin the following string array parameter:
function signature int TestMethod(int argc, array<String^>^ data)
{
pin_ptr<char> p1 = &data[0];
char** p2 = &p1[0];
// char** argv = (char**)calloc(argc+1, sizeof(char*));
}
I want to pin an array<String^>^ object and convert it to the following:
char** argv = (char**)calloc(argc+1, sizeof(char*));
so I can pass it to a native c++ function
any ideas?
What about the following?
UPDATE: just curious? what about the following?
char** argv = (char**)calloc(argc+1, sizeof(char*));
for (int i = 0; i < data->Length; i++)
{
argv[i] = (char*)Marshal::StringToHGlobalAnsi(data[i]).ToPointer();
}
// Use argv as needed here...
// Cleanup
for (int i = 0; i < data->Length; i++)
{
Marshal::FreeHGlobal((IntPtr)argv[i]);
}

You can't directly pin a managed String^ into a char*. .NET Strings are actually 2 bytes per character, so you need to marshal the data manually. This will likely require building up the character arrays, copying data into them, then cleaning up after you're done.
In this case, you likely need to copy the data into your char**, use it, then clean up after yourself. This can be done via something like:
// Requires #include <msclr\marshal.h>
marshal_context context;
char** argv = new char*[data->Length];
for (int i=0;i<Length;++i)
{
const char* tmp = context.marshal_as<const char*>(clrString);
int length = strlen(tmp);
argv[i] = new char[length+1]();
strncpy(argv[i],tmp,length);
}
// Use argv as needed here...
// Cleanup
for (int i=0;i<Length;++i)
delete[] argv[i];
delete[] argv;

Related

Infinite printing on read command of character device (through cat command) [duplicate]

I am working on simple character device driver. I have implemented read and write functions in the module, the problem is when I try to read the device file using cat /dev/devicefile it is going into infinite loop i.e. reading the same data repeatedly. Can someone suggest me any solution to this problem? Below is my driver code.
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/string.h>
#include<asm/uaccess.h>
#include<linux/init.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("character device driver");
MODULE_AUTHOR("Srinivas");
static char msg[100]={0};
static int t;
static int dev_open(struct inode *, struct file *);
static int dev_rls(struct inode *, struct file *);
static ssize_t dev_read(struct file *, char *,size_t, loff_t *);
static ssize_t dev_write(struct file *, const char *, size_t,loff_t *);
static struct file_operations fops =
{
.read = dev_read,
.open = dev_open,
.write = dev_write,
.release = dev_rls,
};
static int himodule( void )
{
t = 0;
t = register_chrdev(0, "chardevdriver", &fops);
if (t < 0)
printk(KERN_ALERT"device registration failed\n");
else
printk(KERN_ALERT"device registered successfully\n");
printk(KERN_ALERT"major number is %d", t);
return 0;
}
static void byemodule(void)
{
unregister_chrdev(t, "chardevdriver");
printk(KERN_ALERT"successfully unregistered\n");
}
static int dev_open(struct inode *inod, struct file *fil)
{
printk(KERN_ALERT"inside the dev open");
return 0;
}
static ssize_t dev_read(struct file *filp, char *buff, size_t len, loff_t *off)
{
short count = 0;
while (msg[count] != 0) {
put_user(msg[count], buff++);
count++;
}
return count;
}
static ssize_t dev_write(struct file *filp, const char *buff, size_t len, loff_t *off)
{
short count = 0;
printk(KERN_ALERT"inside write\n");
memset(msg,0,100);
printk(KERN_ALERT" size of len is %zd",len);
while (len > 0) {
msg[count] = buff[count];
len--;
count++;
}
return count;
}
static int dev_rls(struct inode *inod,struct file *fil)
{
printk(KERN_ALERT"device closed\n");
return 0;
}
module_init(himodule);
module_exit(byemodule);
.read function should also correctly process its len and off arguments. The simplest way to implement reading from memory-buffered file is to use simple_read_from_buffer helper:
static ssize_t dev_read(struct file *filp, char *buff, size_t len, loff_t *off)
{
return simple_read_from_buffer(buff, len, off, msg, 100);
}
You can inspect code of that helper (defined in fs/libfs.c) for educational purposes.
BTW, for your .write method you could use simple_write_to_buffer helper.
You are not respecting the buffer size passed into the dev_read function, so you may be invoking undefined behaviour in cat. Try this:
static ssize_t dev_read( struct file *filp, char *buff, size_t len, loff_t *off )
{
size_t count = 0;
printk( KERN_ALERT"inside read %d\n", *off );
while( msg[count] != 0 && count < len )
{
put_user( msg[count], buff++ );
count++;
}
return count;
}
This problem can be solved by correctly setting *off (fourth parameter of my_read()).
You need to return count for the first time and zero from second time onwards.
if(*off == 0) {
while (msg[count] != 0) {
put_user(msg[count], buff++);
count++;
(*off)++;
}
return count;
}
else
return 0;

Marshaling a reference to a char** array

I am having trouble marshaling an array of char* by reference. The data is filled in correctly on the C++ unmanaged side. But when its returned by referernce to the managed side, I end up with a single pointer to the first array element.
//The function in C++
extern "C" DATAACCESSLAYERDLL_API void __stdcall DB_SchemaField_GetKeyValues(Schema::TSchemaFieldHandle hField, const char** &keys, const char ** &values)
{
Schema::CSchemaField *pField = CDataObjectFactory::GetObjectTpl<Schema::CSchemaField>(hField);
if (!pField) return;
Schema::TSchemaKeyValuePair::iterator itor = pField->GetKeyValues().begin();
int index = 0;
for (itor; itor != pField->GetKeyValues().end(); ++itor)
{
keys[index] = (*itor).first.c_str();
values[index] = (*itor).second.c_str();
index++;
}
return;
}
The pInvoke declaration
[System.Security.SuppressUnmanagedCodeSecurity()]
[DllImport("DataCore.dll")]
static private extern void DB_SchemaField_GetKeyValues(Int64 pField,
[In, Out] ref IntPtr[] keys, [In, Out] ref IntPtr[] values);
And finally.... the code which marshals
int keyValueCount = DB_SchemaField_GetKeyValuesCount(GetHandle());
if (keyValueCount > 0)
{
IntPtr[] KeysPtr = new IntPtr[keyValueCount];
IntPtr[] ValuesPtr = new IntPtr[keyValueCount];
DB_SchemaField_GetKeyValues(GetHandle(), ref KeysPtr, ref ValuesPtr);
for (int i = 0; i < keyValueCount; i++)
{
string key = Marshal.PtrToStringAnsi(KeysPtr[i]);
string value = Marshal.PtrToStringAnsi(ValuesPtr[i]);
if (!String.IsNullOrEmpty(key))
{
KeyValues.Add(key, value);
}
}
}
It is a mistake to pass the two const char* arrays by reference. That's one level of indirection too far for the marshaller. You need the following:
C++
extern "C" DATAACCESSLAYERDLL_API void __stdcall DB_SchemaField_GetKeyValues(
Schema::TSchemaFieldHandle hField, const char** keys, const char ** values)
C#
[System.Security.SuppressUnmanagedCodeSecurity()]
[DllImport("DataCore.dll")]
static private extern void DB_SchemaField_GetKeyValues(Int64 pField,
[Out] IntPtr[] keys, [Out] IntPtr[] values);
You'd better make sure you use the pointers that are returned immediately, because the C string returned by c_str() is only valid until the next modification of the std::string object.

Constructing bitmask ? bitwise packet

I have been wanting to experiment with this project Axon with an iOS app connecting over a tcp connection. Towards the end of the doc the protocol is explained as so
The wire protocol is simple and very much zeromq-like, where is a BE 24 bit unsigned integer representing a maximum length of roughly ~16mb. The data byte is currently only used to store the codec, for example "json" is simply 1, in turn JSON messages received on the client end will then be automatically decoded for you by selecting this same codec.
With the diagram
octet: 0 1 2 3 <length>
+------+------+------+------+------------------...
| meta | <length> | data ...
+------+------+------+------+------------------...
I have had experience working with binary protocols creating a packet such as:
NSUInteger INT_32_LENGTH = sizeof(uint32_t);
uint32_t length = [data length]; // data is an NSData object
NSMutableData *packetData = [NSMutableData dataWithCapacity:length + (INT_32_LENGTH * 2)];
[packetData appendBytes:&requestType length:INT_32_LENGTH];
[packetData appendBytes:&length length:INT_32_LENGTH];
[packetData appendData:data];
So my question is how would you create the data packet for the Axon request, I would assume some bit shifting, which I am not too clued up on.
Allocate 1 array of char or unsigned char with size == packet_size;
Decalre constants:
const int metaFieldPos = 0;
const int sizeofMetaField = sizeof(char);
const int lengthPos = metaFieldPos + sizeofMetaField;
const int sizeofLengthField = sizeof(char) * 3;
const int dataPos = lengthPos + sizeofLengthField;
If you got the data and can recognize begining of the packet, you can use constants above to
navigate by pointers.
May be these functions will help you (They use Qt, but you can easily translate them to library, that you use)
quint32 Convert::uint32_to_uint24(const quint32 value){
return value & (quint32)(0x00FFFFFFu);
}
qint32 Convert::int32_to_uint24(const qint32 value){
return value & (qint32)(0x00FFFFFF);
}
quint32 Convert::bytes_to_uint24(const char* from){
quint32 result = 0;
quint8 shift = 0;
for (int i = 0; i < bytesIn24Bits; i++) {
result |= static_cast<quint32>(*reinterpret_cast<const quint8 *>(from + i)) << shift;
shift+=bitsInByte;
}
return result;
}
void Convert::uint32_to_uint24Bytes(const quint32 value, char* from){
quint8 shift = 0;
for (int i = 0; i < bytesIn24Bits; i++) {
const quint32 buf = (value >> shift) & 0xFFu;
*(from + i) = *reinterpret_cast<const char *>(&buf);
shift+=bitsInByte;
}
}
QByteArray Convert::uint32_to_uint24QByteArray (const quint32 value){
QByteArray bytes;
bytes.resize(sizeof(value));
*reinterpret_cast<quint32 *>(bytes.data()) = value;
bytes.chop(1);
return bytes;
}

Convert decimal to binary and return array

probably there is a smart way to do that , but anyway i get error on this :
-(int*)decimalBinary:(int)decimal
{
int i=0;
int *bin;
while (decimal!=0)
{
bin[i]=decimal%2;
decimal=decimal/2;
i++;
}
return bin;
}
on the modulo line . why ?
And whats the better way to get it to array ?
Declaring
int *bin;
sets aside space for a pointer but doesn't make it point to an object. It is crucial to initialize bin before using it.
To solve your problem you can declare an array bin[4] in caller function (int main) and then pass *bin to your calling function.
The following code is adapted from This answer on how to print an integer in binary format. Storing "binary digits" into an int array is added into the code below:
#include <stdio.h> /* printf */
#include <stdlib.h> /* strtol */
const char *byte_to_binary(long x);
int main(void)
{
long lVal;
int i, len, array[18];
char buf[18];
{ /* binary string to int */
char *tmp;
char *b = "11010111001010110";
lVal=strtol(b, &tmp, 2); //convert string in "base 2" format to long int
printf("%d\n", lVal);
}
{
printf("%s", byte_to_binary(lVal));
/* byte to binary string */
sprintf(buf,"%s", byte_to_binary(lVal));
}
len = strlen(buf);
for(i=0;i<len;i++)
{ //store binary digits into an array.
array[i] = (buf[i]-'0');
}
getchar();
return 0;
}
const char *byte_to_binary(long x)
{
static char b[17]; //16 bits plus '\0'
b[0] = '\0';
char *p = b;
int z;
for (z = 65536; z > 0; z >>= 1) //2^16
{
*p++ = (x & z) ? '1' : '0';
}
return b;
}

How do i copy to a List?

I have this code in CLI
List<Codec^> ^GetCodecs()
{
List<Codec^> ^l = gcnew List<Codec^>;
bool KeepLooping = Encoder_MoveToFirstCodec();
while (KeepLooping)
{
Codec ^codec = gcnew Codec(); // here... and that call encoder_init many times... which call register codec many times... which is a mass...
codec->Name = gcnew String(Encoder_GetCurrentCodecName());
codec->Type = Encoder_GetCurrentCodecType();
char pix_fmts[200]; // array of 200 is probably enough
int actual_pix_fmts_sz = Encoder_GetCurrentCodecPixFmts( pix_fmts , 200 );
for (int i = 0 ; i < actual_pix_fmts_sz ; i++)
{
//copy from pix_fmts to the :List
codec->SupportedPixelFormats->Add(pix_fmts[i]);
}
This is the Encoder_GetCurrentCodecPixFmts function in C:
int Encoder_GetCurrentCodecPixFmts( char *outbuf , int buf_sz )
{
int i=0;
while ( (i<buf_sz) && (codec->pix_fmts[i]!=-1) )
{
outbuf[i] = codec->pix_fmts[i];
i++;
}
return i;
}
This is a new class i did:
#pragma once
using namespace System;
using namespace System::Collections::Generic;
public ref class Codec
{
public:
String^ Name;
int ID; // this is the index
int Type; // this is the type
List<int> ^SupportedPixelFormats;
Codec(void)
{
SupportedPixelFormats = gcnew List<int>;
// do nothing in the constructor;
}
};
Which contain also the: SupportedPixelFormats
The constructor in this new class should be empty but i needed somewhere to make an instance for the List make a NEW for the List.
Now in the C++ i need to transfer from pix_fmts char array to codec->Supported
Or to copy from pix_fmts to the :List
So i did as above:
codec->SupportedPixelFormats->Add(pix_fmts[i]);
But i'm not sure if this the meaning of copy.
Is that right what i did ?
It works, it's a kind of a deep copy. What makes you think it doesn't work? Do the results turn out wrong? If they do, put a breakpoint in there and try to get what is wrong.
Instead of copying one by one perhaps you can use the Enumerable::ToList extension method.
I hope this helped you.