vb.net win32api pointer to integer array parameter - vb.net

Because I need to extract an icon from a file, but not the first icon, I cannot use the vb.net icon extraction function. The WIN32API function that should do this expects a pointer to an integer array.
How can I provide this type as a parameter?
Declare Function ExtractIconEx Lib "shell32.dll" Alias "ExtractIconExA" _
(ByVal lpszFile As String, _
ByVal nIconIndex As Integer, _
ByRef phiconLarge As Integer, _
ByRef phiconSmall As Integer, _
ByVal nIcons As Long) As Integer
Dim icons As integer()
ExtractIconEx("%systemroot%/shell32.dll", 15, icons, 0, 5)
I've taken a gander at the System.Reflection.Pointer class?/namespace?, but the documentation is sparse and less than sensible.
IntPtr doesn't provide support for arrays afaikt
Ok tx to Hans I've managed to correct the signature to:
<Runtime.InteropServices.DllImport("shell32.dll", _
CharSet:=Runtime.InteropServicesCharSet.Auto)> _
Shared Function ExtractIconEx(ByVal szFileName As String, _
ByVal nIconIndex As Integer, _
ByRef phiconLarge() As IntPtr, _
ByRef phiconSmall() As IntPtr, _
ByVal nIcons As UInteger) As UInteger
End Function
...
Dim icons(8) As IntPtr, smicons(8) As IntPtr
MsgBox(ExtractIconEx("%systemroot%/shell32.dll", 15, icons, smicons, 1))
Try
MsgBox(icons.Count)
Catch ex As Exception
MsgBox(ex.Message & " by " & ex.Source)
End Try
...
The subsequent calls always cause an exception (Value cannot be null). I get a return value of 4294967295, which is the maximum 32 bit integer value.
Any ideas how to tame this function and make it work?

ByRef phiconLarge() As IntPtr, _
ByRef phiconSmall() As IntPtr, _
The VB.NET declaration on that webpage has a bug, these arrays need to be passed ByVal, not ByRef. Note how they got it correct in the example code on the bottom of the page.
I edited the page to correct the bug.

Related

System.ArgumentException: Win32 handle that was passed to Icon is not valid or is the wrong type

I have the below code to load an icon using Shell32 dll. It works fine on my machine. But one of the systems in production environment got an exception saying "System.ArgumentException: Win32 handle that was passed to Icon is not valid or is the wrong type".
Any idea why we get this error? Thank you!
Public Function GetExecutableIcon() As Icon
Dim large As IntPtr
Dim small As IntPtr
ExtractIconEx(Application.ExecutablePath, 0, large, small, 1)
Return Icon.FromHandle(small)
End Function
<DllImport("Shell32")> _
Public Shared Function ExtractIconEx(ByVal sFile As String, ByVal iIndex As Integer,
ByRef piLargeVersion As IntPtr, ByRef piSmallVersion As IntPtr,
ByVal amountIcons As Integer) As Integer
End Function
Try this:
<DllImport("Shell32")> _
Public Shared Function ExtractIconEx(ByVal sFile As String, ByVal iIndex As Integer,
ByRef piLargeVersion As IntPtr, ByRef piSmallVersion As IntPtr,
ByVal amountIcons As Integer) As Integer
Public Function GetExecutableIcon() As Icon
Dim num As Integer = 10
Dim large(num - 1) As IntPtr
Dim small(num - 1) As IntPtr
ExtractIconEx("C:\Windows\System32\Shell32.dll", 0, large(0), small(0), num)
Return Icon.FromHandle(small(6)) 'change the index accordingly
End Function
Is your declaration correct? http://www.pinvoke.net/default.aspx/shell32.ExtractIconEx shows
<DllImport("shell32.dll", CharSet:=CharSet.Auto)> _
Shared Function ExtractIconEx(ByVal szFileName As String, _
ByVal nIconIndex As Integer, _
ByVal phiconLarge() As IntPtr, _
ByVal phiconSmall() As IntPtr, _
ByVal nIcons As UInteger) As UInteger
End Function

Access Violation Exception RegEnumValue

