I want to call function MoveFile from "Kernel32.dll".
1)First approach:
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("KERNEL32.DLL", EntryPoint:="MoveFileW", SetLastError:=True, CharSet:=CharSet.Unicode, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)>
Public Shared Function MoveFile(ByVal src As String, ByVal dst As String) As Boolean
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim src As String = "C:\Users\Baha1990\Documents\Visual Studio 2017\Projects\WindowsApp1\TEST FILE\1\MSACCESS.accdb"
Dim dst As String = "C:\Users\Baha1990\Documents\Visual Studio 2017\Projects\WindowsApp1\TEST FILE\2\MSACCESS.accdb"
Dim RetVal As Boolean = MoveFile(src, dst)
End Sub
End Class
It works pretty well
Second approach:
Imports System.Runtime.InteropServices
Public Class Form1
<Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True)> Private Shared Function LoadLibrary(ByVal lpFileName As String) As IntPtr
End Function
<Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True, CharSet:=Runtime.InteropServices.CharSet.Ansi, ExactSpelling:=True)> Private Shared Function GetProcAddress(ByVal hModule As IntPtr, ByVal procName As String) As IntPtr
End Function
<UnmanagedFunctionPointer(CallingConvention.StdCall)>
Public Delegate Function _MoveFile(ByVal src As String, ByVal dst As String) As Boolean
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim src As String = "C:\Users\Baha1990\Documents\Visual Studio 2017\Projects\WindowsApp1\TEST FILE\1\MSACCESS.accdb"
Dim dst As String = "C:\Users\Baha1990\Documents\Visual Studio 2017\Projects\WindowsApp1\TEST FILE\2\MSACCESS.accdb"
Dim pDll As IntPtr = IntPtr.Zero
pDll = LoadLibrary("kernel32.dll")
Dim pProc2D = GetProcAddress(pDll, "MoveFileW")
Dim MoveFile = Marshal.GetDelegateForFunctionPointer(pProc2D, GetType(_MoveFile))
Dim RetVal = MoveFile.DynamicInvoke(src, dst) 'Here I get boolean as false it should be true
or
Dim RetVal = MoveFile.Method.Invoke(What to pass here in my case?)
End Sub
End Class
So Question: What is difference between DLLImport and DynamicInvoke or Method.Invoke, and why I have fail with DynamicInvoke and what params to pass to Method.Invoke?
Ok, in second approach I figure out that in this line:
<UnmanagedFunctionPointer(CallingConvention.StdCall)>
Needs additional params, after I edited as:
<UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError:=True, CharSet:=CharSet.Unicode)>
Dim RetVal = MoveFile.DynamicInvoke(src, dst) - DynamicInvoke works perfect.
So question what to pass as params to Method.Invoke still open.
Ok, I also figured out about Method.Invoke:
Dim param = {src, dst}
Dim RetVal = MoveFile.Method.Invoke(MoveFile, param) - works perfect.
So seems all three aproach works and gives same result, but what advantage gives these methods between each other. Who can explain?
Related
I'm working on programm on VB.net to retrieve data from Firefox browser. I have an error while trying to use "PK11SDR_Decrypt" method from nss3.lib. "PK11SDR_Decrypt" returns -1. I don't have master password. I think that the problem in Ctypes/marshalling/base64 decoding. This is the code of function.
Public Function DecryptFF(ByVal str As String)
On Error Resume Next
Dim tSecDec As New TSECItem
Dim e As Integer
Dim sb As New System.Text.StringBuilder(str)
Dim hi2 As Integer = NSSBase64_DecodeBuffer(IntPtr.Zero, IntPtr.Zero, sb, sb.Length)
Dim item As TSECItem = DirectCast(Marshal.PtrToStructure(New IntPtr(hi2), GetType(TSECItem)), TSECItem)
e = PK11SDR_Decrypt(item, tSecDec, 0)
If e = 0 Then
If tSecDec.SECItemLen <> 0 Then
Dim mozDecryptedData = New Byte(tSecDec.SECItemLen - 1) {}
Marshal.Copy(New IntPtr(tSecDec.SECItemData), mozDecryptedData, 0, tSecDec.SECItemLen)
Return Encoding.UTF8.GetString(mozDecryptedData)
End If
End If
Return String.Empty
End Function
And other code part.
Public NSS3 As IntPtr
Public hModuleList As New List(Of IntPtr)
<StructLayout(LayoutKind.Sequential)>
Public Structure TSECItem
Public SECItemType As Integer
Public SECItemData As Integer
Public SECItemLen As Integer
End Structure
Public Function NSS_Init(ByVal configdir As String) As Long
Dim PathM = FindFirefoxInstallationPath()
hModuleList.Add(LoadLibrary(PathM & "\msvcp140.dll"))
hModuleList.Add(LoadLibrary(PathM & "\mozglue.dll"))
hModuleList.Add(LoadLibrary(PathM & "\mozavutils.dll"))
NSS3 = LoadLibrary(PathM & "\nss3.dll")
hModuleList.Add(NSS3)
Return CreateAPI(Of DLLFunctionDelegate)(NSS3, "NSS_Init")(configdir)
End Function
Public Function CreateAPI(Of T)(ByVal hModule As IntPtr, ByVal method As String) As T 'Simple overload to avoid loading the same library every time
Return DirectCast(DirectCast(Marshal.GetDelegateForFunctionPointer(GetProcAddress(hModule, method), GetType(T)), Object), T)
End Function
Public Function NSSBase64_DecodeBuffer(ByVal arenaOpt As IntPtr, ByVal outItemOpt As IntPtr, ByVal inStr As System.Text.StringBuilder, ByVal inLen As Integer) As Integer
Dim pProc As IntPtr = GetProcAddress(NSS3, "NSSBase64_DecodeBuffer")
Dim dll As DLLFunctionDelegate4 = DirectCast(Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer(pProc, GetType(DLLFunctionDelegate4)), DLLFunctionDelegate4)
Return dll(arenaOpt, outItemOpt, inStr, inLen)
End Function
Public Function PK11SDR_Decrypt(ByRef data As TSECItem, ByRef result As TSECItem, ByVal cx As Integer) As Integer
Dim pProc As IntPtr = GetProcAddress(NSS3, "PK11SDR_Decrypt")
Dim dll As DLLFunctionDelegate5 = DirectCast(Marshal.GetDelegateForFunctionPointer(pProc, GetType(DLLFunctionDelegate5)), DLLFunctionDelegate5)
Return dll(data, result, cx)
End Function
<UnmanagedFunctionPointer(CallingConvention.Cdecl)>
Public Delegate Function DLLFunctionDelegate5(ByRef data As TSECItem, ByRef result As TSECItem, ByVal cx As Integer) As Integer
<UnmanagedFunctionPointer(CallingConvention.Cdecl)>
Public Delegate Function DLLFunctionDelegate6() As Long
Public Function NSS_Shutdown() As Long
Return CreateAPI(Of DLLFunctionDelegate6)(NSS3, "NSS_Shutdown")()
End Function
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Public Shared Function LoadLibrary(ByVal dllFilePath As String) As IntPtr
End Function
<DllImport("kernel32.dll", SetLastError:=True, EntryPoint:="FreeLibrary")>
Public Shared Function FreeLibrary(ByVal hModule As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Ansi, ExactSpelling:=True)>
Public Shared Function GetProcAddress(ByVal hModule As IntPtr, ByVal procName As String) As IntPtr
End Function
DecryptFF get as argument the encrypted login fron logins.json file. Here is the part of code
Dim JSONRegex As New Regex("\""(hostname|encryptedPassword|encryptedUsername)"":""(.*?)""")
Dim mozMC = JSONRegex.Matches(Logins)
For I = 0 To mozMC.Count - 1 Step 3
Dim host = mozMC(I).Groups(2).Value
Dim usr = mozMC(I + 1).Groups(2).Value
Dim pas = mozMC(I + 2).Groups(2).Value
Account = (DecryptFF(usr))
Thank you for your help!
So I have this code
Imports System.Runtime.InteropServices
Imports System.Text
Public Class Form1
Const PROCESS_WM_READ As Integer = &H10
<DllImport("kernel32.dll")>
Public Shared Function OpenProcess(dwDesiredAccess As Integer, bInheritHandle As Boolean, dwProcessId As Integer) As IntPtr
End Function
<DllImport("kernel32.dll")>
Public Shared Function ReadProcessMemory(hProcess As Integer, lpBaseAddress As Integer, lpBuffer As Byte(), dwSize As Integer, ByRef lpNumberOfBytesRead As Integer) As Boolean
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim notepadProcess As Process = Process.GetProcessesByName("GeometryDash")(0)
Dim processHandle As IntPtr = OpenProcess(PROCESS_WM_READ, False, notepadProcess.Id)
Dim bytesRead As Integer = 0
Dim buffer As Byte() = New Byte(23) {}
'The address in this line is hard-coded. Use whatever is appropriate for your situation.
ReadProcessMemory(CInt(processHandle), 117317672, buffer, buffer.Length, bytesRead)
MsgBox(Encoding.Unicode.GetString(buffer))
End Sub
End Class
It outputs 2 or 3 weird Japanese characters, the address "117317672" is "06FE2028" in decimal. I think it's not liking how I'm giving it the address, how should I put in the address?
I've recreated some of the OpenNetCF components like PowerManagement and DeviceStatusMonitor. But since they never raised any events I suspected that something was wrong. My first thought was to check the P2PMessageQueue which they both depends on. And then BAM, the CreateMsgQueue returns IntPtr.Zero. Checking for the last Win32Error gives me an error code of value -2147467259 (minus).
Is this just another generic error code that doesn't provide any hints?
Any help would be appreciated.
(FYI: WinCE 5.0, CF 2.0)
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
Dim lpName As String = "MyQueue"
Dim lpOptions As MSGQUEUEOPTIONS = New MSGQUEUEOPTIONS()
Dim hMsgQ As IntPtr = IntPtr.Zero
lpOptions.bReadAccess = True
lpOptions.dwMaxMessages = 0
lpOptions.cbMaxMessage = &H1000
lpOptions.dwFlags = MSGQUEUE_ALLOW_BROKEN
lpOptions.dwSize = Marshal.SizeOf(lpOptions)
hMsgQ = CreateMsgQueue(lpName, lpOptions)
If (hMsgQ = IntPtr.Zero) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
Else
CloseMsgQueue(hMsgQ)
End If
Catch ex As Win32Exception
MessageBox.Show(String.Format(String.Format("Win32Exception: {0}", ex.ErrorCode)))
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
<DllImport("coredll.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Private Shared Function CloseMsgQueue(ByVal hMsgQ As IntPtr) As Boolean
End Function
<DllImport("coredll.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Private Shared Function CreateMsgQueue(<MarshalAs(UnmanagedType.LPWStr)> ByVal lpName As String, ByVal lpOptions As MSGQUEUEOPTIONS) As IntPtr
End Function
<StructLayout(LayoutKind.Sequential)> _
Private Structure MSGQUEUEOPTIONS
Public dwSize As Integer
Public dwFlags As Integer
Public dwMaxMessages As Integer
Public cbMaxMessage As Integer
Public bReadAccess As Boolean
End Structure
Private Const MSGQUEUE_ALLOW_BROKEN As Integer = 2
Private Const MSGQUEUE_NOPRECOMMIT As Integer = 1
Private Const MSGQUEUE_MSGALERT As Integer = 1
End Class
The lpOptions parameter is declared incorrectly. You declare it as ByVal but it should be ByRef.
That said, -2147467259 is a bit of an oddity. That's not a Win32 error code. That's a COM HRESULT. Specifically it's 0x80004005. Which is the COM wrapper around the Win32 ERROR_ACCESS_DENIED. Not sure where you get a COM HRESULT from in this code mind you, but it would appear that you don't have sufficient rights for what you are attempting.
My code using proxy works but when the proxy is invalid or restricted my program directly uses my IP address, i used a web browser that directly checks my ip, is there any way that i could set an exception whenever the proxy i used is invalid or restricted?
here is my working code:
Imports System.Runtime.InteropServices
#Region "Using Proxy"
<Runtime.InteropServices.DllImport("wininet.dll", SetLastError:=True)> _
Private Shared Function InternetSetOption(ByVal hInternet As IntPtr, ByVal dwOption As Integer, ByVal lpBuffer As IntPtr, ByVal lpdwBufferLength As Integer) As Boolean
End Function
Public Structure Struct_INTERNET_PROXY_INFO
Public dwAccessType As Integer
Public proxy As IntPtr
Public proxyBypass As IntPtr
End Structure
Private Sub UseProxy(ByVal strProxy As String)
Const INTERNET_OPTION_PROXY As Integer = 38
Const INTERNET_OPEN_TYPE_PROXY As Integer = 3
Dim struct_IPI As Struct_INTERNET_PROXY_INFO
struct_IPI.dwAccessType = INTERNET_OPEN_TYPE_PROXY
struct_IPI.proxy = Marshal.StringToHGlobalAnsi(strProxy)
struct_IPI.proxyBypass = Marshal.StringToHGlobalAnsi("local")
Dim intptrStruct As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(struct_IPI))
Marshal.StructureToPtr(struct_IPI, intptrStruct, True)
Dim iReturn As Boolean = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY, intptrStruct, System.Runtime.InteropServices.Marshal.SizeOf(struct_IPI))
End Sub
#End Region
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
UseProxy(ProxyText.Text)
WebBrowser1.Navigate("ipchicken.com")
End Sub
Try the solution below:
Another Stackoverflow Answer
I believe if you bind the address to that specific ip it wont work , if the ip is invalid or not working, and wont use your systems default.
I'm trying to send structured data from a VB 2010 app that I'm developing to an existing library which expects strings to be converted into byte arrays. I'm having trouble with the sending the data as byte arrays - I can send the plain string that should be converted to bytes to a test program that I've written.
Here are the two apps. Firstly the listener process:
Imports System.Runtime.InteropServices
Public Class frmTest
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = frmTest.WM_COPYDATA Then
Dim data As CopyData
Dim message As String
' get the data...
data = CType(m.GetLParam(GetType(CopyData)), CopyData)
message = data.lpData
' add the message
txtTest.Text = message
' let them know we processed the message...
m.Result = New IntPtr(1)
Else
MyBase.WndProc(m)
End If
End Sub
Private Function UnicodeBytesToString(ByVal bytes() As Byte) As String
Return System.Text.Encoding.Unicode.GetString(bytes)
End Function
Private Const WM_COPYDATA As Integer = &H4A
<StructLayout(LayoutKind.Sequential)> _
Private Structure CopyData
Public dwData As IntPtr
Public cbData As Integer
Public lpData As String
End Structure
End Class
Secondly the process that sends the data:
Imports System.Runtime.InteropServices
Imports System.Collections.Generic
Public Class frmMain
<StructLayout(LayoutKind.Sequential)> _
Private Structure CopyData
Public dwData As IntPtr
Public cbData As Integer
Public lpData As String
End Structure
Private Declare Auto Function SendMessage Lib "user32" _
(ByVal hWnd As IntPtr, _
ByVal Msg As Integer, _
ByVal wParam As IntPtr, _
ByRef lParam As CopyData) As Boolean
Private Declare Auto Function FindWindow Lib "user32" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As IntPtr
Private Const WM_COPYDATA As Integer = &H4A
Private Sub cmdSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSend.Click
Dim ClientWindow As IntPtr
Dim a() As System.Diagnostics.Process = System.Diagnostics.Process.GetProcesses
For Each p In a
Console.WriteLine(p.ProcessName)
If p.ProcessName = "Listener" Then
ClientWindow = p.MainWindowHandle
Exit For
End If
Next
' make sure we found an active client window
If Not ClientWindow.Equals(IntPtr.Zero) Then
' if there is text to send
If txtText.Text.Length > 0 Then
Dim message As String = txtText.Text
Dim data As CopyData
' set up the data...
data.lpData = message
data.cbData = message.Length * Marshal.SystemDefaultCharSize
' send the data
frmMain.SendMessage(ClientWindow, frmMain.WM_COPYDATA, Me.Handle, data)
End If
Else
MsgBox("Could Not Find Active Client Window.")
End If
End Sub
Private Function UnicodeStringToBytes(
ByVal str As String) As Byte()
Return System.Text.Encoding.Unicode.GetBytes(str)
End Function
End Class
This all works but if I change 'Public lpData As String' to 'Public lpData As Byte()' in both and then amend 'data.lpData = message' to 'data.lpData = UnicodeStringToBytes(message)' in the sender process and 'message = data.lpData' to 'message = UnicodeBytesToString(data.lpData)' in the listener process it crashes.
How can I send a string encoded as a byte array from the sender to the listener so that the listener can decode it back to a string ?
I realise it would be easier to send the string as a string but the existing library needs it as a byte array so I'm trying to get my sender working against this test listener where I can see what's happening.
Thanks in advance !
Variable-length arrays in structures are always a pain.
Declare lpData as IntPtr in both applications.
Then in the sending app:
' set up the data...
Dim string_bytes = UnicodeStringToBytes(message)
Dim pinned = GCHandle.Alloc(string_bytes, GCHandleType.Pinned)
Try
data.dwData = New IntPtr(message.Length)
data.cbData = string_bytes.Length
data.lpData = pinned.AddrOfPinnedObject()
' send the data
frmMain.SendMessage(ClientWindow, frmMain.WM_COPYDATA, Me.Handle, data)
Finally
If pinned.IsAllocated Then pinned.Free()
End Try
In the receiving app:
' get the data...
data = CType(m.GetLParam(GetType(CopyData)), CopyData)
Dim message(0 To data.cbData - 1) As Byte
Marshal.Copy(data.lpData, message, 0, data.cbData)
' add the message
txtTest.Text = UnicodeBytesToString(message)