I am trying to write text to Win32 resources, but I have failed with it.
Here it is after writing the text:
And here is how it should look like:
Here's my code:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
WriteResourceStr(Target.Text, "hello")
End Sub
#Region "Second"
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
Private Shared Function UpdateResource(ByVal hUpdate As IntPtr, ByVal lpType As String, ByVal lpName As String, ByVal wLanguage As UShort, ByVal lpData As IntPtr, ByVal cbData As UInteger) As Boolean
End Function
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
Private Shared Function BeginUpdateResource(ByVal pFileName As String, <MarshalAs(UnmanagedType.Bool)> ByVal bDeleteExistingResources As Boolean) As IntPtr
End Function
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
Private Shared Function EndUpdateResource(ByVal hUpdate As IntPtr, ByVal fDiscard As Boolean) As Boolean
End Function
Public Function WriteResourceStr(ByVal filename As String, ByVal bytes As String) As Boolean
Try
Dim handle As IntPtr = BeginUpdateResource(filename, False)
Dim file1 As String = bytes
Dim fileptr As IntPtr = ToPtr(file1)
Dim res As Boolean = UpdateResource(handle, "RCData", "CONFIG", 1, fileptr, System.Convert.ToUInt16(file1.Length))
EndUpdateResource(handle, False)
Catch ex As Exception
Return False
End Try
Return True
End Function
Private Function ToPtr(ByVal data As Object) As IntPtr
Dim h As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned)
Dim ptr As IntPtr
Try
ptr = h.AddrOfPinnedObject()
Finally
h.Free()
End Try
Return ptr
End Function
#End Region
So seems like it doesn't write ANSI, but in Unicode. How to change that?
Hopefully somebody replies.
The simplest way to get this is to just overload UpdateResource and let Windows make the Unicode to ANSI conversion for you:
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Ansi)> _
Private Shared Function UpdateResource(ByVal hUpdate As IntPtr, _
ByVal lpType As String, ByVal lpName As String, ByVal wLanguage As UShort,
ByVal lpData As String, ByVal cbData As Integer) As Boolean
End Function
Note the changed lpData type and the changed CharSet. The call now simply becomes:
Dim handle As IntPtr = BeginUpdateResource(filename, False)
If handle = IntPtr.Zero Then Throw New Win32Exception
Dim res As Boolean = UpdateResource(handle, "RCData", "CONFIG", 1, _
bytes, bytes.Length)
If Not EndUpdateResource(handle, False) Then Throw New Win32Exception
I'll have to restate the nonsensical nature of the call. RCData is a numbered resource type and not a string. Using a language ID of 1 makes little sense, that's Arabic so you wouldn't expect a Latin string in the resource. Whatever app reads this resource is unlikely to find it back.
Doing this correctly would require an overload that declares lpType as IntPtr so you can pass CType(10, IntPtr) for the RT_RCData resource type. The ToPtr() function is extremely evil, it returns a dangling pointer that will cause random data corruption. Just let the pinvoke marshaller generate the pointer by declaring the lpData argument as Byte(). You'd then use Encoding.GetBytes() to use the proper ANSI conversion. Thus:
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
Private Shared Function UpdateResource(ByVal hUpdate As IntPtr, _
ByVal lpType As IntPtr, ByVal lpName As String, ByVal wLanguage As UShort,
ByVal lpData As Byte(), ByVal cbData As Integer) As Boolean
End Function
With an additional overload required if lpName is a numbered instead of a named resource, use IntPtr.
Related
I am new to VB.Net. I came from vb6 and VBA so I'm still learning. I am trying to clear the memory space for when I retrieve text using my GetWinTxt() function. I am not sure if I am properly releasing the memory space or not. I have researched MSDN and a multitude of other sites including this one trying to learn about this and I find it somewhat confusing. This function will be used a lot and i don't want a memory leak. It seems to be working fine as there isn't any error codes but can someone with more knowledge please tell me if I'm doing this right? Also should I be using Marshal.DestroyStructure() before I use Marshal.FreeHGlobal()? And if so how would I use that in my code below?
Option Explicit On
Imports System.Runtime.InteropServices
Declare Auto Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Shared Function FindWindowEx(ByVal parentHandle As IntPtr, ByVal childAfter As IntPtr, ByVal lclassName As String, ByVal windowTitle As String) As IntPtr
End Function
Friend Const WM_GETTEXT = &HD
Friend Const WM_GETTEXTLENGTH = &HE
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
Dim Hwnd As IntPtr = FindWindow(Nothing, "Untitled - Notepad") 'notepad parent win
Dim Handle As IntPtr = FindWindowEx(Hwnd, IntPtr.Zero, "Edit", Nothing) 'notepad edit area
MsgBox(Lf.GetWinTxt(Handle))'Lf is my class name
End Sub
Friend Function GetWinTxt(hwnd As IntPtr) As String
Dim TextLen As Integer = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0) + 1
Dim WinHandle As IntPtr = Marshal.AllocHGlobal(TextLen)
Call SendMessage(hwnd, WM_GETTEXT, TextLen, WinHandle)
Dim txt As String = Marshal.PtrToStringUni(WinHandle)
GetWinTxt = txt
Dim ByteString(TextLen) As Byte ' the next 3 lines are what i'm not sure if i'm doing it right or not
Marshal.Copy(WinHandle, ByteString, 0, TextLen)
Marshal.FreeHGlobal(txt)
End Function
EDITED FINAL CODE:
Public Function GetWinTxt(hwnd As IntPtr) As String
Dim TextLen As IntPtr = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0) + 1
Dim f As Integer = TextLen
Winhandle = Marshal.AllocHGlobal(f)
Call SendMessage(hwnd, WM_GETTEXT, f, Winhandle)
Dim txt As String = Marshal.PtrToStringUni(Winhandle)
Return txt
Try
Dim ByteString(f) As Byte
Marshal.Copy(Winhandle, ByteString, 0, f)
Marshal.FreeHGlobal(Winhandle)
Catch ex As Exception
Return ""
Debug.Print(ex.Message)
End Try
End Function
The answer is no, unless you call method like Marshal. StructureToPtr().
You should use the counterpart of whatever method you used to allocate it.
Marshal. Destroy Structure will free all substructures that specify unmanaged memory block points to. But you don't have any structure in it.
In addition, you call Dim WinHandle As IntPtr = Marshal.AllocHGlobal(TextLen) Allocates memory from the unmanaged memory of the process to WinHandle, then free anther one, Marshal.FreeHGlobal(txt). This will cause memory leaks.
try to change it to Marshal.FreeHGlobal(WinHandle).
CryptAcquireContext function returns FALSE with The Keyset is not defined error message. Here is my code.
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Public Shared Function CryptAcquireContext(ByRef hProv As IntPtr, ByVal pszContainer As String, ByVal pszProvider As String, ByVal dwProvType As Int32, ByVal dwFlags As UInt32) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Public Shared Function CryptCreateHash(ByVal hProv As IntPtr, ByVal Algid As Int32, ByVal hKey As IntPtr, ByVal dwFlags As Int32, ByRef phHash As IntPtr) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Public Shared Function CryptHashData(ByVal hHash As IntPtr, ByVal pbData() As Byte, ByVal dwDataLen As Int32, ByVal dwFlags As Int32) As Boolean
End Function
Public Const PROV_RSA_FULL As Int32 = 1
Private Const CRYPT_VERIFYCONTEXT As UInt32 = &HF0000000UI
Private Function GetHash(ByVal text As String) As Boolean
Dim bResult As Boolean = False
Dim hProv As IntPtr
Dim hHash As IntPtr
If CryptAcquireContext(hProv, vbNull, vbNull, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) Then
If CryptCreateHash(hProv, CALG_SHA1, 0, 0, hHash) Then
If CryptHashData(hHash, Encoding.ASCII.GetBytes(text), text.Length, 0) Then
Dim bHash(20) As Byte
Dim dwHashLen As Int32 = Marshal.SizeOf(bHash)
bResult = CryptGetHashParam(hHash, HP_HASHVAL, bHash, dwHashLen, 0)
If bResult = True Then
//Rest of string operations
End If
End If
End If
End If
Dim errorMessage As String = New Win32Exception(Marshal.GetLastWin32Error()).Message
MsgBox(errorMessage)
Return bResult
End Function
Do you have any idea about what i'm doing wrong?
Thanks
I'm trying to use some winapi methods. how ever, when I try to use the function I get the following error:
'System.Runtime.InteropServices.DllImportAttribute' cannot be applied to instance method.
code:
Public Class Anti
<DllImport("kernel32.dll", SetLastError:=True)> _
Public Function ReadProcessMemory(ByVal hProcess As IntPtr, ByVal lpBaseAdress As Integer, ByRef lpBuffer As Integer, ByVal nSize As Integer, Optional ByRef lpNumberOfBytesRead As Integer = 0) As Boolean
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Public Sub ZeroMemory(ByVal handle As IntPtr, ByVal length As UInt32)
End Sub
<DllImport("kernel32.dll", SetLastError:=True)> _
Public Function VirtualProtect(ByVal lpAddress As IntPtr, ByVal dwSize As Integer, ByVal flNewProtect As Integer, ByRef lpflOldProtect As UInteger) As Boolean
End Function
Public Sub AntiDump()
Try
Dim x(0) As Process
Well, the message is pretty clear. Methods that you apply the DllImport attribute to must be class methods (shared).
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
I want to use a function from a dll :
<DllImport("netXTransport.dll", CallingConvention:=CallingConvention.StdCall, CharSet:=CharSet.Auto, ExactSpelling:=True)> _
Public Shared Function xSysdeviceUpload(ByVal hSysdevice As IntPtr, ByVal ulChannel As UInt32, ByVal ulMode As UInt32, ByVal pszFileName As IntPtr, ByVal pabFileData As IntPtr, ByVal pulFileSize As IntPtr, ByVal pfnCallback As PFN_NXAPI_PROGRESS_CALLBACK, ByVal pfnRecvPktCallback As PFN_NXAPI_BROWSE_CALLBACK, ByVal pvUser As IntPtr) As Int32
End Function
with
Public Delegate Sub PFN_NXAPI_PROGRESS_CALLBACK(ByVal ulStep As UInt32, ByVal ulMaxStep As UInt32, ByVal pvUser As IntPtr, ByVal bFinished As Char, ByVal lError As Int32)
(for information the C interface is :
int32_t APIENTRY xSysdeviceUpload(CIFXHANDLE hSysdevice, uint32_t ulChannel, uint32_t ulMode, char* pszFileName, uint8_t* pabFileData, uint32_t* pulFileSize, PFN_PROGRESS_CALLBACK pfnCallback, PFN_RECV_PKT_CALLBACK pfnRecvPktCallback, void* pvUser)`;)
My pfnCallback function is done in managed memory (vb.net) :
<AllowReversePInvokeCalls()>
Public Shared Sub TCPRenderProgressBar(ByVal ulStep As UInt32, ByVal ulMaxStep As UInt32, ByVal pvUser As IntPtr, ByVal bFinished As Char, ByVal lError As Int32)
End Sub
therefore I did this in my code to use the function :
Dim pFile As IntPtr = Marshal.AllocHGlobal(CInt(FileLength))
Dim pFileLength As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(FileLength))
Dim pszFileName As IntPtr = Marshal.AllocHGlobal(szFileName.Length)
Dim Temp() As Byte = g_encoding.GetBytes(szFileName & " ")
Temp(szFileName.Length) = 0
Marshal.Copy(Temp, 0, pszFileName, (szFileName.Length + 1))
iResult = xSysdeviceUpload(g_hSysdevice, 0, DOWNLOAD_MODE_FILE, pszFileName, pFile, pFileLength, AddressOf TCPRenderProgressBar, Nothing, Nothing)
All run good if no callback is declared (AddressOf TCPRenderProgressBar replaced by anything), but if I declare (AddressOf) TCPRenderProgressBar, I saw that I pass in function TCPRenderProgressBar but I an error AccessViolationException after...
What is the problem ?
Thank you for your help