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"
Related
I have been trying to connect remote PC with known Credentials but variable lon(refer below code) is showing Error-487.
Code:
Private Declare Function WNetAddConnection2 Lib "mpr.dll" Alias "WNetAddConnection2A" ( ByRef lpNetResource As NETRESOURCE, ByVal lpPassword As String, ByVal lpUserName As String, ByVal dwFlags As Integer) As Long
Private Declare Function WNetCancelConnection2 Lib "mpr.dll" Alias "WNetCancelConnection2A" (ByVal lpName As String, ByVal dwFlags As Long, ByVal fForce As Integer) As Long
Private Structure NETRESOURCE
Dim dwType As Long
Dim lpRemoteName As String
End Structure
Private Const RESOURCETYPE_DISK = &H1
Private Sub ConnectToPC()
Dim networkResource As New NETRESOURCE
Dim lon As Long
With networkResource
.dwType = RESOURCETYPE_DISK
.lpRemoteName = "\\192.168.1.1"
End With
lon = WNetAddConnection2(networkResource, "123", "ADMIN", 0)
msgbox(lon)
lon = WNetCancelConnection2("\\192.168.1.1", 0, 1)
msgbox(lon)
End Sub
Tried Below thing but it didn't serve my purpose
- Change type from Integer to Int32/Int64
I have been working on this issue for last two days but couldn't gain any success. Can anybody tell me what went wrong with code? Any help will be highly Appreciated
I haven't learned yet how to correctly convert the Windows API functions to be used on Excel VBA. If I can't find it online and it isn't something easy like SwapMouseButton or SetDoubleClickTime I just get stuck on getting it to work.
Can I get some help fixing my call of the GetMouseMovePointsEx function and maybe tips to understand better how to do it for other complex function?
Here's what I have in a module:
Private Declare Function SwapMouseButton Lib "user32" (ByVal fSwap As Boolean) As Boolean
Private Declare Function SetDoubleClickTime Lib "user32" (ByVal uInterval As Integer) As Boolean
Private Type MOUSEMOVEPOINT
x As Integer
y As Integer
time As Long
dwExtraInfo As Long
End Type
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function GetActiveWindow Lib "user32" () As Long
'Private Declare Function WindowProc Lib "user32" (ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const WM_MOUSEDOWN = &H200
Private Declare Function GetMouseMovePointsEx Lib "user32" (ByVal cbSize As Integer, ByRef lppt As MOUSEMOVEPOINT, ByRef lpptBuf() As MOUSEMOVEPOINT, ByVal nBufPoints As Integer, ByVal resolution As Long) As Integer
Private Sub Test1()
SwapMouseButton False 'True|False
End Sub
Private Sub Test2()
SetDoubleClickTime 0 '0=default(500), 48~=fastest I could get, >5000=5000
End Sub
Private Sub Test3()
Dim hwnd As Long, mmp As MOUSEMOVEPOINT, mmpBuf(64) As MOUSEMOVEPOINT, returnedValue As Integer
Sleep 1000
hwnd = GetActiveWindow()
'WindowProc hwnd, WS_MOUSEMOVE, WS_MOUSEMOVE, WS_MOUSEMOVE
mmp.x = 600
mmp.y = 300
mmp.time = 200
returnedValue = GetMouseMovePointsEx(Len(mmp), mmp, mmpBuf, 1000, 1)
If returnedValue = -1 Then
Debug.Print "Error"
Else
Debug.Print mmpBuf(0).x
Debug.Print mmpBuf(0).y
End If
End Sub
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'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!
So i have the following code
Imports System.Diagnostics
Imports System.IO
Imports System.Runtime.InteropServices
Public Class Form1
<StructLayout(LayoutKind.Sequential)> _
Structure OSVERSIONINFO
Dim dwOSVersionInfoSize As Integer
Dim dwMajorVersion As Integer
Dim dwMinorVersion As Integer
Dim dwBuildNumber As Integer
Dim dwPlatformId As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128), VBFixedString(128)> Dim szCSDVersion As String
End Structure
<StructLayout(LayoutKind.Sequential)> _
Structure MEMORY_BASIC_INFORMATION
Dim BaseAddress As Integer
Dim AllocationBase As Integer
Dim AllocationProtect As Integer
Dim RegionSize As Integer
Dim State As Integer
Dim Protect As Integer
Dim lType As Integer
End Structure
<StructLayout(LayoutKind.Sequential)> _
Structure SYSTEM_INFO ' 36 Bytes
Dim dwOemID As Integer
Dim dwPageSize As Integer
Dim lpMinimumApplicationAddress As Integer
Dim lpMaximumApplicationAddress As Integer
Dim dwActiveProcessorMask As Integer
Dim dwNumberOrfProcessors As Integer
Dim dwProcessorType As Integer
Dim dwAllocationGranularity As Integer
Dim wProcessorLevel As Short
Dim wProcessorRevision As Short
End Structure
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (ByRef LpVersionInformation As OSVERSIONINFO) As Integer
Private Declare Function VirtualQueryEx Lib "kernel32.dll" (ByVal hProcess As IntPtr, ByVal lpAddress As UInteger, ByRef lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As Integer) As Integer
Private Declare Sub GetSystemInfo Lib "kernel32" (ByRef lpSystemInfo As SYSTEM_INFO)
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Integer, ByVal blnheritHandle As Integer, ByVal dwAppProcessId As Integer) As Integer
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Integer) As Integer
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByRef lpBaseAddress As Integer, ByRef lpBuffer As Long, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByRef lpBaseAddress As Integer, ByRef lpBuffer As String, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Integer, ByRef lpdwProcessId As Integer) As Integer
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Integer, ByVal lpWindowName As Integer) As Integer
Private Declare Function GetParent Lib "user32" (ByVal hWnd As Integer) As Integer
Private Declare Function GetWindow Lib "user32" (ByVal hWnd As Integer, ByVal wCmd As Integer) As Integer
Private Const PROCESS_VM_READ = (&H10)
Private Const PROCESS_VM_OPERATION = (&H8)
Private Const PROCESS_QUERY_INFORMATION = (&H400)
Public Const PROCESS_READ_WRITE_QUERY = PROCESS_VM_READ + PROCESS_VM_OPERATION + PROCESS_QUERY_INFORMATION
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim pid As Integer, hProcess As Integer
Dim lpMem As Integer, ret As DialogResult, lLenMBI As Integer
Dim lWritten As Integer
Dim sBuffer As String
Dim sSearchString As String = "", sReplaceString As String = ""
Dim si As SYSTEM_INFO
Dim mbi As MEMORY_BASIC_INFORMATION
For Each p As Process In Process.GetProcesses
If p.ProcessName = "notepad" Then
pid = p.Id
End If
Next
hProcess = OpenProcess(PROCESS_READ_WRITE_QUERY, False, pid)
lLenMBI = Len(mbi)
'Determine applications memory addresses range
GetSystemInfo(si)
lpMem = si.lpMinimumApplicationAddress
Do While lpMem < si.lpMaximumApplicationAddress
mbi.RegionSize = 0
ret = VirtualQueryEx(hProcess, lpMem, mbi, lLenMBI)
If ret = lLenMBI Then
If ((mbi.lType = &H20000) And (mbi.State = &H1000)) Then
If mbi.RegionSize > 0 Then
Dim stringinmemory As Long
sBuffer = mbi.RegionSize
ReadProcessMemory(hProcess, mbi.BaseAddress, stringinmemory, mbi.RegionSize, lWritten)
Debug.WriteLine(sBuffer)
End If
End If
lpMem = mbi.BaseAddress + mbi.RegionSize
Else
Exit Do
End If
Loop
CloseHandle(hProcess)
End Sub
End Class
And it should read all notepad memory (step by step like). I get no errors when i run it , but it returns
4096
4096
4096
8192
90112
4096
344064
131072
8192
45056
172032
4096
155648
4096
This code works well in VB6, but i converted it to VB.NET.
What am I doing wrong ? Can you help me please ?
Thanks in advance.
Nicu
You are printing the value of sBuffer which is an integer which explains the results you are seeing. Besides, sBuffer does not contain the data which is read from memory. I think your lpBuffer parameter (and also stringinmemory as well) should not be a Long but instead be an Byte array. Something like this:
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
Public Shared Sub Main()
Dim notepadProcess As Process = Process.GetProcessesByName("notepad")(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), &H36B9D0, buffer, buffer.Length, bytesRead)
Console.WriteLine(Encoding.Unicode.GetString(buffer))
Console.ReadLine()
End Sub