How to convert VB.net unsafe pointers? - vb.net

How to transfer this code from C# to VB.net?
This is from C#
if (local > 0)
{ //Local patches set offsets to data located elsewhere in this section
IntPtr start = data + section->_localPatchesOffset;
LocalPatch* patch = (LocalPatch*)start;
while ((int)patch - (int)start < local && patch->_dataOffset >= 0)
{ //Make the pointer offset relative to itself so it's self-contained
int ptrOffset = patch->_pointerOffset;
int* ptr = (int*)(data + ptrOffset);
*ptr = patch->_dataOffset - ptrOffset;
patch++;
}
}
Or I have this sample from C:
What exactly does it mean (byte*) in C
For example I have some byte array (like MemoryStream loaded from hole file....)
Dim arr As Byte() = New Byte() {1, 2, 33, 4, 55, 6, 7, 8, 9, 10, 10, 114, .....}
For example 33 is (at fromoffset 3) and 114 is (at tooffset 12)
This is not I think... Arr(fromoffset) = Arr(tooffset)
This is from C:
*(byte**)(SectionStart + LF->fromOffset) = SectionStart + LF->toOffset;

As jmc points out, you won't be able to convert that code to vb then compile it. I think your only option will be to make a c# DLL project, put that code into it (with any extra code it needs to function) as a method and then compile the c#
After you've done this you can reference the DLL, or you can even add the C# project to your solution continuing your VB item, and reference the project. The whole lot will compile and even the debugger will happily step from your VB.NET code into the c# and back again; these are not two separate languages when compiled - you could think of each language as merely being a whole lot of syntactic sugar for IL; but as VB simply doesn't have the sugar for unsafe stuff you'll have to do it in C#

The (byte*) is a pointer to a function with a parameter that is a pointer to a pointer of type byte.
Regarding unsafe pointers, the following is an excerpt from my Enhancing Visual Basic Book:
A Note on Recovering VarPtr, ObjPtr, StrPtr, VarPtrArray, and VarPtrStringArray.
If upgraded VB6 code required the “undocumented” VB6 functions VarPtr, ObjPtr, StrPtr, VarPtrArray, or VarPtrStringArray, use this one VB.NET function to duplicate all of them:
Imports System.Runtime.InteropServices
'--------------------------------------------------------------------------------------
' This Module Provides the memory addresses of Numeric Variables, Objects, and Strings.
'--------------------------------------------------------------------------------------
Module modVarPtr
'VB.NET version of VB6 VarPtr, ObjPtr, StrPtr, etc. (ALL of them are now supported by this one function).
'----------------------------------------------------------------------------------------------------------------------
'NOTES: Strings are not BSTR, so this returns the text address, not a BSTR pointer to the address pointing to it. This
' provides C# 'Unsafe Pointers' for VB.NET! Use the returned address right away before the Garbage Collector
' tries to change it! If we must hold it a short time, do not execute the GC.Free() instruction until done.
' We can break this code out in-line, using GC.Free() once we are done, but do not go on Break in the meantime.
' Garbage Collection will be held up until we GC.Free(), until then preventing the release of unused objects.
'----------------------------------------------------------------------------------------------------------------------
Public Function VarPtr(ByVal o As Object) As IntPtr 'Object 'catch all' (Return can also be 'As Integer').
Dim GC As GCHandle = GCHandle.Alloc(o, GCHandleType.Pinned) 'Get a trackable handle and pin (lock) the o address.
VarPtr = GC.AddrOfPinnedObject 'Get an IntPtr to the pinned o (var's data address).
GC.Free() 'free the allocated space used and unlock o address.
End Function 'Be aware IntPtr is 32-bit only on x86 compiles, otherwise it is 64-bit on 64-bit systems.
End Module
I am amaze so many VB6 users demanded a full VB OOPL environment with absolutely no sacrifice of OOPL functionality or data safety in the then-proposed VB.NET in 1999, with fist-shaking threats to abandon VB if their demands were not met. Yet, when they got exactly that, they had the gall to whine about the loss of the unsafe VarPtr, which did not jive with OOPL or data safety, but threatened user-demanded specifications. What was the result? They again threatened to abandon VB. There is a funny anecdote to describe such people, but I doubt they would appreciate it. Me? I love making fun of myself. I am a geek, and my jokes about geeks are merciless!
Finally, notice VB.NET Varptr again allows us to directly copy structure object data using the CopyMemory Pinvoke. However, even though we can grab class object memory addresses as well, we cannot use CopyMemory to copy data from or to it due to violating protected memory. Although some creative developers have managed to achieve this using intermediate memory areas, we can actually bypass employing intermediate buffers and use the .NET methods they recommend, the StructToPtr and PtrToStructure marshalling methods, to actually copy data directly to and from our local memory data and class objects. Even so, because these Unsafe Pointers are an allowed extension of OOPL rules, Microsoft should consider adding unsafe pointers to VB.NET.

