How to convert data contained in (managed) array<System::Byte^> to other managed types? - msdn

I'm reading in data as an array< System::Byte^ > in Visual C++ and want to assign it to managed types such as UInt16, UInt32, etc. How do I do this in Visual C++?
suppose I have a function parameter- array< System::Byte^ > receivedBytes, and I want to assign the first 2 bytes to a UInt16, and the next 4 bytes to a UInt32.

This isn't really (managed) C++ specific, but you might try using the various To* methods of the BitConverter class. I've used them in completely managed C# (for example to read raw SHA1 values into 5 integers), and they work well.

Related

C# Bond: string to wstring

In the Bond C# manual, it notes the following:
These following changes will break wire compatibility and are not recommended:
Adding or removing required fields
Incompatible change of field types (any type change not covered above); e.g.: int32 to string, string to wstring
...
But it doesn't explain why. The use case here is that I'm using Bond that connects a C# application with a C++ backend. The field is currently a string. I want to change it to a wstring. The manual notes that C# strings can handle C++ strings and C++ wstrings. Therefore, why I can't I just change the field type from string to wstring? Why does this break wire compat?
In Bond's binary formats, strings are UTF8 encoded (no BOM) and wstrings are UTF16-LE encoded. If you were to switch a field from string to wstring, the reading side would try to interpret UTF8 data as UTF16-LE data. These two encodings are not compatible with each other, hence a field type change from string to wstring is a breaking change.
Note that the manual says "For example C# string can represent either Bond type string or wstring." It does not say anything about C++ types. When working with Bond across C# and C++, there are three type systems: Bond's, C#'s, and C++'s.
If on the C++ side, you want to use something akin to std::wstring to store the field in memory, take a look as using Custom type mapping with the string concept.

Proper way to define and initialize Decimal in Managed C++/CLI

This seems like it should be really simple but I'm having trouble finding the answer online.
What's the proper way to define a Decimal variable and initialize it with constant value in C++/CLI?
In C# it would be:
decimal d = 1.1M;
In C++/CLI I've been doing:
Decimal d = (Decimal)1.1;
Which works for some numbers, but I suspect it's just converting from double.
I notice there's a constructor: Decimal(int, int, int, bool, unsigned char) but was hoping there's an easier way to deal with large specific numbers.
You are indeed casting the number. You can, as mentioned, parse from a string or divide integers, or you may want to use the BigRational data type. Independently of the option you choose you may create a utility method in a static class to do it so you don't have to repeat it all the time.
You can also suggest on the VS UserVoice Site to allow number sufixes like in C#.

Pass data of arbitrary type between VBA and dll

So I am working on an Excel Project that is going to load a C++ dll using VBA. What I'd like to do is to be able to pass an Excel range with no specific type (data can be numerical or categorical) to the C++ dll (The best way I can describe my Excel range is of the type variant).
So the steps probably involve:
Load the dll in VBA
Send the excel range to dll (The range may contain columns of numbers and/or columns of strings)
manipulate the data from excel in the dll file
I am thinking of using excel variant and C++ variant. But it's not clear for me how to use the C++ variant as I couldn't find any good documentations on it.
Another suggestion I received was to ues COM programming.
My Questions:
Could a kind soul possibly provide pointers for me on how to proceed? (e.g. by providing the C++ prototype, and a simple example of how to handle the variant)
Does anyone know any good documentation/tutorial on using C++ Variants (and perhaps jointly with VBA)?
Is using COMs preferable to using VARIANTS if speed is an issue?
Is using the C API an option?
UPDATE:
The size of the ranges I need to manipulate can be large (~ 500,000 rows).
Speed is a factor, thus, I'd like to avoid unnecessary copying as much as possible.
Provided you only want to pass data to the dll (and not pointers to actual Excel objects such as Range), you have two fundamental options:
You have huge data sets and want to avoid copying as much as possible.
In this case you might want to pass that same Variant array you get by calling Range.Value. In order to do that, you will have to write a little TLB to reference from VB, in which you would describe your exported C++ function as expecting a SAFEARRAY(VARIANT)*. This is because the Declare operator will not let you actually pass a SAFEARRAY*.
The function will look like this:
LONG __stdcall ReturnArrLowerBound(SAFEARRAY** ppArr)
{
if (ppArr == NULL) return -1;
SAFEARRAY* pArr = (*ppArr);
LONG res = 0;
SafeArrayGetLBound(pArr, 1, &res);
return res;
}
And the TLB descripion will look like that:
[
uuid(A686B138-D8CE-462e-AEF2-75DA4DBF1C75)
]
library foo
{
[
dllname("TestSafearray.dll")
]
module vb
{
[entry("ReturnArrLowerBound")]
LONG __stdcall ReturnArrLowerBound(SAFEARRAY(VARIANT)* ppArr);
}
}
And your C++ project will obviously include a def file:
LIBRARY "TestSafearray"
EXPORTS
ReturnArrLowerBound
Your data sets are reasonably sized and you don't mind a little bit of copying.
Then make your C++ function to accept a mere int[] and Declare it in VB as accepting arr() as Long. On VB side, allocate an array on Longs and copy the elements into it from the Range.Value array.

