I got a PL/I Dll and I'm trying to import the DLL into my VB.Net Application.
The first try worked but the program did quit without comment after a few calls.
And it is not possible to call these function twice from two different threads.
I get the result from the DLL in paramone. Any Ideas why this doesn't work right and how to get it to work?
<DllImport(("PLIDLL.dll"), CallingConvention:=CallingConvention.StdCall)> _
Public Shared Sub MYFUNC(ByVal LogonString As String, _
<MarshalAs(UnmanagedType.VBByRefStr)> ByRef paramone As String, _
ByVal paramtwo As String)
End Sub
If anything is unclear please ask.
Greetings Lim
PS: I already tried to rerewrite the PL/I Code so that it returns a String instead of the ByRef value. Same issue.
The Sub in PLI:
MYFUNC: PROC(LOGONSTRING,PARAMONE,PARAMTWO) REORDER
OPTIONS(FROMALIEN NODESCRIPTOR
BYADDR LINKAGE(STDCALL));
DEFAULT RANGE(*) STATIC;
DCL LOGONSTRING CHAR(30);
DCL PARAMONE CHAR(2033);
DCL PARAMTWO CHAR (5500);
Found at least a working solution.
Module NativeMethods
<DllImport("kernel32.dll", SetLastError:=True)> _
Public Function LoadLibrary(ByVal lpFileName As String) As IntPtr
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Public Function GetProcAddress(ByVal hModule As IntPtr, ByVal procedureName As String) As IntPtr
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Public Function FreeLibrary(ByVal hModule As IntPtr) As IntPtr
End Function
End Module
<UnmanagedFunctionPointer(CallingConvention.StdCall)>
Private Delegate Sub MYFUNC(ByVal LogonString As String, <MarshalAs(UnmanagedType.VBByRefStr)> ByRef PARAMONE As String, ByVal PARAMTWO As String)
Public Shared Sub CallFunction(ByRef workingObject As PLIOBJECT)
Dim EntryPointer As IntPtr = NativeMethods.LoadLibrary("PLIDLL.dll")
Dim FunctionPointer As IntPtr = NativeMethods.GetProcAddress(EntryPointer, "MYFUNC")
Dim MyFUNC As MYFUNC= CType(Marshal.GetDelegateForFunctionPointer(FunctionPointer, GetType(MYFUNC)), MYFUNC)
MyFUNC(workingObject.Logonstring, workingObject.PARAMONE, workingObject.PARAMTWO)
Dim result As Boolean = NativeMethods.FreeLibrary(EntryPointer)
End Sub
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).
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).
im trying to hide/unhide window process by name or PID i have tried
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As ShowWindowCommands) As Boolean
End Function
but ShowWindowCommands what is and how to find it ?
thanks !
there is many ways to do this the easiest one should be this :
'GENERAL IMPORT
Imports System.Runtime.InteropServices
'FORM CLASS DECLARATION
<DllImport("user32.dll")> _
Private Shared Function ShowWindow(ByVal hWnd As IntPtr, ByVal nCmdShow As Integer) As Boolean
End Function
'then if you want to hide firefox's window :
Dim mywindow As Integer
Dim processRunning As Process() = Process.GetProcesses()
For Each pr As Process In processRunning
If pr.ProcessName = "Firefox" Then
mywindow = pr.MainWindowHandle.ToInt32()
ShowWindow(mywindow , 0)
End If
Next
You can do it like this:
Form.FromHandle(Process.GetProcessById(PID).MainWindowHandle).Show()
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.
How should I DLLImport things in VB.NET? An example would be:
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function GetWindowText(ByVal hwnd As IntPtr, ByVal lpString As StringBuilder, ByVal cch As Integer) As Integer
End Function
If I put it inside a Class or somewhere else, I get "DLLimport is not defined" I am using Visual Studio 2008 Professional
You have to add Imports System.Runtime.InteropServices to the top of your source file.
Alternatively, you can fully qualify attribute name:
<System.Runtime.InteropService.DllImport("user32.dll", _
SetLastError:=True, CharSet:=CharSet.Auto)> _
Imports System.Runtime.InteropServices
I know this has already been answered, but here is an example for the people who are trying to use SQL Server Types in a vb project:
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Namespace SqlServerTypes
Public Class Utilities
<DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Public Shared Function LoadLibrary(ByVal libname As String) As IntPtr
End Function
Public Shared Sub LoadNativeAssemblies(ByVal rootApplicationPath As String)
Dim nativeBinaryPath = If(IntPtr.Size > 4, Path.Combine(rootApplicationPath, "SqlServerTypes\x64\"), Path.Combine(rootApplicationPath, "SqlServerTypes\x86\"))
LoadNativeAssembly(nativeBinaryPath, "msvcr120.dll")
LoadNativeAssembly(nativeBinaryPath, "SqlServerSpatial140.dll")
End Sub
Private Shared Sub LoadNativeAssembly(ByVal nativeBinaryPath As String, ByVal assemblyName As String)
Dim path = System.IO.Path.Combine(nativeBinaryPath, assemblyName)
Dim ptr = LoadLibrary(path)
If ptr = IntPtr.Zero Then
Throw New Exception(String.Format("Error loading {0} (ErrorCode: {1})", assemblyName, Marshal.GetLastWin32Error()))
End If
End Sub
End Class
End Namespace
I saw in getwindowtext (user32) on pinvoke.net that you can place a MarshalAs statement to state that the StringBuffer is equivalent to LPSTR.
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Ansi)> _
Public Function GetWindowText(hwnd As IntPtr, <MarshalAs(UnManagedType.LPStr)>lpString As System.Text.StringBuilder, cch As Integer) As Integer
End Function
You can also try this
Private Declare Function GetWindowText Lib "user32.dll" (ByVal hwnd As IntPtr, ByVal lpString As StringBuilder, ByVal cch As Integer) As Integer
I always use Declare Function instead of DllImport...
Its more simply, its shorter and does the same