Related

How can I create a standard DLL in VB6?

TL:DR; How can I compile a VB6 module file into a standard DLL which I can use across multiple VB6 applications?
I am tasked with the support of multiple legacy applications written in VB6.
All of these applications make use of piece of hardware constructed by my employer. Before I came on to work for my employer, he had outsourced the work of developing a DLL for the project to a company that is no longer capable of supporting it since the individual working for THEM recently quit and no one else is capable of figuring it out.
My employer has recently upgraded our hardware, so even worse - the DLL that Company furnished us with is no longer useful either.
Further exacerbated by the fact that the company who released to us the NEW hardware did not release to us a DLL file which is capable of running in VB6.
It now falls to me to create a DLL file ( NOT a device driver ) which is capable of facilitating communications between the new ( and hopefully the old ) devices and VB6 applications.
My knowledge of VB6 is... limited, at best. I am mostly familiar with .Net and have had much success in creating DLLs in .Net, but when it comes to VB6, I know enough to get by. I'm entering into uncharted territory here.
I'm well acquainted with the HID.dll and the SetupAPI.dll P/Invokes and structs necessary to make this work, and I was even fortunate enough to stumble upon this, which had a working bit of VB6 code which facilitates read/writing to/from HIDs connected to the system. I tested this and ( with a bit of fidgeting ) it worked for our device out of the box. But that doesn't help me because I can't compile the module into a DLL file ( let alone figuring out events in VB6 and a truck load of other things, but I'm getting ahead of myself ).
I've read and tried a few different methods and while they proved promising, they didn't work.
Google has also inundated me with a lot of red herrings and been in general not very helpful.
If necessary, I would even write it in C/C++ ( though I'd rather not if there is some other way ).
So is what I am trying to do possible? Can someone direct me to some step-by-step for this sort of thing?
EDIT 1 :
To expound a bit, when I say that "they didn't work", what I mean is that in the case of the first link, the program still failed to find the function ( with an error message like "Function entry point not found" ) and in the second case I consistently and repeatedly received a memory write error when trying to call the function ( not fun ).
Here's a link to a way to do a standard DLL, that looks more straightforward than the links you've posted. I can say that if Mike Strong ("strongm") posts code, it works, too. You might want to have a look at it.
However, it's probably better to use COM if you're able: it's easier to set up (obviously) and it also has some standard capabilities for keeping track of the object's interface, that are built into VB6. For example, when you use the TypeOf keyword, VB6 actually makes an internal call to the object's QueryInterface method, which is guaranteed to exist as one of the rules of COM (and, if you use the keyword on a reference to a standard DLL object you'll get an error).
VB6 does "static" classes by setting the class's Instancing property to GlobalMultiUse. Warning: the "static" keyword has an entirely different meaning in VB6: static local variables' values persist between method calls.
1. After your trip to 1998 to get your copy of VB6, start a new ActiveX DLL project:
2. Edit Project Properties for the name of the beast.
3. Add a Class for the interface you are creating. I cleverly named the class VB6Class because the project/DLL is named VB6DLL.
4. Write code. I added some test methods to perform complex calculations:
Option Explicit
Public Function GetAString(ByVal index As Integer) As String
Dim ret As String
Select Case index
Case 0
ret = "Alpha"
Case 1
ret = "Beta"
Case Else
ret = "Omega"
End Select
GetAString = ret
End Function
Public Function DoubleMyInt(ByVal value As Integer) As Integer
DoubleMyInt = (2 * value)
End Function
Public Function DoubleMyLong(ByVal value As Long) As Long
DoubleMyLong = (2 * value)
End Function
5. Make DLL from File menu. You may need to be running As Admin so it can register the DLL.
6. In the project which uses it, add a reference to the DLL.
Test code:
Private Sub Command1_Click()
Dim vb6 As New VB6DLL.VB6Class
Dim var0 As String
Dim var1 As Integer
Dim var2 As Long
var0 = vb6.GetAString(0)
var1 = vb6.DoubleMyInt(2)
var2 = vb6.DoubleMyLong(1234)
Debug.Print "GetAString == " & var0
Debug.Print "DoubleMyInt == " & var1
Debug.Print "DoubleMyLng == " & var2
End Sub
Result:
GetAString == Alpha
DoubleMyInt == 4
DoubleMyLng == 2468
Not sure what to do about the "truck load of other things".