I'm using this code to enumerate all values in a registry key.
Private ReadOnly HKeyLocalMachine As New IntPtr(-2147483646)
Private Const KeyQueryValueWow64Key As Integer = &H101
Private Const ErrorNoMoreItems As Integer = &H103
Private Const errorSuccess As Integer = &H0
Dim keyHandle As IntPtr = Nothing
RegOpenKeyEx(HKeyLocalMachine, newPath, 0, KeyQueryValueWow64Key, keyHandle)
If keyHandle = Nothing Then
Return "Error accessing registry key"
End If
Dim index As Integer = 0
Dim valueName As New StringBuilder(1000)
Dim valueLenght As UInteger
Dim valueDataLenght As IntPtr
If RegQueryInfoKey(keyHandle, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, valueLenght, valueDataLenght, Nothing, Nothing) = errorSuccess Then
Debug.WriteLine("SUCCESS IN REGQUERYINFOKEY")
End If
Do
returnValue = RegEnumValue(keyHandle, index, valueName, valueLenght, Nothing, Nothing, datalenght, valueDataLenght)
If returnValue = errorSuccess Then
Debug.WriteLine("Success")
End If
index = index + 1
Loop Until returnValue = ErrorNoMoreItems
Here are my API declarations:
<DllImport("advapi32.dll", CharSet:=CharSet.Unicode)> _
Private Shared Function RegOpenKeyEx( _
hKey As IntPtr, _
subKey As String, _
ulOptions As Integer, _
samDesired As Integer, _
ByRef hkResult As IntPtr _
) As Integer
End Function
<DllImport("advapi32.dll", SetLastError:=True)> _
Private Shared Function RegEnumValue( _
ByVal hKey As IntPtr, _
ByVal dwIndex As Integer, _
ByVal lpValueName As StringBuilder, _
ByRef lpcValueName As UInteger, _
ByVal lpReserved As IntPtr, _
ByVal lpType As IntPtr, _
ByVal lpData As IntPtr, _
ByVal lpcbData As IntPtr _
) As Integer
End Function
<DllImport("advapi32.dll")> _
Private Shared Function RegQueryInfoKey( _
hkey As IntPtr, _
ByRef lpClass As StringBuilder, _
ByRef lpcbClass As UInteger, _
lpReserved As IntPtr, _
ByRef lpcSubKeys As UInteger, _
ByRef lpcbMaxSubKeyLen As UInteger, _
ByRef lpcbMaxClassLen As UInteger, _
ByRef lpcValues As UInteger, _
ByRef lpcbMaxValueNameLen As UInteger, _
ByRef lpcbMaxValueLen As IntPtr, _
ByRef lpcbSecurityDescriptor As UInteger, _
lpftLastWriteTime As IntPtr _
) As Integer
End Function
And i'm getting AccessViolationException when i pass the last parameter of RegEnumValue non-null, if i pass a null IntPtr the function succeeds but no data is retrieved, only the name.
I've tried changing the API variables with no luck, the other two functions always succeed.
The reason that the code fails is that you did not initialise valueDataLenght. Incidentally, you mean to name this variable valueDataLength.
You need the IntPtr variable valueDataLength to refer to a DWORD that contains the length of the data buffer. Using IntPtr here makes life difficult for you. I'd declare the parameter like this instead:
ByRef lpcbData As Integer

ReadProcessMemory declaration

