How to convert exactly:
array<BYTE>^ mntest = gcnew array<BYTE>{0x1A, 0x1B, 0x1C};
to
BYTE unmtest [] = { 0x1A, 0x1B, 0x1C };
Resp. how to initialize unmanaged BYTE array to correct size of managed array.
Dynamic initialization of unmanaged array throws an error.
I found because dynamic initialization of static array is not allowed is conversion above possible only with using array pointer.
Related
If we have the following code:
pragma solidity >= 0.5;
contract stringsContract {
function takesTwo(string memory str, uint idx) public pure returns (bytes memory) {
bytes memory bytesStr = bytes(str);
return bytesStr[idx];
}
}
Why do we get TypeError return argument bytes1 is not explicitly convertible to expected type (type of first return variable bytes memory).
The fix was to change bytes memory to bytes:
contract stringsContract {
function takesTwo(string memory str, uint idx) public pure returns (byte) {
bytes memory bytesStr = bytes(str);
return bytesStr[idx];
}
}
Nevertheless, I'm still curious about the reason of the compilation error. Any thoughts?
Variable of type 'bytes' and 'string' are special arrays. In first code snippet you are returning an array which is not yet possible in Solidity yet.
You can find docs: https://solidity.readthedocs.io/en/develop/types.html#bytes-and-strings-as-arrays
When you return in solidity the syntax is like (value_type value_name: optional), what you tried returning bytes which is an array and with name memory, memory itself is spacial keyword in solidity
My C structure format is this:
typedef struct pt_data {
int Length; ///< Length of the Data field in bytes
uchar Data[1]; ///< The data itself, variable length
} PT_DATA;
My C function is this:
PT_STATUS PTSetFingerData (
IN PT_CONNECTION hConnection,
IN PT_LONG lSlotNr,
IN PT_DATA *pFingerData
)
Now I want to put a wrapper for this function in C#.
How can I do this? In particular, how can I do this for passing the C# PT_DATA struct to PT_DATA C struct?
You need to marshal the data manually. A variable length struct cannot be marshalled by the p/invoke marshaller.
In your case the obvious way to do this would be to declare the PTDATA* argument as byte[] in your p/invoke. Then you just need to populated the byte array before calling the function. The first 4 bytes are the length of the subsequent data.
static byte[] GetPTData(byte[] arr)
{
byte[] len = BitConverter.GetBytes(arr.Length);
byte[] data = new byte[sizeof(int) + arr.Length];
Array.Copy(len, data, sizeof(int));
Array.Copy(arr, 0, data, sizeof(int), arr.Length);
return data;
}
I seem to have a problem deleting a char* array. It crashes due to heap corruption as delete[] gets called:
typedef struct _CDB_SYMBOL_INFO {
char * name;
unsigned long address;
unsigned long value;
} CDB_SYMBOL_INFO;
// ...
for each( Symbol ^ symbol in bls->Symbols )
{
CDB_SYMBOL_INFO symbol_info;
symbol_info.name = new char[symbol->Name->Length];
Marshal::Copy( symbol->Name->ToCharArray(), 0, IntPtr( (char*) symbol_info.name ), symbol->Name->Length );
// see enumerate_cdb_symbols_callback(..)
cdb_call_back(&symbol_info, *call_back);
delete[] symbol_info.name; // Crashes here
}
// ...
I don't see the problem here ..
static int enumerate_cdb_symbols_callback(CDB_SYMBOL_INFO * info, void * call_back)
{
EnumerateSymbolsCallBack *cb = (EnumerateSymbolsCallBack*)call_back;
Symbol * symbol = alloc_symbol();
cb(0, symbol);
return 0;
}
You're calling the Marshal::Copy overload for an array of 16-bit elements (.NET System::Char is not C++ char!), and the fourth parameter is the number of elements not the number of bytes, so you're actually copying symbol->Name->Length * 2 bytes, which is twice the size of your buffer. The resulting overflow corrupts heap metadata, causing delete[] to crash.
Either use a buffer of type wchar_t, which is the C++ type that matches System::Char, or convert the string to ASCII, perhaps by replacing ToCharArray() with Encoding::ASCII::GetBytes(symbol->Name). Or UTF-8, in which case you can't assume that symbol->Name->Length is the necessary buffer size.
An even simpler way is to use the marshal_as library that comes with C++/CLI:
#include <msclr\marshal_cppstd.h>
using namespace msclr::interop;
for each( Symbol ^ symbol in bls->Symbols )
{
std::string sym_name = marshal_as<std::string>(symbol->Name);
CDB_SYMBOL_INFO symbol_info;
symbol_info.name = &sym_name[0];
// see enumerate_cdb_symbols_callback(..)
cdb_call_back(&symbol_info, *call_back);
}
It does some unspecified single-byte character encoding (most likely ASCII), and uses RAII to free the memory automatically.
I am new to managed code and i need to pass array of pointers to different structures to windows form using C++/CLI , but it didn`t work !
My problem is in the managed array, how can i correctly access its elements .
The code sequence :
array<void*> ^ ptr;//here ptr value is undefined , type array<void*> ^
ptr = gcnew array<void*> (2);// length 0x2 , 0x0 and 0x1 values are undefined of type void
class1::struct1 structObj1;
class2::struct2 structObj2;
ptr[0] = &structObj1;// value is empty of type void!!
ptr[1] = &structObj2;//value is empty of type void!!
When i watched ptr , i found the above comments.
Notice that repeating code but using unmanaged array works probably
void* ptr[2];//here ptr value is undefined , type void*[]
class1::struct1 structObj1;
class2::struct2 structObj2;
ptr[0] = &structObj1;// value is address1 of type void*
ptr[1] = &structObj2;//value is address2 of type void*
Can anyone see where is the problem??
Do I need to use unmanaged array then convert to managed? If yes, how can I do it ??
Passing unmanaged pointers in a managed array may be valid C++/CLI, but it's definitely not the ideal way to do things. Do consider creating a custom managed class (ref class in C++/CLI) to hold the structures, instead of passing around pointers.
For this, I'm assuming that struct1 and struct2 are unmanged structs. This answer only applies if that is the case.
Your existing code works for me. Here's my version, with some debugging added in.
public struct struct1 { int foo; };
public struct struct2 { float bar; };
int main(array<System::String ^> ^args)
{
array<void*> ^ ptr;
ptr = gcnew array<void*> (2);
for(int i = 0; i < ptr->Length; i++)
Debug::WriteLine("ptr[{0}] = {1:X8}", i, reinterpret_cast<int>(ptr[i]));
struct1 structObj1;
struct2 structObj2;
ptr[0] = &structObj1;
ptr[1] = &structObj2;
for(int i = 0; i < ptr->Length; i++)
Debug::WriteLine("ptr[{0}] = {1:X8}", i, reinterpret_cast<int>(ptr[i]));
struct1* pointerToStructObj1 = reinterpret_cast<struct1*>(ptr[0]);
structObj1.foo = 4;
Debug::WriteLine("pointerToStructObj1->foo = {0}", pointerToStructObj1->foo);
}
Output:
ptr[0] = 00000000
ptr[1] = 00000000
ptr[0] = 0013F390
ptr[1] = 0013F394
pointerToStructObj1->foo = 4
Edit
To use Debug::WriteLine, add using namespace System::Diagnostics.
The debugger doesn't know how to display the contents of a void*, so it just displays blank. It does display a null pointer differently, though: null shows up as <undefined value>, non-null shows up as just blank.
My philosophy on C++/CLI is: If you're going to write managed code, write managed code. Consider replacing your vector with a managed List. If you still need unmanaged objects, I strongly urge you to consider writing a managed class with properly typed pointers, rather than a void* array.
To implement such a class, create whatever fields you need, just be sure that they're pointers, not direct. (vector<foo>* instead of vector<foo>.) Create the objects with new in the constructor, and delete them in the destructor (which is called on Dispose) & finalizer.
I need to take a char [] array and copy it's value to another, but I fail every time.
It works using this format:
char array[] = { 0x00, 0x00, 0x00 }
However, when I try to do this:
char array[] = char new_array[];
it fails, even though the new_array is just like the original.
Any help would be kindly appreciated.
Thanks
To copy at runtime, the usual C method is to use the strncpy or memcpy functions.
If you want two char arrays initialized to the same constant initializer at compile time, you're probably stuck with using #define:
#define ARRAY_INIT { 0x00, 0x00, 0x00 }
char array[] = ARRAY_INIT;
char new_array[] = ARRAY_INIT;
Thing is, this is rarely done because there's usually a better implementation.
EDIT: Okay, so you want to copy arrays at runtime. This is done with memcpy, part of <string.h> (of all places).
If I'm reading you right, you have initial conditions like so:
char array[] = { 0x00, 0x00, 0x00 };
char new_array[] = { 0x01, 0x00, 0xFF };
Then you do something, changing the arrays' contents, and after it's done, you want to set array to match new_array. That's just this:
memcpy(new_array, array, sizeof(array));
/* ^ ^ ^
| | +--- size in bytes
| +-------------- source array
+-------------------------destination array
*/
The library writers chose to order the arguments with the destination first because that's the same order as in assignment: destination = source.
There is no language-level built-in means to copy arrays in C, Objective-C, or C++ with primitive arrays like this. C++ encourages people to use std::vector, and Objective-C encourages the use of NSArray.
I'm still not sure of exactly what you want, though.