I'm trying to integrate a scanner to my code, in the sample solution they provided, they use DllImport, Delegate functions, callback procedures, etc...
This is just my first encounter with dllImport, delegates, callback procedures, everytime I debug the solution they gave me, starting from initializing, then button click and then suddenly I always get an error "vshost32.exe has stopped working".
Here's my the code:
Imported Functions from DLL:
Private Declare Function rdInit Lib "sb6lib" (ByVal tmo As Integer) As Integer
Private Declare Function rdStart Lib "sb6lib" () As Integer
Private Declare Function rdsConfig Lib "sb6lib" (ByVal Wnd As Integer, ByVal confile As String) As Integer
Private Declare Function rdConfigAPI Lib "sb6lib" (ByVal tmo As Integer, ByVal tmo As Integer) As Integer
Use of delegates to implement callback procedures.
Public Delegate Sub FeederEmptyDelegate(ByVal x As Integer)
Private Declare Function rdOnFeederEmpty Lib "sb6lib" (ByVal lpfeederempty As FeederEmptyDelegate) As Integer
Public Delegate Sub AllDoneDelegate(ByVal x As Integer)
Private Declare Function rdOnAllDone Lib "sb6lib" (ByVal lpx As AllDoneDelegate) As Integer
Delegate Function CodeLineVBDelegate(ByVal lpx As IntPtr) As Integer
Private Declare Function rdOnCodeLineVB Lib "sb6lib" (ByVal lpx As CodeLineVBDelegate) As Integer
Public Delegate Sub ErrorDelegate(ByVal x As Integer)
Private Declare Function rdOnError Lib "sb6lib" (ByVal lpx As ErrorDelegate) As Integer
Public Delegate Function DocumentDoneDelegate(ByVal lpx As Integer) As Integer
Private Declare Function rdOnDocumentDone Lib "sb6lib" (ByVal lpx As DocumentDoneDelegate) As Integer
On Command1_Click Event -Stands for Initialize Button
Public Sub Command1_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command1.Click
Dim rtnval As Object
' find the RDS and initialize the API
rtnval = rdInit(-1)
List1.Items.Add(("rdInit returns " & rtnval))
If rtnval > -1 Then
rtnval = rdConfigAPI(4101, 0)
rtnval = rdsConfig(Frame1.Handle.ToInt32, ".\\DOCDES0.DES")
List1.Items.Add(("rdsConfig returns " & rtnval))
'Callbacks
rtnval = rdOnFeederEmpty(AddressOf feederempty)
rtnval = rdOnAllDone(AddressOf alldone)
rtnval = rdOnCodeLineVB(AddressOf codeline)
rtnval = rdOnError(AddressOf onerror)
rtnval = rdOnDocumentDone(AddressOf docdone)
Command2.Enabled = True
Command1.Enabled = False
Command3.Enabled = True
ViewButton.Enabled = True
End If
End Sub
On Command2_Click Event -Stands for Start Scanning Button
Private Sub Command2_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command2.Click
Dim rtnval As Object
rtnval = rdStart()
List1.Items.Add(("rdStart returns " & rtnval))
End Sub
After the scanning (End Sub) it goes to the Callback function "codeline": (Debug Mode)
Private Function codeline(ByVal x As IntPtr) As Integer
' called when a codeline is available
Dim cl As String
cl = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(x) 'conversion necessary as passed argument is a BSTR type string in sb6lib
If Me.InvokeRequired Then
Me.Invoke(New WriteTextBoxDelegate(AddressOf codeline), New Object() {x})
Else
yval.Text = "CL: " & cl
End If
codeline = 1
End Function
and then the application stopped working ("vshost32.exe has stopped working").
Can sombebody tell me what causes the crashing of the application? Thanks!
Related
I am just learning programming, so please be understanding :)
I am writing an application that needs to send text data to another console program. I was successful with SendMessage(), but unfortunately with Wine (on linux) it is not supported for console applications.
So I found a function that is supported. This is WriteConsoleInput().
Here is my code, could someone indicate why it doesn't work?
Public Declare Function AttachConsole Lib "kernel32" (ByVal ProcessID As Long) As Boolean
Private Declare Function GetStdHandle Lib "kernel32.dll" (ByVal nStdHandle As Int32) As IntPtr
Declare Function WriteConsoleInputW Lib "kernel32" Alias "WriteConsoleInputW" (ByVal hConsoleInput As Integer, ByVal lpBuffer As String, ByVal nNumberOfCharsToWrite As Integer, ByRef lpNumberOfCharsWritten As Integer) As Integer
Declare Function WriteConsoleInputA Lib "kernel32" Alias "WriteConsoleInputA" (ByVal hConsoleInput As Integer, ByVal lpBuffer As String, ByVal nNumberOfCharsToWrite As Integer, ByRef lpNumberOfCharsWritten As Integer) As Integer
Declare Function SetConsoleTitle Lib "kernel32.dll" Alias "SetConsoleTitleA" (lpConsoleTitle As String) As Boolean
Private Const STD_OUTPUT_HANDLE As Long = -11&
Private Const STD_INPUT_HANDLE As Long = -10&
Private Const STD_ERROR_HANDLE As Long = -12&
Private Const INVALID_HANDLE_VALUE As Long = -1&
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim titleStr As String = "Test"
Dim textToWrite As Char() = CType("test", Char())
Dim stdIN As Integer
Dim stdOUT As Integer
Dim charwritten As Integer = 0
Dim ret As Integer
If ReturnCMDProcessID() = 0 Then
MessageBox.Show("CMD off")
Exit Sub
End If
AttachConsole(ReturnCMDProcessID())
stdIN = CInt(GetStdHandle(CInt(STD_INPUT_HANDLE)))
stdOUT = CInt(GetStdHandle(CInt(STD_OUTPUT_HANDLE)))
ret = WriteConsoleInputA(stdIN, textToWrite, textToWrite.Length, charwritten)
SetConsoleTitle(titleStr)
End Sub
Did you try the "built-in" way to do this?
System.Console:
https://learn.microsoft.com/en-us/dotnet/api/system.console?view=netframework-4.8
And in particular Console.In
https://learn.microsoft.com/en-us/dotnet/api/system.console.in?view=netframework-4.8
And Console.Out
https://learn.microsoft.com/en-us/dotnet/api/system.console.out?view=netframework-4.8
I also just noticed you are setting the title, that is as simple as Console.Title = "My Title"
This is the source of the original VBA code: Original VBA code
Im converting these functions to VB.Net
FilePropertyExplorer
Class_Initialize
Heres the code I have thus far (note I removed some lines for brevity)
Imports System.Runtime.InteropServices
Public Class VirtualCOMObject
Private Const OPTION_BASE As Long = 0
Private Const OPTION_FLAGS As Long = 2
Private Const OPTION_INCLUDE_REFERENCEDOCS As Long = 0
Private Const OPTION_DISABLEDCLASSES As String = ""
Private Const DECOMPRESSED_EXT As Long = 56493
Private Const SIZEOF_PTR32 As Long = &H4
Private Const SIZEOF_PTR64 As Long = &H8
Private Const PAGE_EXECUTE_RW As Long = &H40
Private Const MEM_RESERVE_AND_COMMIT As Long = &H3000
Private Const ERR_OUT_OF_MEMORY As Long = &H7
Private m_ClassFactory As Object
<DllImport("kernel32.dll", CharSet:=CharSet.None, ExactSpelling:=False, SetLastError:=True)>
Private Shared Function VirtualAlloc(
ByVal lpAddress As IntPtr,
ByVal dwSize As UIntPtr,
ByVal flAllocationType As AllocationType,
ByVal flProtect As MemoryProtection) As IntPtr
End Function
<DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Public Shared Function GetModuleHandleA(ByVal lpModuleName As String) As IntPtr
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
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Ansi, ExactSpelling:=True, EntryPoint:="RtlMoveMemory")>
Public Shared Sub CopyMemoryAnsi(ByVal Dest As IntPtr, ByVal Source As String, ByVal Size As IntPtr)
End Sub
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Ansi, ExactSpelling:=True, EntryPoint:="RtlMoveMemory")>
Public Shared Sub CastToObject(ByRef Dest As Object, ByRef Source As IntPtr, ByVal Size As IntPtr)
End Sub
Declare Sub CopyMemoryByref Lib "Kernel32.dll" Alias "RtlMoveMemory" (ByRef dest As Integer, ByRef source As Integer, ByVal numBytes As Integer)
<Flags>
Public Enum AllocationType As UInteger
COMMIT = 4096
RESERVE = 8192
RESET = 524288
TOP_DOWN = 1048576
WRITE_WATCH = 2097152
PHYSICAL = 4194304
LARGE_PAGES = 536870912
End Enum
<Flags>
Public Enum MemoryProtection As UInteger
NOACCESS = 1
[READONLY] = 2
READWRITE = 4
WRITECOPY = 8
EXECUTE = 16
EXECUTE_READ = 32
EXECUTE_READWRITE = 64
EXECUTE_WRITECOPY = 128
GUARD_Modifierflag = 256
NOCACHE_Modifierflag = 512
WRITECOMBINE_Modifierflag = 1024
End Enum
Public Sub Class_Initialize()
Dim NativeCode As String
Dim LoaderVTable As IDispatchVTable
Dim Ignore As Boolean
Dim ClassFactoryLoader As Object
#If VBA7 = False Then
Dim Kernel32Handle As Long
Dim GetProcAddressPtr As Long
Dim NativeCodeAddr As Long
Dim LoaderVTablePtr As Long
Dim LoaderObj As Long
#Else
Dim Kernel32Handle As LongPtr
Dim GetProcAddressPtr As LongPtr
Dim NativeCodeAddr As LongPtr
Dim LoaderVTablePtr As LongPtr
Dim LoaderObj As LongPtr
#End If
'#If Win64 = False Then
' Const SIZEOF_PTR = SIZEOF_PTR32
'#Else
Const SIZEOF_PTR = SIZEOF_PTR64
'#End If
'NativeCode string initialized here
NativeCode = NativeCode & "%EEEE%::::RPZPPPh$#$$j PPPPH+T$ t5AYAZkDTX 5j7{{L3TQ#M3LR#A)DR#Xf5##fA)AUXI3DR#ZZZZZZ?!, #RY3LDl3TA#PY,VH)DJ#XXXXXXXXXX%EEEE%::::VSPPPPj PPPPPPPP4T)D$04P)D$,4 '4 )D$($ PZ3D$#+D$ YQ3H +L$ XP3Q +T$0XPf55nf)BUR[YQ^VXP2Cf<0tF1+++
'==========================================================================
'Code removed for brevity. The full string can be found on the links above
'==========================================================================
ij DdEXXZPEdkHOqrLSKGZT;pOCUHvFst;z??qapyyZtzrUuhX_;hnJmp;n;kGQF^AF oqvSDDS\^;TufXPumRLDVQSzCbT]x]keCb?fWgTwFvTwEj0"
ClassFactoryLoader = New Object()
' Allocate the executable memory for the object
NativeCodeAddr = VirtualAlloc(0, Len(NativeCode) + DECOMPRESSED_EXT, MEM_RESERVE_AND_COMMIT, PAGE_EXECUTE_RW)
If NativeCodeAddr <> 0 Then
' Copy the x86 and x64 native code into the allocated memory
Call CopyMemoryAnsi(NativeCodeAddr, NativeCode, Len(NativeCode))
' Force the memory address into an Object variable (also triggers the shell code)
LoaderVTable.QueryInterface = NativeCodeAddr 'longptr
LoaderVTablePtr = VarPtr(LoaderVTable) 'ptr to LoaderVTable(IDispatchVTable structure)
LoaderObj = VarPtr(LoaderVTablePtr)
'==========================================================================
'ERROR: Managed Debugging Assistant 'InvalidVariant' : 'An invalid VARIANT was detected during a conversion from an unmanaged VARIANT to a managed object. Passing invalid VARIANTs to the CLR can cause unexpected exceptions, corruption or data loss.'
'==========================================================================
Call CastToObject(ClassFactoryLoader, LoaderObj, SIZEOF_PTR) 'CastToObject=RtlMoveMemory
Ignore = TypeOf ClassFactoryLoader Is VBA.Collection 'ClassFactoryLoader(object type)
m_ClassFactory = (ClassFactoryLoader) 'object
' Initialize our COM object
Kernel32Handle = GetModuleHandleA("kernel32")
GetProcAddressPtr = GetProcAddress(Kernel32Handle, "GetProcAddress")
'With m_ClassFactory
' Call .Init(Kernel32Handle, GetProcAddressPtr, OPTION_BASE + OPTION_FLAGS, NativeCode, New FilePropertyExplorer_Helper)
' Ignore = TypeOf .FileProperties Is FileProperties And TypeOf .FileProperty Is FileProperty
'End With
Else
Err.Raise(ERR_OUT_OF_MEMORY)
End If
End Sub
Function OpenFile(ByVal FilePath As String, Optional ByVal WriteSupport As Boolean = False) As FileProperties
OpenFile = m_ClassFactory.OpenFile(FilePath, WriteSupport)
End Function
End Class
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi, Pack:=1)>
Public Structure IDispatchVTable
Public QueryInterface As IntPtr
Public AddRef As IntPtr
Public Release As IntPtr
Public GetTypeInfoCount As IntPtr
Public GetTypeInfo As IntPtr
Public GetIDsOfNames As IntPtr
Public Invoke As IntPtr
End Structure
VarToPtr . Im unsure of this code. Found it on the internet and slightly modified it
Module VarPtrSupport
' a delegate that can point to the VarPtrCallback method
Private Delegate Function VarPtrCallbackDelegate(
ByVal address As Integer, ByVal unused1 As Integer,
ByVal unused2 As Integer, ByVal unused3 As Integer) As Integer
' two aliases for the CallWindowProcA Windows API method
' notice that 2nd argument is passed by-reference
Private Declare Function CallWindowProc Lib "user32" _
Alias "CallWindowProcA" _
(ByVal wndProc As VarPtrCallbackDelegate, ByRef var As Short,
ByVal unused1 As Integer, ByVal unused2 As Integer,
ByVal unused3 As Integer) As Integer
Private Declare Function CallWindowProc Lib "user32" _
Alias "CallWindowProcA" _
(ByVal wndProc As VarPtrCallbackDelegate, ByRef var As Integer,
ByVal unused1 As Integer, ByVal unused2 As Integer,
ByVal unused3 As Integer) As Integer
' ...add more overload to support other data types...
Private Declare Function CallWindowProc Lib "user32" _
Alias "CallWindowProcA" _
(ByVal wndProc As VarPtrCallbackDelegate, ByRef var As IDispatchVTable,
ByVal unused1 As Integer, ByVal unused2 As Integer,
ByVal unused3 As Integer) As Integer
Private Declare Function CallWindowProc Lib "user32" _
Alias "CallWindowProcA" _
(ByVal wndProc As VarPtrCallbackDelegate, ByRef var As Long,
ByVal unused1 As Integer, ByVal unused2 As Integer,
ByVal unused3 As Integer) As Integer
Private Declare Function CallWindowProc Lib "user32" _
Alias "CallWindowProcA" _
(ByVal wndProc As VarPtrCallbackDelegate, ByRef var As IntPtr,
ByVal unused1 As Integer, ByVal unused2 As Integer,
ByVal unused3 As Integer) As Integer
' the method that is indirectly executed when calling CallVarPtrSupport
' notice that 1st argument is declared by-value (this is the
' argument that receives the 2nd value passed to CallVarPtrSupport)
Private Function VarPtrCallback(ByVal address As Integer,
ByVal unused1 As Integer, ByVal unused2 As Integer,
ByVal unused3 As Integer) As Integer
Return address
End Function
' two overloads of VarPtr
Public Function VarPtr(ByRef var As Short) As Integer
Return CallWindowProc(AddressOf VarPtrCallback, var, 0, 0, 0)
End Function
Public Function VarPtr(ByRef var As Integer) As Integer
Return CallWindowProc(AddressOf VarPtrCallback, var, 0, 0, 0)
End Function
Public Function VarPtr(ByRef var As IDispatchVTable) As Integer
Return CallWindowProc(AddressOf VarPtrCallback, var, 0, 0, 0)
End Function
Public Function VarPtr(ByRef var As Long) As Integer
Return CallWindowProc(AddressOf VarPtrCallback, var, 0, 0, 0)
End Function
Public Function VarPtr(ByRef var As IntPtr) As Integer
Return CallWindowProc(AddressOf VarPtrCallback, var, 0, 0, 0)
End Function
' ...add more overload to support other data types...
End Module
Now I currently get the error (I placed a comment in the code):
ERROR: Managed Debugging Assistant 'InvalidVariant' : 'An invalid VARIANT was detected during a conversion from an unmanaged VARIANT to a managed object. Passing invalid VARIANTs to the CLR can cause unexpected exceptions, corruption or data loss.'
But overall... Im actually unsure if Im even on the right track in properly converting the VBA code as Im having to do it without for example excel installed to test the VBA out on.
The code essentially creates a dynamic COM object which will then be used to fetch extended file properties.
If someone could perhaps tell me what Im doing wrong it will be appreciated. Also the code needs to be in .Net and not import any VBA/VB dll's.
In reference to #Jimi's comment, I have created a couple of vba functions for you.
Here is the vba Code which you can just paste into an excel "ThisWorkbook" object.
It will create a text file name "ExtendedProperties.txt" in the same directory as the file that is passed to it.
Sub GetExtendedProperties(strInFullFilePath)
Dim objShell As Object
Dim objFolder As Object
Dim objFolderItem As Object
Dim strPath As String
Dim strFldr As String
Dim vntInfo As Variant
Dim intI As Integer
Dim strName As String
Dim strTemp As String
Dim fso As Object
Dim strOut As String
Dim ts As Object
Set fso = CreateObject("Scripting.FileSystemObject")
strPath = fso.GetAbsolutePathName(strInFullFilePath)
strFldr = fso.GetParentFolderName(strPath)
strName = fso.GetFileName(strPath)
strOut = strFldr & "\ExtendedProperties.txt"
Set ts = fso.CreateTextFile(strOut, True)
Set objShell = CreateObject("shell.application")
If (Not (objShell Is Nothing)) Then
Set objFolder = objShell.Namespace(CStr(strFldr))
If (Not (objFolder Is Nothing)) Then
Set objFolderItem = objFolder.ParseName(CStr(strName))
If (Not (objFolderItem Is Nothing)) Then
For intI = 0 To 321
If intI <> 31 Then
vntInfo = objFolder.GetDetailsOf(Nothing, intI)
strTemp = CStr(vntInfo)
If (InStr(1, strTemp, vbNull) > 0) Then strTemp = Replace(strTemp, vbNull, "")
If IsNull(strTemp) = False Then
ts.WriteLine "File Detail Attribute: " & CheckString(strTemp)
Else
ts.WriteLine "File Detail Attribute: NULL"
End If
vntInfo = objFolder.GetDetailsOf(objFolderItem, intI)
strTemp = CStr(vntInfo)
If (InStr(1, strTemp, vbNull) > 0) Then strTemp = Replace(strTemp, vbNull, "")
If IsNull(strTemp) = False Then
ts.WriteLine "Value: """ & CheckString(strTemp) & """"
Else
ts.WriteLine "Value: NULL"
End If
End If
Next intI
End If
Set objFolderItem = Nothing
End If
Set objFolder = Nothing
End If
ts.Close
Set ts = Nothing
Set objShell = Nothing
End Sub
Private Function CheckString(strInString As String) As String
Dim strOut As String
Dim strTemp As String
Dim blnValid As Boolean
Dim intI As Integer
Dim intJ As Integer
Dim strChar As String
Dim bytChars() As Byte
'This Function is used to check the string to see if there are any problem
' characters in the string (as there are at intI=31 in the above function).
strTemp = strInString
strOut = ""
For intI = 1 To Len(strTemp)
strChar = Mid(strTemp, intI, 1)
If (AscW(strChar) = 32) Or (AscW(strChar) >= 48) And (AscW(strChar) <= 57) Or _
(AscW(strChar) >= 65) And (AscW(strChar) <= 90) Or _
(AscW(strChar) >= 97) And (AscW(strChar) <= 122) Then
strOut = strOut & strChar
End If
Next intI
CheckString = strOut
End Function
This question is basically regarding to loop all workbooks in all excel instances!
Your main issue you are facing is you are not using any of the process's you come across. Therefore, you will not get anything that way. Inside of the loop for the process's you then create a new instance of ExcelApplication and then try to loop through the Workbooks. By default when you do this there is only 1 at that time, hence why you get only 1 Workbook and also why you will only ever see 1 Workbook.
Solution (Tried & Tested)
You need to look into Windows API calls to get what you need. A few of them are:
GetDesktopWindow()
EnumChildWindows()
GetClassName()
EnumWindowsProc()
AccessibleObjectFromWindow()
Imports Microsoft.Office.Interop
Imports System.Runtime.InteropServices
Public Class Form1
Private Declare Function GetDesktopWindow Lib "user32" () As Integer
Private Declare Function EnumChildWindows Lib "user32.dll" (ByVal WindowHandle As IntPtr, ByVal Callback As EnumWindowsProc, ByVal lParam As IntPtr) As Boolean
Private Declare Function GetClassName Lib "user32.dll" Alias "GetClassNameA" (ByVal hWnd As IntPtr, ByVal lpClassName As String, ByVal nMaxCount As Integer) As Integer
Private Delegate Function EnumWindowsProc(ByVal hwnd As IntPtr, ByVal lParam As Int32) As Boolean
Private Declare Function AccessibleObjectFromWindow Lib "oleacc" (ByVal Hwnd As Int32, ByVal dwId As Int32, ByRef riid As Guid, <MarshalAs(UnmanagedType.IUnknown)> ByRef ppvObject As Object) As Int32
Private Const OBJID_NATIVE = &HFFFFFFF0
'Required to show the workbooks. Used in function to add to.
Private lstWorkBooks As New List(Of String)
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
lstWorkBooks.Clear()
GetExcelOpenWorkBooks()
End Sub
Private Sub GetExcelOpenWorkBooks()
Try
'Get handle to desktop
Dim WindowHandle As IntPtr = GetDesktopWindow()
'Enumerate through the windows (objects) that are open
EnumChildWindows(WindowHandle, AddressOf GetExcelWindows, 0)
'List the workbooks out if we have something
If lstWorkBooks.Count > 0 Then MsgBox(String.Join(Environment.NewLine, lstWorkBooks))
Catch ex As Exception
End Try
End Sub
Public Function GetExcelWindows(ByVal hwnd As IntPtr, ByVal lParam As Int32) As Boolean
Dim Ret As Integer = 0
Dim className As String = Space(255) 'Return the string with some padding...
Ret = GetClassName(hwnd, className, 255)
className = className.Substring(0, Ret)
If className = "EXCEL7" Then
Dim ExcelApplication As Excel.Application
Dim ExcelObject As Object = Nothing
Dim IDispatch As Guid
AccessibleObjectFromWindow(hwnd, OBJID_NATIVE, IDispatch, ExcelObject)
'Did we get anything?
If ExcelObject IsNot Nothing Then
ExcelApplication = ExcelObject.Application
'Make sure we have the instance...
If ExcelApplication IsNot Nothing Then
'Go through the workbooks...
For Each wrk As Excel.Workbook In ExcelApplication.Workbooks
'If workbook ins't in the list then add it...
If Not lstWorkBooks.Contains(wrk.Name) Then
lstWorkBooks.Add(wrk.Name)
End If
Next
End If
End If
End If
Return True
End Function
End Class
i want to check if the active window handle is password box.
this function returns me the active control handle of the active window:
Imports System.Runtime.InteropServices
Public Class FormMain
Inherits Form
Private Declare Function GetForegroundWindow Lib "user32.dll" () As IntPtr
Private Declare Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal ProcessId As IntPtr) As IntPtr
Private Declare Function AttachThreadInput Lib "user32.dll" (ByVal idAttach As IntPtr, ByVal idAttachTo As IntPtr, ByVal fAttach As Boolean) As IntPtr
Private Declare Function GetFocus Lib "user32.dll" () As IntPtr
Public Sub New()
MyBase.New
InitializeComponent
End Sub
Private Sub timerUpdate_Tick(ByVal sender As Object, ByVal e As EventArgs)
labelHandle.Text = ("hWnd: " + FocusedControlInActiveWindow.ToString)
End Sub
Private Function FocusedControlInActiveWindow() As IntPtr
Dim activeWindowHandle As IntPtr = GetForegroundWindow
Dim activeWindowThread As IntPtr = GetWindowThreadProcessId(activeWindowHandle, IntPtr.Zero)
Dim thisWindowThread As IntPtr = GetWindowThreadProcessId(Me.Handle, IntPtr.Zero)
AttachThreadInput(activeWindowThread, thisWindowThread, true)
Dim focusedControlHandle As IntPtr = GetFocus
AttachThreadInput(activeWindowThread, thisWindowThread, false)
Return focusedControlHandle
End Function
End Class
now i want to do something like:
if FocusedControlInActiveWindow() <> intptr.zero then
dim IsPass as boolean = isPassword(FocusedControlInActiveWindow())
if IsPass then
msgbox("yes")
else
msgbox ("no")
end if
end if
how can i check if the foucsed control in the active window text is passwordcahr?
If you want to check if a Windows Edit Control has the ES_PASSWORD style, this is how to do it:
Public Shared Function HasPasswordStyle(ByVal hWnd As IntPtr) As Boolean
Return ((GetWindowLong(hWnd, GWL_STYLE) And ES_PASSWORD) <> 0)
End Function
<DllImport("user32.dll")> _
Private Shared Function GetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
End Function
Private Const ES_PASSWORD As Integer = 32
Private Const GWL_STYLE As Integer = -16
I am new to VSTO VB.Net programming. and I am developing a word application level Addin and want to trap keypress event. I have tried various codes of hooking but none is working. I want to use application level hook using WH_KEYBOARD instead of WH_KEYBOARD_LL. The following code which I have tried traps just one key stroke after that it stops. Moreover I could not understand where to put trap the keystrokes. How would I use the following for handling key events.
Public Event KeyDown As KeyEventHandler
Public Event KeyPress As KeyPressEventHandler
Public Event KeyUp As KeyEventHandler
The code that I am using is
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
Public Class KeyBoardHook
Inherits Component
Dim PredictString As String
#Region " keyboardHook"
Private Declare Auto Function LoadLibrary Lib "kernel32" (ByVal lpFileName As String) As IntPtr
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hhk As IntPtr) As Boolean
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Integer, _
ByVal lpfn As KeyboardProc, ByVal hmod As IntPtr, ByVal dwThreadId As Integer) As IntPtr
Private Delegate Function KeyboardProc(ByVal Code As Integer, ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As IntPtr
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As IntPtr, ByVal nCode As Integer, ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As IntPtr
Private Structure KBDLLHOOKSTRUCT
Public vkCode As Integer
Public scanCode As Integer
Public flags As Integer
Public time As Integer
Public dwExtraInfo As Integer
End Structure
'Keyboard Constants
Private Const HC_ACTION As Integer = 0
Private Const WM_KEYDOWN As Integer = &H100
Private Const WM_KEYUP As Integer = &H101
Private Const WM_SYSKEYDOWN As Integer = &H104
Private Const WM_SYSKEYUP As Integer = &H105
Private Const WH_KEYBOARD As Integer = 2
Public hKeyboardHook As IntPtr
Public Event KeyDown As KeyEventHandler
Public Event KeyPress As KeyPressEventHandler
Public Event KeyUp As KeyEventHandler
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Integer) As Integer
Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Integer) As Integer
Private Const VK_ALT As Integer = &H12
Private Const VK_CONTROL As Integer = &H11
Private Const VK_SHIFT As Integer = 16
<MarshalAs(UnmanagedType.FunctionPtr)> Private callback As KeyboardProc
Public Sub HookKeyboard()
callback = New KeyboardProc(AddressOf KeyboardCallback)
Dim hInstance As IntPtr = LoadLibrary("User32")
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, callback, hInstance, 0)
CheckHooked()
End Sub
Private Function KeyboardCallback(ByVal Code As Integer, ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As IntPtr
Dim xy As System.Drawing.Point = Cursor.Position()
Try
If (Code = HC_ACTION Or Code = 3) Then
Dim CapsLock As Boolean = GetKeyState(Keys.CapsLock) = 1
Dim shifting As Boolean = False
Dim modifiers As Keys
If GetAsyncKeyState(VK_CONTROL) <> 0 Then
modifiers = modifiers Or Keys.Control
End If
If GetAsyncKeyState(VK_SHIFT) <> 0 Then
modifiers = modifiers Or Keys.Shift
shifting = True
End If
If GetAsyncKeyState(VK_ALT) <> 0 Then
modifiers = modifiers Or Keys.Alt
End If
Static lastKeys As Keys
Select Case wParam
Case WM_KEYDOWN, WM_SYSKEYDOWN
RaiseEvent KeyDown(Me, New KeyEventArgs(DirectCast(Asc(Chr(lParam.vkCode)), Keys) Or modifiers))
If lastKeys <> (DirectCast(Asc(Chr(lParam.vkCode)), Keys) Or modifiers) Then
lastKeys = (DirectCast(Asc(Chr(lParam.vkCode)), Keys) Or modifiers)
If CapsLock AndAlso shifting Then
RaiseEvent KeyPress(Me, New KeyPressEventArgs(Char.ToLower(Chr(lParam.vkCode))))
ElseIf Not CapsLock AndAlso shifting Then
RaiseEvent KeyPress(Me, New KeyPressEventArgs(Char.ToUpper(Chr(lParam.vkCode))))
ElseIf Not shifting Then
If CapsLock Then
RaiseEvent KeyPress(Me, New KeyPressEventArgs(Char.ToUpper(Chr(lParam.vkCode))))
Else
RaiseEvent KeyPress(Me, New KeyPressEventArgs(Char.ToLower(Chr(lParam.vkCode))))
End If
End If
End If
Case WM_KEYUP, WM_SYSKEYUP
If CapsLock AndAlso shifting Then
RaiseEvent KeyUp(Me, New KeyEventArgs(DirectCast(Asc(Chr(lParam.vkCode)), Keys) Or modifiers))
ElseIf Not CapsLock AndAlso shifting Then
RaiseEvent KeyUp(Me, New KeyEventArgs(DirectCast(Asc(Chr(lParam.vkCode)), Keys) Or modifiers))
ElseIf Not shifting Then
If CapsLock Then
RaiseEvent KeyUp(Me, New KeyEventArgs(DirectCast(Asc(Chr(lParam.vkCode)), Keys) Or modifiers))
Else
RaiseEvent KeyUp(Me, New KeyEventArgs(DirectCast(Asc(Chr(lParam.vkCode)), Keys) Or modifiers))
End If
End If
lastKeys = Nothing
End Select
End If
MsgBox("Keypressed is -> " & lParam.vkCode)
Return CallNextHookEx(hKeyboardHook, Code, wParam, lParam)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Function
Private Function keyboardHooked() As Boolean
Return hKeyboardHook <> IntPtr.Zero
End Function
Public Sub UnhookKeyboard()
If keyboardHooked() Then
UnhookWindowsHookEx(hKeyboardHook)
End If
End Sub
#End Region
Private Sub CheckHooked()
If keyboardHooked() Then
MsgBox("Keyboard hooked")
Else
MsgBox("Keyboard hook failed: " & Err.LastDllError)
End If
End Sub
End Class
Your question is a possible duplicate of:
How to get the "KeyPress" event from a Word 2010 Addin (developed in C#)?
How to raise an event on MS word Keypress
Capturing keydown event of MS Word using C#
... however, the answer remains the same: you simply can't :)
In my answer to the last of the questions listed above I explain the reason behind this in a bit more detail, and also covers a possible alternative solution involving the WindowSelectionChange event.