How to load DLL file from Jscript file?

So I'm writing a standalone JScript file to be executed by Windows Script Host (this file is not going to be used as a web application).
My goal is to load a dll file. Just like using LoadLibrary function in a C++ application.
I tried researching the subject but I didn't come up with anything useful. I'm so lost I don't have any piece of code to share. I understand using ActiveXObject may come to my rescue. if so, any idea how to use it?
Update:
If we all agree that loading is impossible, I'll settle for validity check. Meaning, don't try to load but check if it is loaded and functional.
You can export a specific function for this purpose.
Then, from your JScript, execute rundll32.exe and check that the function ran as expected.
You might also give Gilles Laurent's DynaWrap
ocx a chance.
This kind of dll needs to be registered on the target system like regsvr32 /s DynaWrap.dll.
It is restricted to 32-bit DLLs, and this might be inconvenient for you to use, but it works on a 64bit Windows. You can't access function exported by ordinal number and you can't directly handle 64bit or greater values/pointers.
Here's a sample to call MessageBoxA from JScript:
var oDynaWrap = new ActiveXObject( "DynamicWrapper" )
// to call MessageBoxA(), first register the API function
oDynaWrap.Register( "USER32.DLL", "MessageBoxA", "I=HsSu", "f=s", "R=l" )
// now call the function
oDynaWrap.MessageBoxA( null, "MessageBoxA()", "A messagebox from JScript...", 3 )
And here from VBScript:
Option Explicit
Dim oDynaWrap
Set oDynaWrap = CreateObject( "DynamicWrapper" )
' to call MessageBoxA(), first register the API function
UserWrap.Register "USER32.DLL", "MessageBoxA", "I=HsSu", "f=s", "R=l"
' now call the function
UserWrap.MessageBoxA Null, "MessageBoxA()", "A messagebox from VBScript...", 3
To use a function you need to "register" the exported function of your DLL.
To do this you need to call the register method with a first parameter containing a string object to the complete path of the DLL, a second parameter for the exported name of the function to use, and following three paremeters describing the functions declartion in a somehow obscure syntax.
i= describes the number and data type of the functions parameters.
f= describes the type of call: _stdcall or _cdecl. Default to _stdcall.
r= describes the return values data type.
The supported data types are:
Code Variant Description
a VT_DISPATCH IDispatch*
b VT_BOOL BOOL
c VT_I4 unsigned char
d VT_R8 8 byte real
f VT_R4 4 byte real
h VT_I4 HANDLE
k VT_UNKNOWN IUnknown*
l VT_I4 LONG
p VT_PTR pointer
r VT_LPSTR string by reference
s VT_LPSTR string
t VT_I2 SHORT
u VT_UINT UINT
w VT_LPWSTR wide string
Thus the Register method call used in the examples describes MessageBoxA like this:
_stdcall LONG MessageBoxA( HANDLE, LPSTR, LPSTR, UINT );
For a explanation of MessageBoxA look at the docs on MSDN.
Please read the DynaWrap docs for more sophisticated examples... But you might need Google translate, 'cos they are written in french ;-)
To be able to use a dll as ActiveXObject, it needs to be registered as COM object. There are some restrictions on this but if you have a code for this dll, it is certainly doable.
When you register your dll as COM object, it is assigned a name. You use this name to create an object. This example from MSDN uses excel since it is already registered if you installed office.
var ExcelApp = new ActiveXObject("Excel.Application");
var ExcelSheet = new ActiveXObject("Excel.Sheet");
// Make Excel visible through the Application object.
ExcelSheet.Application.Visible = true;
// Place some text in the first cell of the sheet.
ExcelSheet.ActiveSheet.Cells(1,1).Value = "This is column A, row 1";
// Save the sheet.
ExcelSheet.SaveAs("C:\\TEST.XLS");
// Close Excel with the Quit method on the Application object.
ExcelSheet.Application.Quit();
Apart from restriction of registering dll, using dll is no different from using it as c++ or c# dll. Note that, C# (or other .NET dlls) should be ComVisible to be used from javascript this way.
EDIT: The only other way of using C/C++ dll from javascript is swig interfaces. I have not used it, therefore I can only point you in that direction.
SWIG is a software development tool that connects programs written in
C and C++ with a variety of high-level programming languages. SWIG is
used with different types of target languages including common
scripting languages such as Javascript, Perl, PHP, Python, Tcl and
Ruby.