I currently have it defined as
Private Declare Function ReadProcessMemory1 Lib "kernel32" Alias "ReadProcessMemory" (ByVal hProcess As IntPtr, ByVal lpBaseAddress As Integer, ByRef lpBuffer As Integer, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
and I have another declaration for each type.
I'm trying to use this instead
<DllImport("kernel32.dll", SetLastError:=True)> _
Public Shared Function ReadProcessMemory( _
ByVal hProcess As IntPtr, _
ByVal lpBaseAddress As Integer, _
<Out()> ByRef lpBuffer As Byte(), _
ByVal dwSize As Integer, _
ByRef lpNumberOfBytesRead As Integer) As Boolean
End Function
Which is off pvinvoke.net, heres how I'm trying to use it:
Public Shared Function Int(address As Integer)
Dim buffer(3) As Byte
ReadProcessMemory(pHandle, address, buffer, 4, 0)
Return BitConverter.ToInt32(buffer, 0)
End Function
This errors and says Attempt to read or write protected memory, but I use the old RPM declaration I have like this and it works fine.
Public Shared Function Int(address As Integer)
Dim buffer As Integer
ReadProcessMemory(pHandle, address, buffer, 4, 0)
Return buffer
End Function
What am I doing wrong?
Your p/invoke declaration is wrong. It should be:
<DllImport("kernel32.dll", SetLastError:=True)> _
Public Shared Function ReadProcessMemory( _
ByVal hProcess As IntPtr, _
ByVal lpBaseAddress As IntPtr, _
<Out()> ByVal lpBuffer As Byte(), _
ByVal dwSize As IntPtr, _
ByRef lpNumberOfBytesRead As IntPtr) As Boolean
End Function

Errors calling WriteFile from visual basic .net 2010 on a named pipe

I've been banging my head on this one all day, and I just can't make sense of the various (sometimes conflicting) documentation on this. To add to the confusion, at some point during the day, this did (sort of) work - i.e. didn't throw an access violation error. But the data at the other end of the pipe was nonsense, so I suspect it only 'worked' by accident.
I have a vb.net program (using .net 3.0 so no support for System.IO.NamedPipes :( ) which creates a named pipe and waits for another app to connect and send some data. As an 'ack', I then want the vb program to send back the total length of the message received. I'm able to create the pipe, wait for a connection and receive the message, but it barfs on trying to send the 'ack' using WriteFile. The (current) definition I'm using for WriteFile is based on the corresponding ReadFile, which seems to work fine:
Declare Function ReadFile Lib "kernel32" ( _
ByVal hFile As Integer, _
ByRef lpBuffer As Byte, _
ByVal nNumberOfBytesToRead As Integer, _
ByRef lpNumberOfBytesRead As Integer, _
ByVal lpOverlapped As Integer) _
As Integer
Declare Function WriteFile Lib "kernel32" ( _
ByVal hFile As Long, _
ByRef lpBuffer As Byte, _
ByVal nNumberOfBytesToWrite As Integer, _
ByRef lpNumberOfBytesWritten As Integer, _
ByVal lpOverlapped As Integer) _
As Integer
The stripped down code (error checking and debug printing removed) looks like this:
Dim openMode = PIPE_ACCESS_DUPLEX Or FILE_FLAG_FIRST_PIPE_INSTANCE
Dim pipeMode = PIPE_WAIT Or PIPE_TYPE_MESSAGE Or PIPE_READMODE_MESSAGE
Dim res ' Result of dll calls
pipeN2Q = CreateNamedPipe("\\.\pipe\N2Q", openMode, pipeMode, 10, 1024, 1024, 2000, IntPtr.Zero)
res = ConnectNamedPipe(pipeN2Q, 0)
Dim rxCount As Integer = 0 ' To hold the number of bytes received
Dim txCount As Integer = 0 ' To hold the number of bytes sent
Dim txReq As Integer = 2 ' To hold the number of bytes we're going to ask to be sent during the 'ack'
Dim dataIn(256) As Byte
res = ReadFile(pipeN2Q, dataIn(0), 256, rxCount, Nothing)
Dim recvBuffer As String = System.Text.Encoding.ASCII.GetString(dataIn, 0, rxCount)
Dim dataOut(2) As Byte
dataOut(0) = 42
dataOut(1) = 43
res = WriteFile(pipeN2Q, dataOut(0), txReq, txCount, Nothing)
Once the code gets to WriteFile, it throws an AccessViolationException - "Attempted to read or write protected memory." I'm assuming this is complaining about the dataOut parameter, but it gives no further details. Things I've tried so far include:
Changing the declaration of WriteFile so that lpBuffer is declared: ByVal lpBuffer as IntPtr
Allocating dataOut using Marshal.AllocHGlobal(txReq) and initialised using Marshal.WriteInt16()
Allocating a large buffer for dataOut (1024 bytes) and initialising them to zeros
To be clear, the message coming from the other app is received perfectly and recvBuffer has the string exactly as sent. I just can't persuade WriteFile to cooperate (except once, perhaps by chance, and I haven't been able to repeat it). I'm hoping it's just something in either the declaration or the initialisation of the variables - any clues?
Based on Hans' suggestion to use pinvoke.net, here is the combination of signatures and calls which eventually worked for me - just in case anyone else can use it. I know I should probably convert those first 3 declarations to follow the same format as ReadFile / WriteFile, but it's working for now...
Declare Function CreateNamedPipe Lib "kernel32" Alias "CreateNamedPipeA" ( _
ByVal lpName As String, ByVal dwOpenMode As Integer, _
ByVal dwPipeMode As Integer, ByVal nMaxInstances As Integer, _
ByVal nOutBufferSize As Integer, ByVal nInBufferSize As Integer, _
ByVal nDefaultTimeOut As Integer, ByVal lpSecurityAttributes As IntPtr) _
As SafeFileHandle
Declare Function ConnectNamedPipe Lib "kernel32" ( _
ByVal hNamedPipe As SafeFileHandle, ByVal lpOverlapped As System.Threading.NativeOverlapped) _
As SafeFileHandle
Declare Function CloseHandle Lib "kernel32" ( _
ByVal hFile As SafeFileHandle) _
As Integer
<DllImport("kernel32.dll", SetlastError:=True)> Friend Shared Function WriteFile( _
ByVal File As SafeFileHandle, _
ByVal Buffer As System.Text.StringBuilder, _
ByVal NumberOfBytesToWrite As Integer, _
ByRef NumberOfBytesWritten As Integer, _
ByRef Overlapped As System.Threading.NativeOverlapped) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("kernel32.dll")> Friend Shared Function ReadFile( _
ByVal File As SafeFileHandle, _
ByVal Buffer As System.Text.StringBuilder, _
ByVal NumberOfBytesToRead As Integer, _
ByRef NumberOfBytesRead As Integer, _
ByRef Overlapped As System.Threading.NativeOverlapped) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
...
pipeN2Q = CreateNamedPipe("\\.\pipe\N2Q", openMode, pipeMode, 10, 1024, 1024, 2000, IntPtr.Zero)
If Not pipeN2Q.IsInvalid Then
If Not ConnectNamedPipe(pipeN2Q, Nothing).IsInvalid Then
Dim rxCount As Integer = 0
Dim txCount As Integer = 0
Dim dataIn As New System.Text.StringBuilder
res = ReadFile(pipeN2Q, dataIn, 256, rxCount, Nothing)
If res <> 0 Then
Dim dataOut As New StringBuilder(dataIn.Length.ToString)
res = WriteFile(pipeN2Q, dataOut, dataOut.Length, txCount, Nothing)
Else
Debug.Print("ReadFile ERROR: " & Err.LastDllError)
End If
Else
Debug.Print("ConnectNamedPipe ERROR: " & Err.LastDllError)
End If
If CloseHandle(pipeN2Q) <> 0 Then
Debug.Print("Pipe closed")
Else
Debug.Print("CloseHandle ERRPR: " & Err.LastDllError)
End If
Else
Debug.Print("CreateNamedPipe ERROR: " & Err.LastDllError)
End If

Can I Call unmanaged Mobile CE Dll from Full .Net Framework (Run on Desktop)

I have an Unmanaged Lib compiled for Windows Ce. I am trying to call this dll from VB.net Full Framework .Net 4 Client Profile Windows application. I am trying to use the same code that I use in the Compact Framework application. It compiles without errors and runs but when Invoking a function I get error ex = {"An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)"} Is it possible to use the Mobile Unmanaged Dll on the Desktop ? Here is the Wrapper code I use to call the Dll:
Imports System
Imports System.Runtime.InteropServices
Module modM300CF
Public Declare Function ParseBarCode Lib "M300LAP.dll" ( _
ByVal P_track1 As Byte(), ByVal P_t1length As Short, _
ByRef P_DLStatus As Short, _
ByRef P_StateID As Byte, _
ByRef P_DAge As Short, _
ByRef P_CardName As Byte, _
ByRef P_Address As Byte, _
ByRef P_City As Byte, _
ByRef P_State As Byte, _
ByRef P_Zip As Byte, _
ByRef P_DLNumber As Byte, _
ByRef P_Expdate As Byte, _
ByRef P_Bdate As Byte, _
ByRef P_DLAlpha As Byte, _
ByRef P_DHair As Byte, _
ByRef P_DEyes As Byte, _
ByRef P_DHeight As Byte, _
ByRef P_DWeight As Byte, _
ByRef P_DSex As Byte) As Short
Public Declare Function ParseMagStripe Lib "M300LAP.dll" ( _
ByVal P_track1 As Byte(), ByVal P_t1length As Short, _
ByVal P_track2 As Byte(), ByVal P_t2length As Short, _
ByVal P_track3 As Byte(), ByVal P_t3length As Short, _
ByRef P_DLStatus As Short, _
ByRef P_StateID As Byte, _
ByRef P_DAge As Short, _
ByRef P_CardName As Byte, _
ByRef P_Address As Byte, _
ByRef P_City As Byte, _
ByRef P_State As Byte, _
ByRef P_Zip As Byte, _
ByRef P_DLNumber As Byte, _
ByRef P_Expdate As Byte, _
ByRef P_Bdate As Byte, _
ByRef P_DLAlpha As Byte, _
ByRef P_DHair As Byte, _
ByRef P_DEyes As Byte, _
ByRef P_DHeight As Byte, _
ByRef P_DWeight As Byte, _
ByRef P_DSex As Byte) As Short
End Module
I could be wrong but I believe the binary format is slightly different on Windows CE which might explain why desktop windows is having difficulty making sense of the image file