i write this code to change default printer in windows and work fine but in reload the INI file have a error
this is a code :
Private Sub SetDefaultPrinter(ByVal PrinterName As String, ByVal DriverName As String, ByVal PrinterPort As String)
Dim DeviceLine As String
'rebuild a valid device line string
DeviceLine = PrinterName & "," & DriverName & "," & PrinterPort
'Store the new printer information in the
'[WINDOWS] section of the WIN.INI file for
'the DEVICE= item
Call WriteProfileString("windows", "Device", DeviceLine)
'Cause all applications to reload the INI file
Call SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, "windows")
End Sub
Private Declare Function WriteProfileString Lib "kernel32" Alias "WriteProfileStringA" (ByVal lpszSection As String, ByVal lpszKeyName As String, ByVal lpszString As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lparam As String) As Long
Private Const HWND_BROADCAST As Long = &HFFFF&
Private Const WM_WININICHANGE As Long = &H1A
and this is a error :
A call to PInvoke function 'Test!Test.Form2::SendMessage' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
Does anyone have an idea to solve this problem?
Thankful
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
ByVal lparam As String) As Long
Your data types are wrong. The hwnd parameter is pointer sized, wMsg is a 32 bit value, and wParam, lParam and the return value are pointer sized. Note that Long is a 64 bit type.
Instead it should be
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, _
ByVal lparam As String) As IntPtr
Note that I recommend that, in the modern day, you use pinvoke declarations rather than Declare. This offer much more flexibility.
Related
Public Class gFunctions
Public Function gSerialPortWrite(ByVal msg As String, comport As Object)
SerialPort1.Write(msg)
End Function
'Pinvoke.Net stackoverflow.com/questions/11238898/reading-from-an-ini-file
Public Declare Auto Function GetPrivateProfileString Lib "kernel32" (ByVal lpAppName As String,
ByVal lpKeyName As String,
ByVal lpDefault As String,
ByVal lpReturnedString As StringBuilder,
ByVal nSize As Integer,
ByVal lpFileName As String) As Integer
Public Declare Auto Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" _
(ByVal lpSectionName As String,
ByVal lpKeyName As String,
ByVal lpValue As String,
ByVal lpFilename As String) As Integer
End Class
How do I call these functions in my form1.vb if I place them in my class1.vb? thanks for any help or added information. New to Visual Studio, although I have experience with VB in Excel. In Excel I just added another module.bas.
I'm trying to pass text to a 3rd party program but running into a snag.
I have isolated the Class Handler ID inside my program,validated with the messagebox. However, when I try sending it text, I get a run time error.
Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Int32
Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByVal lParam As Int32) As Int32
Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Int32, ByVal hWnd2 As Int32, ByVal lpsz1 As String, ByVal lpsz2 As String) As Int32
Dim hwnd As Integer
Dim hwindow2 As Integer
Dim main_view As Integer
Dim sub_window As Integer
Public Const WM_SETTEXT = &H0
And
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
hwindow2 = FindWindow(vbNullString, "Trace")
main_view = FindWindowEx(hwindow2, 0&, "#32770", vbNullString)
System.Threading.Thread.Sleep(10)
sub_window = FindWindowEx(main_view, 0&, "Edit", vbNullString)
MessageBox.Show(main_view)
MessageBox.Show(sub_window)
Call SendMessage(sub_window, WM_SETTEXT, 0, "test")
End Sub
Any help would be appreciated.
Thanks
you might consider using PostMessage(), it is an asynchronous method and it won't wait for the response from the receiving end. while SendMessage method is synchronous, it 'does not return until the window procedure has processed the message'.
see suggestions from post here
it is also good to indicate the error message to better understand the problem.
I found a piece of code that enables my User form list boxes to resize in height based on the number of inputs, but the declaration is for win32 and i do not know how to change it to win 64 correctly, please help. Here it is:
Option Explicit
Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, ByVal lParam As Any) As Long
Private Const LB_GETITEMHEIGHT = &H1A1
Public Function AutoSizeLBHeight(LB As Object) As Boolean
If Not TypeOf LB Is ListBox Then Exit Function
On Error GoTo ErrHandler
Dim lItemHeight As Long
Dim lRet As Long
Dim lItems As Long
Dim sngTwips As Single
Dim sngLBHeight As Single
If LB.ListCount = 0 Then
LB.Height = 125
AutoSizeLBHeight = True
Else
lItems = LB.ListCount
lItemHeight = SendMessage(LB.hwnd, LB_GETITEMHEIGHT, 0&, 0&)
If lItemHeight > 0 Then
sngTwips = lItemHeight * Screen.TwipsPerPixelY
sngLBHeight = (sngTwips * lItems) + 125
LB.Height = sngLBHeight
AutoSizeLBHeight = True
End If
End If
ErrHandler:
End Function
http://www.jkp-ads.com/articles/apideclarations.asp has everything you need.
The SendMessage API is a good example because it uses both types:
32-bit:
Public Declare Function SendMessageA Lib "user32" ( _
ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long
64 bit:
Public Declare PtrSafe Function SendMessageA Lib "user32" ( _
ByVal hWnd As LongPtr, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As LongPtr
The first argument -hWnd- is a window handle, which is an address in memory. The return value is a pointer to a function, which is also an address in memory. Both of these must be declared LongPtr in 64-bit VBA. The arguments wMsg and wParam are used to pass data, so they can be Long in both 32-bit and 64-bit.
But you are aware that you only need this for 64bit-Excel, not for 64bit-Windows?
Using Compiler Directives will allow the code to run properly on either platform.
#If Win64 Then
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As LongPtr, ByVal wMsg As Long, _
ByVal wParam As LongPtr, lParam As Any) As LongPtr
#ElseIf Win32 Then
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long
#End If
I am writing a vba application using macros. I am trying to read a dword value for IMAP Port using RegQueryValueEx. The call succeeds but I lpcbData points to 0. Here is my declaration
Private Declare PtrSafe Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExW" (ByVal hKey As LongPtr, ByVal lpValueName As LongPtr, ByVal lpReserved As LongPtr, lpType As LongPtr, ByVal lpData As LongPtr, lpcbData As LongPtr) As LongPtr
If RegQueryValueExStr(hKey, StrPtr(queryFieldName), 0, dwType, port, dwBufSize) = ERROR_SUCCESS Then
Dim wport As String
'wport = StrConv(port, vbUnicode)
EnumerateAccounts = EnumerateAccounts & fieldvalue & ": " & wport & "\n\r"
End If
The code above is not very well written, im just trying to hack some code together to read the port value.
I have the same code working in a C++ application so it is not the issue of 32/64bit windows.
Ok so i found out why it was returning a zero. First of all the dword values are/were stored using ASCII not unicode. In case someone else runs into the same problem, the correct declaration is as follows:
Private Declare PtrSafe Function RegQueryValueExDword Lib "advapi32.dll" Alias "RegQueryValueExA" (ByVal hKey As LongPtr, ByVal lpValueName As String, ByVal lpReserved As LongPtr, lpType As LongPtr, lpData As Any, lpcbData As LongPtr) As LongPtr
I have
Private Declare Function ReadProcessMemory Lib "kernel32" Alias "ReadProcessMemory" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByRef lpBuffer As Integer, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
But I also need
Private Declare Function ReadProcessMemory Lib "kernel32" Alias "ReadProcessMemory" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByRef lpBuffer As Single, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
And some other variations. So, as in the example above, lpBuffer as Single instead of Integer. How can I achieve this?
UPDATE: Alrighty, now I'm doing this:
Imports System.Math
Imports System.Threading
Imports System.Runtime.InteropServices
Public Class Form1
'Declare ReadProcessMemory with lpBuffer As IntPtr
Private Declare Function ReadProcessMemory Lib "kernel32" Alias "ReadProcessMemory" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByRef lpBuffer As IntPtr, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
'This is the function I am now having trouble with
Public Function memfloat(ByVal address As Long, ByVal processHandle As IntPtr)
Dim floatvalueinmemory As Single
ReadProcessMemory(processHandle, address, floatvalueinmemory, 4, 0)
Dim letstryagain As Single 'floatvalueinmemory didn't give the desired result, so going to try to TryParse
Single.TryParse(floatvalueinmemory, letstryagain)
Return CStr(letstryagain) 'returns the same result as floatvalueinmemory did
End Function
End Class
Partial Public Class NativeMethods
<DllImport("user32.dll")> _
Public Shared Function ReadProcessMemory(ByVal hProcess As System.IntPtr, ByVal lpBaseAddress As IntPtr, ByVal lpBuffer As System.IntPtr, ByVal nSize As UInteger, ByVal lpNumberOfBytesRead As IntPtr) As Boolean
End Function
End Class
The memfloat function used to return something like "-75,48196", now it returns something like "-1,012555E+09" (the actual values don't match, just using these as an example), this is why I wanted to declare multiple times in the first place.. how do I convert from the IntPtr to a Single ?
What does work is:
Public Function memstring(ByVal address As Long, ByVal length As Int32, ByVal processHandle As IntPtr)
Dim stringinmemory As Long
Dim ret1 As Byte() = Nothing
Dim tStr(length) As Char
Dim retStr As String = ""
For i As Int32 = 0 To length - 1
ReadProcessMemory(processHandle, address + i, stringinmemory, 1, 0)
ret1 = BitConverter.GetBytes(stringinmemory)
tStr(i) = System.Text.Encoding.ASCII.GetString(ret1) : retStr += tStr(i)
Next
Return retStr
End Function
This correctly returns the memory value as string. So yeah, now it's just the Single that's causing issues.
You are using the Alias keyword anyway, so take advantage of it:
Private Declare Function ReadProcessMemoryInt Lib "kernel32" _
Alias "ReadProcessMemory" (ByVal hProcess As Integer, _
ByVal lpBaseAddress As Integer, _
ByRef lpBuffer As Integer, _
ByVal nSize As Integer, _
ByRef lpNumberOfBytesWritten As Integer) As Integer
Private Declare Function ReadProcessMemorySingle Lib "kernel32" _
Alias "ReadProcessMemory" (ByVal hProcess As Integer, _
ByVal lpBaseAddress As Integer, _
ByRef lpBuffer As Single, _
ByVal nSize As Integer, _
ByRef lpNumberOfBytesWritten As Integer) As Integer
The name you give to the function can be arbitrary. Only the Alias name must match the name in the library. In your code, you can refer to ReadProcessMemoryInt and ReadProcessMemorySingle (or whatever name you chose).
(Note: I didn't check whether you are actually using the API correctly, I've just answered your question about how to define the same API function twice with different signatures.)
I fired up the P/Invoke Interop Assistant tool (link), found ReadProcessMemory and generated the signature in vb.net as:
Partial Public Class NativeMethods
'''Return Type: BOOL->int
'''hProcess: HANDLE->void*
'''lpBaseAddress: LPCVOID->void*
'''lpBuffer: LPVOID->void*
'''nSize: SIZE_T->ULONG_PTR->unsigned int
'''lpNumberOfBytesRead: SIZE_T*
<System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint:="ReadProcessMemory")> _
Public Shared Function ReadProcessMemory(<System.Runtime.InteropServices.InAttribute()> ByVal hProcess As System.IntPtr, <System.Runtime.InteropServices.InAttribute()> ByVal lpBaseAddress As System.IntPtr, ByVal lpBuffer As System.IntPtr, ByVal nSize As UInteger, ByVal lpNumberOfBytesRead As System.IntPtr) As <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)> Boolean
End Function
End Class
So the bufffer is IntPtr that you need to convert into an array of various types. I suggest you look into the Marshal class and its static methods. Also here are links to possible relevant articles SO link,url 1,url 2. Translation from c# to vb.net may be needed. I also noticed on these online examples that the function definition can be overloaded (which surprised me).