What is the equivalent of a C pointer in VB.NET?

What is the most similar thing in VB.NET to a pointer, meaning like C pointers?
I have a TreeView within a class. I need to expose some specific nodes (or leaves) that can be modified by external objects.
C#, and I also believe VB.Net, will work on the concept of references. Essentially, it means when you say
A a = new A()
the 'a' is a reference, and not the actual object.
So if I go
B b = a
b is another reference to the same underlying object.
When you want to expose any internal objects, you can simply do so by exposing 'properties'. Make sure, that you do not provide setters for the properties, or that if you do, there is code to check if the value is legal.
ByRef is used when you want to pass the object as a parameter, and when you want the called method to be able to change the reference (as opposed to the object).
As mentioned above, if you post some code, it will be easier to explain.
Nathan W has already suggested the IntPtr structure which can represent a pointer or handle, however, whilst this structure is part and parcel of the .NET framework, .NET really doesn't have pointers per-say, and certainly not like C pointers.
This is primarily because the .NET Framework is a "managed" platform and memory is managed, assigned, allocated and deallocated by the CLR without you, the developer, having to worry about it (i.e. no malloc commands!) It's mostly because of this memory management that you don't really have access to direct memory addresses.
The closest thing within the .NET Framework that can be thought of as a "pointer" (but really isn't one) is the delegate. You can think of a delegate as a "function pointer", however, it's not really a pointer in the strictest sense. Delegates add type-safety to calling functions, allowing code that "invokes" a delegate instance to ensure that it is calling the correct method with the correct parameters. This is unlike "traditional" pointers as they are not type-safe, and merely reference a memory address.
Delegates are everywhere in the .NET Framework, and whenever you use an event, or respond to an event, you're using delegates.
If you want to use C# rather than VB.NET, you can write code that is marked as "unsafe". This allows code within the unsafe block to run outside of the protection of the CLR. This, in turn, allows usage of "real" pointers, just like C, however, they still do have some limitations (such as what can be at the memory address that is pointed to).
Best way to do it is to just allocate everything manually:
You can move up OR down each Stack at free will without Pushing or Popping.
Dim Stack(4095) as Byte 'for 8bit - 1 bytes each entry
Dim Stack(4095) as Integer 'for 16bit - 2 bytes each entry
Dim Stack(4095) as Long 'for 32bit - 4 bytes each entry
Dim Stack(4095) as Double 'for 64 bit - 8 bytes each entry
Dim i as integer 'Where i is your Stack Pointer(0 through 4095)
Dim int as integer 'Byte Integer Long or Double (8, 16, 32, 64 bit)
for i = 0 to 4095
int = i
Stack(i) = int/256 'For 8bit Byte
Stack(i) = int 'For 16bit Integer
Stack(i) = Microsoft.VisualBasic.MKL$(int) 'For 32bit Long
Stack(i) = Microsoft.VisualBasic.MKD$(int) 'For 64bit Double
MsgBox(Microsoft.VisualBasic.HEX$(Stack(i))) 'To See Bitwise Length Per Entry
next i
If you're looking to pass something back from a subroutine you can pass it by reference - as in "ByRef myParamter as Object".
Best answer depends, to some degree, on what you're trying to do.
If you are using VB the only thing that is really close to a pointer is a IntPtr. If you have access to C# you can use unsafe C# code to do pointer work.

Visual Basic 6.0 to VB.NET declaration

How do I declare "as any" in VB.NET, or what is the equivalent?
The closest you can get is:
Dim var as Object
It's not exactly the same as VB6's as Any (which stores values in a Variant) but you can store variables of any type as Object, albeit boxed.
VB.NET does not support the as any keyword, VB.NET is a strongly typed language, you can however (with .NET 3.5) use implicit typing in VB
Dim fred = "Hello World" will implicitly type fred as a string variable. If you want to simply hold a value that you do not know the type of at design time then you can simply declare your variable as object (the mother of all objects) NOTE, this usually is a red flag for code reviewers, so make sure you have a good reason ready :-)
As Any must be referring to Windows API declarations, as it can't be used in variable declarations. You can use overloading: just repeat the declarations for each different data type you wish to pass. VB.NET picks out the one that matches the argument you pass in your call.
This is better than As Any was in VB6 because the compiler can still do type-checking.
I suppose you have problems with converting WinAPI declarations. Sometimes you can get away if you just declare your variable as string or integer because that is the real type of value returned.
You can also try marshaling:
<MarshalAsAttribute(UnmanagedType.AsAny)> ByRef buff As Object
VB.NET doesn't support the "As Any" keyword. You'll need to explicitly specify the type.