Hi currently I'm having this code below.
It retrieves the filename of open excel document from process and displays it.
For now it can retrieve it from my own pc, but when I wanted to remotely retrieves it from other pc, it doesn't work.
I have authorized access and I could actually get the process id and name of remote pcs only.
Dim w As Object
Dim processQ As String
Dim processes As Object
Dim processA As Object
Dim pname As String
w = GetObject("winmgmts:{impersonationLevel=impersonate}\\" & pc & "\root\cimv2")
processQ = "SELECT * FROM win32_process WHERE name = 'EXCEL.EXE'"
processes = w.execquery(processQ)
For Each processA In processes
activeprocess = Process.GetProcessById(processA.processid)
MsgBox(processA.processid & processA.name)
Dim windows As IDictionary(Of IntPtr, String) = GetOpenWindowsFromPID(processA.processid)
MsgBox(windows.Count())
For Each kvp As KeyValuePair(Of IntPtr, String) In windows
Dim value As String = kvp.Value.ToString
If InStr(value, "Excel") = False Then
MsgBox(value)
End If
Next
Next
Can anyone tell me what should I do and what's wrong with this?
<DllImport("USER32.DLL")>
Private Shared Function GetShellWindow() As IntPtr
End Function
<DllImport("USER32.DLL")>
Private Shared Function GetWindowText(ByVal hwnd As IntPtr, ByVal lpString As StringBuilder, ByVal nMaxCount As Integer) As Integer
End Function
<DllImport("USER32.DLL")>
Private Shared Function GetWindowTextLength(ByVal hwnd As IntPtr) As Integer
End Function
<DllImport("USER32.DLL", SetLastError:=True)>
Private Shared Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, <Out()> ByRef lpdwProcessId As UInt32) As UInt32
End Function
<DllImport("USER32.DLL")>
Private Shared Function IsWindowVisible(ByVal hwnd As IntPtr) As Boolean
End Function
Private Delegate Function EnumWindowsProc(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
<DllImport("USER32.DLL")>
Private Shared Function EnumWindows(ByVal enumFunc As EnumWindowsProc, ByVal lParam As Integer) As Boolean
End Function
Private hShellWindow As IntPtr = GetShellWindow()
Private dictWindows As New Dictionary(Of IntPtr, String)
Private currentProcessID As Integer
Public Function GetOpenWindowsFromPID(ByVal processID As Integer) As IDictionary(Of IntPtr, String)
dictWindows.Clear()
currentProcessID = processID
EnumWindows(AddressOf enumWindowsInternal, 0)
Return dictWindows
End Function
Public Function enumWindowsInternal(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
If (hwnd <> hShellWindow) Then
Dim windowPid As UInt32
If Not IsWindowVisible(hwnd) Then
Return True
End If
Dim length As Integer = GetWindowTextLength(hwnd)
If (length = 0) Then
Return True
End If
GetWindowThreadProcessId(hwnd, windowPid)
If (windowPid <> currentProcessID) Then
Return True
End If
Dim stringBuilder As New StringBuilder(length)
GetWindowText(hwnd, stringBuilder, (length + 1))
dictWindows.Add(hwnd, stringBuilder.ToString)
End If
Return True
End Function
Sorry I'm quite new to vb.net.. but I'm learning thanks!
Related
I Tried to convert this code into vb.net and add a little code to make a file... but the file's resolution became crap and i cant seem to insert it into the Crystal report, Did i do something wrong while converting it into vb.net? thanks in advance :)
Here is the original link Convert an image into WMF with .NET?
<Flags>
Private Enum EmfToWmfBitsFlags
EmfToWmfBitsFlagsDefault = &H0
EmfToWmfBitsFlagsEmbedEmf = &H1
EmfToWmfBitsFlagsIncludePlaceable = &H2
EmfToWmfBitsFlagsNoXORClip = &H4
End Enum
Private Shared MM_ISOTROPIC As Integer = 7
Private Shared MM_ANISOTROPIC As Integer = 8
<DllImport("gdiplus.dll")>
Private Shared Function GdipEmfToWmfBits(_hEmf As IntPtr, _bufferSize As UInteger, _buffer As Byte(), _mappingMode As Integer, _flags As EmfToWmfBitsFlags) As UInteger
End Function
<DllImport("gdi32.dll")>
Private Shared Function SetMetaFileBitsEx(_bufferSize As UInteger, _buffer As Byte()) As IntPtr
End Function
<DllImport("gdi32.dll")>
Private Shared Function CopyMetaFile(hWmf As IntPtr, filename As String) As IntPtr
End Function
<DllImport("gdi32.dll")>
Private Shared Function DeleteMetaFile(hWmf As IntPtr) As Boolean
End Function
<DllImport("gdi32.dll")>
Private Shared Function DeleteEnhMetaFile(hEmf As IntPtr) As Boolean
End Function
Private Function MakeMetafileStream(image As Bitmap) As Byte()
Dim metafile As Metafile = Nothing
Using g As Graphics = Graphics.FromImage(image)
Dim hDC As IntPtr = g.GetHdc()
metafile = New Metafile(hDC, EmfType.EmfOnly)
g.ReleaseHdc(hDC)
End Using
Using g As Graphics = Graphics.FromImage(metafile)
g.DrawImage(image, 0, 0)
End Using
Dim _hEmf As IntPtr = metafile.GetHenhmetafile()
Dim _bufferSize As UInteger = GdipEmfToWmfBits(_hEmf, 0, Nothing, MM_ANISOTROPIC, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault)
Dim _buffer As Byte() = New Byte(_bufferSize - 1) {}
GdipEmfToWmfBits(_hEmf, _bufferSize, _buffer, MM_ANISOTROPIC, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault)
Dim hmf As IntPtr = SetMetaFileBitsEx(_bufferSize, _buffer)
Dim tempfile As String = Path.GetTempFileName()
CopyMetaFile(hmf, tempfile)
DeleteMetaFile(hmf)
DeleteEnhMetaFile(_hEmf)
Dim stream = New MemoryStream()
Dim data As Byte() = File.ReadAllBytes(tempfile)
Return data
End Function
Private Sub Convert()
Dim src As New Bitmap("C:\Users\Sample\Desktop\Logos\LogoTransparent\Transparentlogo.png")
Dim Msteam As Byte() = MakeMetafileStream(src)
Dim newF As String = "C:\Users\Alvin Rodriguez\Desktop\Logos\new logo transparent\Transparentlogo.wmf"
System.IO.File.WriteAllBytes(newF, Msteam)
Msteam = Nothing
End Sub
Some interface are to be modifed:
Declare Function CopyEnhMetaFile Lib "gdi32" Alias "CopyEnhMetaFileA" (ByVal hemfSrc As IntPtr, ByVal lpszFile As String) As IntPtr
Declare Function DeleteEnhMetaFile Lib "gdi32" (ByVal hemf As IntPtr) As Integer
Private Declare Function GdipEmfToWmfBits Lib "gdiplus.dll" (ByVal hEmf As IntPtr, ByVal bufferSize As UInteger, ByVal buffer() As Byte, ByVal mappingMode As Integer, ByVal flags As EmfToWmfBitsFlags) As UInteger
CryptAcquireContext function returns FALSE with The Keyset is not defined error message. Here is my code.
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Public Shared Function CryptAcquireContext(ByRef hProv As IntPtr, ByVal pszContainer As String, ByVal pszProvider As String, ByVal dwProvType As Int32, ByVal dwFlags As UInt32) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Public Shared Function CryptCreateHash(ByVal hProv As IntPtr, ByVal Algid As Int32, ByVal hKey As IntPtr, ByVal dwFlags As Int32, ByRef phHash As IntPtr) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Public Shared Function CryptHashData(ByVal hHash As IntPtr, ByVal pbData() As Byte, ByVal dwDataLen As Int32, ByVal dwFlags As Int32) As Boolean
End Function
Public Const PROV_RSA_FULL As Int32 = 1
Private Const CRYPT_VERIFYCONTEXT As UInt32 = &HF0000000UI
Private Function GetHash(ByVal text As String) As Boolean
Dim bResult As Boolean = False
Dim hProv As IntPtr
Dim hHash As IntPtr
If CryptAcquireContext(hProv, vbNull, vbNull, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) Then
If CryptCreateHash(hProv, CALG_SHA1, 0, 0, hHash) Then
If CryptHashData(hHash, Encoding.ASCII.GetBytes(text), text.Length, 0) Then
Dim bHash(20) As Byte
Dim dwHashLen As Int32 = Marshal.SizeOf(bHash)
bResult = CryptGetHashParam(hHash, HP_HASHVAL, bHash, dwHashLen, 0)
If bResult = True Then
//Rest of string operations
End If
End If
End If
End If
Dim errorMessage As String = New Win32Exception(Marshal.GetLastWin32Error()).Message
MsgBox(errorMessage)
Return bResult
End Function
Do you have any idea about what i'm doing wrong?
Thanks
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
OK, this problem has been bugging me for a long time.
I have the code for the service which communicates a string to the client via PostMessage:
Public Sub SendToClient(msgs As String, types As Integer, hwnd As Long)
postMessage(hwnd, 0, Nothing, msgs)
End Sub
Then I have the client that receives the string:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If (m.Msg = 0) Then
Dim a as string
a = Marshal.PtrToStringAuto(m.LParam)
end if
MyBase.WndProc(m)
End Sub
However, the client sends an error, or some jumble of binary data or even just a blank string sometimes. By the way, the m.LParam is a number.
Can someone tell me what is the right way to send/receive strings via postmessage.
I do it like this:
Public Sub SendMessageToApp(ByVal NombreVentana As String, ByVal Mensaje As String, ByVal sender As Form)
Dim hWnd As IntPtr
Dim mCopyData As COPYDATASTRUCT
hWnd = CType(FindWindow(Nothing, NombreVentana), IntPtr)
Dim message As New System.Text.StringBuilder
If (CInt(hWnd) <> 0) Then
message.Append(Mensaje)
Dim pCopyData As IntPtr = Marshal.AllocHGlobal(message.Length() + 40)
mCopyData.lpData = Marshal.StringToHGlobalAnsi(message.ToString)
mCopyData.cbData = message.Length
mCopyData.dwData = CType(_messageID, IntPtr)
Marshal.StructureToPtr(mCopyData, pCopyData, False)
SendMessage(hWnd, WM_COPYDATA, CInt(sender.Handle), pCopyData)
Marshal.FreeHGlobal(mCopyData.lpData)
Marshal.FreeHGlobal(pCopyData)
End If
End Sub
Receiver window:
Declarations and definitions:
Const WM_COPYDATA As Integer = 74
Const SIG_LENGTH As Integer = 36
Const MAX_COPY_LENGTH As Integer = 128
Const SigConnect As String = "F7B82657-BD18-4ee6-B182-78721293821C"
Dim CDCount As Integer
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, _
ByVal lParam As IntPtr) As Integer
Dim hWndSender As Integer
Private Const _messageID As Integer = 10
'Estructura obligatoria para poder utilizar el API CopyData
<StructLayout(LayoutKind.Sequential)> _
Private Structure COPYDATASTRUCT
Public dwData As IntPtr
Public cbData As Integer
Public lpData As IntPtr
End Structure
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_COPYDATA Then
Dim Estructura As COPYDATASTRUCT
Dim tipo As Type = Estructura.GetType
Dim message As String
Estructura = CType(m.GetLParam(GetType(COPYDATASTRUCT)), COPYDATASTRUCT)
'Here you get the message
message = Marshal.PtrToStringAnsi(Estructura.lpData, Estructura.cbData)
End If
I got all Child Windows of handle,
Now I want to get the caption of every Child Window by handle.
my code:
For Each p As Process In Process.GetProcessesByName("MyProccess")
Dim ChildrenList As New List(Of IntPtr)
ChildrenList = GetChildWindows(p.MainWindowHandle)
MsgBox(ChildrenList.Count) ' = 343
For Each hh As IntPtr In ChildrenList
' i want to do something like: MsgBox(getCaption(hh))
Next
Next
How can I do it?
You can get the title of a window with the GetWindowText function. You'll need to p/invoke to it. You can find sample code for this at pinvoke.net.
Source : #1 & #2
By caption i hope you mean "The window Title text"
you have already created a list of window handle of child windows
for rest will be easy
<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
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function GetWindowTextLength(ByVal hwnd As IntPtr) As Integer
End Function
Public Function GetText(ByVal hWnd As IntPtr) As String
Dim length As Integer
If hWnd.ToInt32 <= 0 Then
Return Nothing
End If
length = GetWindowTextLength(hWnd)
If length = 0 Then
Return Nothing
End If
Dim sb As New System.Text.StringBuilder("", length + 1)
GetWindowText(hWnd, sb, sb.Capacity)
Return sb.ToString()
End Function
Usage :
For Each p As Process In Process.GetProcessesByName("MyProccess")
Dim ChildrenList As New List(Of IntPtr)
ChildrenList = GetChildWindows(p.MainWindowHandle)
MsgBox(ChildrenList.Count) ' = 343
For Each hh As IntPtr In ChildrenList
Dim caption As String = GetText(hh)
' use the caption the way u want
Next
Next