ComBSTR assignment

I'm confused about COM string assignments. Which of the following string assignment is correct. Why?
CComBSTR str;
.
.
Obj->str = L"" //Option1
OR should it be
Obj->str = CComBSTR(L"") //Option2
What is the reason
A real BSTR is:
temporarily allocated from the COM heap (via SysAllocString() and family)
a data structure in which the string data is preceded by its length, stored in a 32-bit value.
passed as a pointer to the fifth byte of that data structure, where the string data resides.
See the documentation:
MSDN: BSTR
Most functions which accept a BSTR will not crash when passed a BSTR created the simple assignment. This leads to confusion as people observe what seems to be working code from which they infer that a BSTR can be initialized just like any WCHAR *. That inference is incorrect.
Only real BSTRs can be passed to OLE Automation interfaces.
By using the CComBSTR() constructor, which calls SysAllocString(), your code will create a real BSTR. The CComBSTR() destructor will take care of returning the allocated storage to the system via SysFreeString().
If you pass the CComBSTR() to an API which takes ownership, be sure to call the .Detach() method to ensure the BSTR is not freed. BSTRs are not reference counted (unlike COM objects, which are), and therefore an attempt to free a BSTR more than once will crash.
If you use str = CComBSTR(L"") you use the constructor:
CComBSTR( LPCSTR pSrc );
If you use str = L"" you use the assignment operator:
CComBSTR& operator =(LPCSTR pSrc);
They both would initialize the CComBSTR object correctly.
Personally, I'd prefer option 1, because that doesn't require constructing a new CComBSTR object. (Whether their code does so behind the scenes is a different story, of course.)
Option 1 is preferred because it only does one allocation for the string where as option 2 does 2 (not withstanding the creation of a new temporary object for no particular reason). Unlike the bstr_t type in VC++ the ATL one does not do referenced counted strings so it will copy the entire string across.

Copy bytes in memory to an Array in VB.NET

unfortunately I cannot resort to C# in my current project, so I'll have to solve this without the unsafe keyword.
I've got a bitmap, and I need to access the pixels and channel values directly. I'd like to go beyond Marshal.ReadByte() and Marshal.WriteByte() (and definitely beyond GetPixel and SetPixel).
Is there a way to put all the pixel data of the bitmap into a Byte array that works on both 32 and 64 bit systems? I want the exact same layout as the original bitmap, so the padding for each row (if it exists) also needs to be included.
Marshal doesn't seem to have something akin to:
byte[] ReadBytes(IntPtr start, int offset, int count)
Unless I totally missed it...
Any help greatly appreciated,
David
ps. So far all my images are in 32BppPArgb pixelformat.
Marshal does have a Method that does exactly what you are asking. See Marshall.Copy()
public static void Copy(
IntPtr source,
byte[] destination,
int startIndex,
int length
)
Copies data from an unmanaged memory
pointer to a managed 8-bit unsigned
integer array.
And there are overloads to go the other direction as well
Would something like this do? (untested):
Public Shared Function BytesFromBitmap(ByVal Image As Drawing.Bitmap) As Byte()
Using buffer As New IO.MemoryStream()
image.Save(result, Drawing.Imaging.ImageFormat.Bmp)
Using rdr As New IO.BinaryReader(buffer)
Return rdr.ReadBytes(buffer.Length)
End Using
End Using
End Function
It won't let you manipulate the pixels in a Drawing.Bitmap object directly, but it will let you copy that bitmap to a byte array, as per the question title.
Another option is serialization via the BinaryFormatter, but I think that will still require you to pass it through a MemoryStream.
VB does not offer methods for direct memory access. You have two choices:
Use the Marshal class
Write a small unsafe C# (or C++/CLI) library that handles only these operations and reference it from your VB code.
Alright, there is a third option. VB.Net does not inherently support direct memory access, but it can be accomplished. It's just ugly and prone to errors. Nonetheless, if you're willing to put in the effort, you can try building a bitmap access library using these techniques combined with the approach referenced previously.
shf301 is right on the money, but I'd like to add a link to a comprehensive explanation/tutorial on fast pixel data access. Rather than saving the image to a stream and accessing a file-in-memory, it would be better to lock the bitmap, copy pixel data out, access it, and copy it back in. The performance of this technique is pretty good.
Code is in c#, but the approach is language-neutral and easy to read.
http://ilab.ahemm.org/tutBitmap.html

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.