Get MS-Word application instance using process handle - c#

Using this,
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern IntPtr GetForegroundWindow();
I retrieve handle for a process then,
IntPtr hwnd = GetForegroundWindow();
int pid = APIFuncs.GetWindowProcessID(hwnd);
Process p = Process.GetProcessById(pid);
string appName = p.ProcessName;
So whenever I find appName = "WINWORD", I would like to retrieve Word application object using hwnd
NOTE: I don't want to create new instance of word, just get running one.

Given a window handle, you get an automatable Word application instance using the AccessibleObjectFromWindow function from oleacc.dll.
Here is a sample program showing how to use it (add a reference to Microsoft.Office.Interop.Word.dll):
using Microsoft.Office.Interop.Word;
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
namespace WordLateBindingSample
{
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00020400-0000-0000-C000-000000000046")]
public interface IDispatch
{
}
class Program
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("Oleacc.dll")]
static extern int AccessibleObjectFromWindow(int hwnd, uint dwObjectID, byte[] riid, out IDispatch ptr);
public delegate bool EnumChildCallback(int hwnd, ref int lParam);
[DllImport("User32.dll")]
public static extern bool EnumChildWindows(int hWndParent, EnumChildCallback lpEnumFunc, ref int lParam);
[DllImport("User32.dll")]
public static extern int GetClassName(int hWnd, StringBuilder lpClassName, int nMaxCount);
public static bool EnumChildProc(int hwndChild, ref int lParam)
{
StringBuilder buf = new StringBuilder(128);
GetClassName(hwndChild, buf, 128);
if (buf.ToString() == "_WwG")
{
lParam = hwndChild;
return false;
}
return true;
}
static void Main(string[] args)
{
// Use the window class name ("OpusApp") to retrieve a handle to Word's main window.
// Alternatively you can get the window handle via the process id:
// int hwnd = (int)Process.GetProcessById(wordPid).MainWindowHandle;
//
int hwnd = (int)FindWindow("OpusApp", null);
if (hwnd != 0)
{
int hwndChild = 0;
// Search the accessible child window (it has class name "_WwG")
// as described in http://msdn.microsoft.com/en-us/library/dd317978%28VS.85%29.aspx
//
EnumChildCallback cb = new EnumChildCallback(EnumChildProc);
EnumChildWindows(hwnd, cb, ref hwndChild);
if (hwndChild != 0)
{
// We call AccessibleObjectFromWindow, passing the constant OBJID_NATIVEOM (defined in winuser.h)
// and IID_IDispatch - we want an IDispatch pointer into the native object model.
//
const uint OBJID_NATIVEOM = 0xFFFFFFF0;
Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}");
IDispatch ptr;
int hr = AccessibleObjectFromWindow(hwndChild, OBJID_NATIVEOM, IID_IDispatch.ToByteArray(), out ptr);
if (hr >= 0)
{
var wordApp = (Application)ptr.GetType().InvokeMember("Application", BindingFlags.GetProperty, null, ptr, null);
var version = wordApp.Version;
Console.WriteLine(string.Format("Word version is: {0}", version));
}
}
}
}
}
}

Related

Failing when using Pinvoke calling UpdateProcThreadAttribute for AppContainer security capabilities

I am trying to launch an appcontainer using C# and pinvoke and getting hung up setting the security capabilities into the attribute list via UpdateProcThreadAttribute().
The GetLastError() returns
87 - invalid parameter
Similar c++ code from this article (github link at the bottom https://scorpiosoftware.net/2019/01/15/fun-with-appcontainers/) works well.
Code: (pinvoke structs/enums/externs below)
public bool testAppContainer()
{
const uint SE_GROUP_ENABLED = 0x00000004;
const int ProcThreadAttributeSecurityCapabilities = 0x00020009;
STARTUPINFOEX startupInfoEx = new STARTUPINFOEX();
PROCESSINFO pInfo = new PROCESSINFO();
SECURITY_CAPABILITIES sc = new SECURITY_CAPABILITIES();
IntPtr pSidInternetClientServer = IntPtr.Zero;
startupInfoEx.StartupInfo.cb = Marshal.SizeOf(startupInfoEx);
string appContainerName = "Test.AppContainer";
try
{
//get the size, then the sid
IntPtr clientServerSid = IntPtr.Zero; uint cbSid = 0;
SecurityNative.CreateWellKnownSid(SecurityNative.WELL_KNOWN_SID_TYPE.WinCapabilityInternetClientServerSid, clientServerSid, pSidInternetClientServer, ref cbSid);
pSidInternetClientServer = Marshal.AllocCoTaskMem(Convert.ToInt32(cbSid));
if (!CreateWellKnownSid(WELL_KNOWN_SID_TYPE.WinCapabilityInternetClientServerSid, clientServerSid, pSidInternetClientServer, ref cbSid))
{
throw new ApplicationException($"Unable to create well known Client Server capability sid!");
}
//create an array of one capability
SID_AND_ATTRIBUTES[] sidAndAttributes = new SID_AND_ATTRIBUTES[1];
sidAndAttributes[0].Sid = pSidInternetClientServer;
sidAndAttributes[0].Attributes = SE_GROUP_ENABLED;
sc.Capabilities = sidAndAttributes;
sc.CapabilityCount = 1;
IntPtr appConSid = IntPtr.Zero;
int hResult = AppContainerNative.DeriveAppContainerSidFromAppContainerName(appContainerName, out appConSid);
if (hResult < 0)
{
throw new ApplicationException($"Application container {appContainerName} was not found on the machine (err code {hResult})");
}
//security capabilities for existing app container
sc.AppContainerSid = appConSid;
const int reserved = 0; var size = IntPtr.Zero; int attributeCount = 1;
bool alreadyInit = ProcessNative.InitializeProcThreadAttributeList(IntPtr.Zero, attributeCount, reserved, ref size);
if (alreadyInit || size == IntPtr.Zero)
{
throw new Exception(string.Format("Couldn't get the size of the attribute list for {0} attributes", attributeCount));
}
startupInfoEx.lpAttributeList = Marshal.AllocHGlobal(size);
if (startupInfoEx.lpAttributeList == IntPtr.Zero)
{
throw new Exception("Couldn't reserve space for a new attribute list");
}
bool initAttributeList = ProcessNative.InitializeProcThreadAttributeList(startupInfoEx.lpAttributeList, attributeCount, reserved, ref size);
if (!initAttributeList )
{
throw new Exception("Couldn't create new attribute list");
}
//also tried this (pass in unmanagedAddr instead of ref sc)
// IntPtr unmanagedAddr = Marshal.AllocHGlobal(Marshal.SizeOf(sc));
// Marshal.StructureToPtr(sc, unmanagedAddr, true);
bool success = UpdateProcThreadAttribute(startupInfoEx.lpAttributeList, reserved, (IntPtr)ProcThreadAttributeSecurityCapabilities,
ref sc, (IntPtr)Marshal.SizeOf(sc), IntPtr.Zero, IntPtr.Zero);
// Marshal.FreeHGlobal(unmanagedAddr);
// unmanagedAddr = IntPtr.Zero;
if (!success)
{
throw new Exception($"Error adding security capabilities to process launch. Error Code: {Marshal.GetLastWin32Error()}");
}
var pSec = new SECURITY_ATTRIBUTES(); pSec.nLength = Marshal.SizeOf(pSec);
var tSec = new SECURITY_ATTRIBUTES(); tSec.nLength = Marshal.SizeOf(tSec);
success = CreateProcess(null, #"c:\windows\notepad.exe", ref pSec, ref tSec, false,
(uint)ProcessNative.CreateProcessFlags.EXTENDED_STARTUPINFO_PRESENT, IntPtr.Zero, null, ref startupInfoEx, out pInfo);
if (success)
{
System.Diagnostics.Debug.WriteLine($"Created new app container process {pInfo.dwProcessId}!");
return true;
}
}
finally
{
// Free the attribute list
if (startupInfoEx.lpAttributeList != IntPtr.Zero)
{
ProcessNative.DeleteProcThreadAttributeList(startupInfoEx.lpAttributeList);
Marshal.FreeHGlobal(startupInfoEx.lpAttributeList);
}
// Close process and thread handles
if (pInfo.hProcess != IntPtr.Zero)
{
ProcessNative.CloseHandle(pInfo.hProcess);
}
if (pInfo.hThread != IntPtr.Zero)
{
ProcessNative.CloseHandle(pInfo.hThread);
}
Marshal.FreeHGlobal(startupInfoEx.lpAttributeList);
if (pSidInternetClientServer != IntPtr.Zero)
Marshal.FreeCoTaskMem(pSidInternetClientServer);
}
return true;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_CAPABILITIES
{
public IntPtr AppContainerSid;
[MarshalAs(UnmanagedType.ByValArray)]
public SID_AND_ATTRIBUTES[] Capabilities;
public uint CapabilityCount;
public uint Reserved;
}
[StructLayout(LayoutKind.Sequential)]
public struct SID_AND_ATTRIBUTES
{
public IntPtr Sid;
public UInt32 Attributes;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct PROCESSINFO
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessId;
public Int32 dwThreadId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
public enum WELL_KNOWN_SID_TYPE
{
WinNullSid,
WinWorldSid,
WinLocalSid,
WinCreatorOwnerSid,
WinCreatorGroupSid,
WinCreatorOwnerServerSid,
WinCreatorGroupServerSid,
WinNtAuthoritySid,
WinDialupSid,
WinNetworkSid,
WinBatchSid,
WinInteractiveSid,
WinServiceSid,
WinAnonymousSid,
WinProxySid,
WinEnterpriseControllersSid,
WinSelfSid,
WinAuthenticatedUserSid,
WinRestrictedCodeSid,
WinTerminalServerSid,
WinRemoteLogonIdSid,
WinLogonIdsSid,
WinLocalSystemSid,
WinLocalServiceSid,
WinNetworkServiceSid,
WinBuiltinDomainSid,
WinBuiltinAdministratorsSid,
WinBuiltinUsersSid,
WinBuiltinGuestsSid,
WinBuiltinPowerUsersSid,
WinBuiltinAccountOperatorsSid,
WinBuiltinSystemOperatorsSid,
WinBuiltinPrintOperatorsSid,
WinBuiltinBackupOperatorsSid,
WinBuiltinReplicatorSid,
WinBuiltinPreWindows2000CompatibleAccessSid,
WinBuiltinRemoteDesktopUsersSid,
WinBuiltinNetworkConfigurationOperatorsSid,
WinAccountAdministratorSid,
WinAccountGuestSid,
WinAccountKrbtgtSid,
WinAccountDomainAdminsSid,
WinAccountDomainUsersSid,
WinAccountDomainGuestsSid,
WinAccountComputersSid,
WinAccountControllersSid,
WinAccountCertAdminsSid,
WinAccountSchemaAdminsSid,
WinAccountEnterpriseAdminsSid,
WinAccountPolicyAdminsSid,
WinAccountRasAndIasServersSid,
WinNTLMAuthenticationSid,
WinDigestAuthenticationSid,
WinSChannelAuthenticationSid,
WinThisOrganizationSid,
WinOtherOrganizationSid,
WinBuiltinIncomingForestTrustBuildersSid,
WinBuiltinPerfMonitoringUsersSid,
WinBuiltinPerfLoggingUsersSid,
WinBuiltinAuthorizationAccessSid,
WinBuiltinTerminalServerLicenseServersSid,
WinBuiltinDCOMUsersSid,
WinBuiltinIUsersSid,
WinIUserSid,
WinBuiltinCryptoOperatorsSid,
WinUntrustedLabelSid,
WinLowLabelSid,
WinMediumLabelSid,
WinHighLabelSid,
WinSystemLabelSid,
WinWriteRestrictedCodeSid,
WinCreatorOwnerRightsSid,
WinCacheablePrincipalsGroupSid,
WinNonCacheablePrincipalsGroupSid,
WinEnterpriseReadonlyControllersSid,
WinAccountReadonlyControllersSid,
WinBuiltinEventLogReadersGroup,
WinNewEnterpriseReadonlyControllersSid,
WinBuiltinCertSvcDComAccessGroup,
WinMediumPlusLabelSid,
WinLocalLogonSid,
WinConsoleLogonSid,
WinThisOrganizationCertificateSid,
WinApplicationPackageAuthoritySid,
WinBuiltinAnyPackageSid,
WinCapabilityInternetClientSid,
WinCapabilityInternetClientServerSid,
WinCapabilityPrivateNetworkClientServerSid,
WinCapabilityPicturesLibrarySid,
WinCapabilityVideosLibrarySid,
WinCapabilityMusicLibrarySid,
WinCapabilityDocumentsLibrarySid,
WinCapabilitySharedUserCertificatesSid,
WinCapabilityEnterpriseAuthenticationSid,
WinCapabilityRemovableStorageSid,
WinBuiltinRDSRemoteAccessServersSid,
WinBuiltinRDSEndpointServersSid,
WinBuiltinRDSManagementServersSid,
WinUserModeDriversSid,
WinBuiltinHyperVAdminsSid,
WinAccountCloneableControllersSid,
WinBuiltinAccessControlAssistanceOperatorsSid,
WinBuiltinRemoteManagementUsersSid,
WinAuthenticationAuthorityAssertedSid,
WinAuthenticationServiceAssertedSid,
WinLocalAccountSid,
WinLocalAccountAndAdministratorSid,
WinAccountProtectedUsersSid,
WinCapabilityAppointmentsSid,
WinCapabilityContactsSid,
WinAccountDefaultSystemManagedSid,
WinBuiltinDefaultSystemManagedGroupSid,
WinBuiltinStorageReplicaAdminsSid,
WinAccountKeyAdminsSid,
WinAccountEnterpriseKeyAdminsSid,
WinAuthenticationKeyTrustSid,
WinAuthenticationKeyPropertyMFASid,
WinAuthenticationKeyPropertyAttestationSid,
WinAuthenticationFreshKeyAuthSid,
WinBuiltinDeviceOwnersSid
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType, IntPtr DomainSid, IntPtr pSid, ref uint cbSid);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment,
string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo, out PROCESSINFO lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UpdateProcThreadAttribute(IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, [MarshalAs(UnmanagedType.Struct), In] ref SECURITY_CAPABILITIES caps, IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern void DeleteProcThreadAttributeList(IntPtr lpAttributeList);
Wow, first off, this is some great work and I'm curious how you are leveraging it (CICD? Security?). As a challenge I played around with the code and noticed that your declaration for the SECURITY_CAPABILITIES structure wasn't matching with the Microsoft documentation. They list the Capabilities member as a pointer to the SID_AND_ATTRIBUTES structure, not a structure itself. So, I changed that to IntPtr making it...
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_CAPABILITIES
{
public IntPtr AppContainerSid;
public IntPtr Capabilities;
public uint CapabilityCount;
public uint Reserved;
}
I'm not sure how to marshal an array of structs to an IntPtr so for now my example below is the single capability you listed.
//create one capability
SID_AND_ATTRIBUTES sidAndAttributes = new SID_AND_ATTRIBUTES();
sidAndAttributes.Sid = pSidInternetClientServer;
sidAndAttributes.Attributes = SE_GROUP_ENABLED;
IntPtr sidAndAttributesPtr = Marshal.AllocHGlobal(Marshal.SizeOf(sidAndAttributes));
Marshal.StructureToPtr(sidAndAttributes, sidAndAttributesPtr, false);
sc.Capabilities = sidAndAttributesPtr;
sc.CapabilityCount = 1;
This allowed notepad.exe to launch with AppContainer integrity and containing the capability flag you specified.
Thank you for the reply! I did get this to work. Your suggestion did help. This does actually launch a notepad.exe in an app container with two capabilities. Here is the code for the marshal for all that want to try this. My objective is to containerize some programs that we are using to protect the servers as much as possible.
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_CAPABILITIES
{
public IntPtr AppContainerSid;
public IntPtr Capabilities;
public int CapabilityCount;
public int Reserved;
}
private void AddDefaultCapabilitiesSid(ref SECURITY_CAPABILITIES sc)
{
//get the size, then the sid
IntPtr mem = IntPtr.Zero;
IntPtr clientServerSid = IntPtr.Zero;
IntPtr privateNetworkSid = IntPtr.Zero;
IntPtr pSid = IntPtr.Zero;
uint cbSid = 0;
//get the size, then the sid
SecurityNative.CreateWellKnownSid(SecurityNative.WELL_KNOWN_SID_TYPE.WinCapabilityInternetClientServerSid, pSid, clientServerSid, ref cbSid);
clientServerSid = Marshal.AllocCoTaskMem(Convert.ToInt32(cbSid));
if (!SecurityNative.CreateWellKnownSid(SecurityNative.WELL_KNOWN_SID_TYPE.WinCapabilityInternetClientServerSid, pSid, clientServerSid, ref cbSid))
{
throw new ApplicationException($"Unable to create well known Client Server capability sid!");
}
//get the size, then the sid
SecurityNative.CreateWellKnownSid(SecurityNative.WELL_KNOWN_SID_TYPE.WinCapabilityPrivateNetworkClientServerSid, pSid, privateNetworkSid, ref cbSid);
privateNetworkSid = Marshal.AllocCoTaskMem(Convert.ToInt32(cbSid));
if (!SecurityNative.CreateWellKnownSid(SecurityNative.WELL_KNOWN_SID_TYPE.WinCapabilityPrivateNetworkClientServerSid, pSid, privateNetworkSid, ref cbSid))
{
throw new ApplicationException($"Unable to create well known Client Server capability sid!");
}
SecurityNative.SID_AND_ATTRIBUTES[] sidAndAttributes = new SecurityNative.SID_AND_ATTRIBUTES[2];
sidAndAttributes[0].Sid = clientServerSid;
sidAndAttributes[0].Attributes = SE_GROUP_ENABLED;
sidAndAttributes[1].Sid = privateNetworkSid;
sidAndAttributes[1].Attributes = SE_GROUP_ENABLED;
int arraySize = sidAndAttributes.Length;
int elemSize = Marshal.SizeOf(typeof(SecurityNative.SID_AND_ATTRIBUTES));
IntPtr result = Marshal.AllocHGlobal(elemSize * arraySize);
mem = new IntPtr(result.ToInt64());
for (int i = 0; i < arraySize; i++)
{
IntPtr ptr = new IntPtr(result.ToInt64() + elemSize * i);
Marshal.StructureToPtr(sidAndAttributes[i], ptr, false);
MemToFree.Add(ptr); //free this mem later
}
sc.Capabilities = mem;
sc.CapabilityCount = arraySize;
}

Get current active application name in Windows 10 using C#

I tried get current active application name (or process name) but in some application like Microsoft Edge is result ApplicationFrameHost. Is there way to get application name such as in Task manager?
My actual code:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
private string GetActiveProcess()
{
const int nChars = 256;
uint processId;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
GetWindowThreadProcessId(handle, out processId);
return Process.GetProcessById((int)processId).ProcessName;
}
return null;
}
This solution looks functional for me in form application:
//aktivneOknoProces
string aktivneOknoProces = GetActiveProcess();
private Process _realProcess;
private string GetActiveProcess()
{
string app = "";
var foregroundProcess = Process.GetProcessById(WinAPIFunctions.GetWindowProcessId(WinAPIFunctions.GetforegroundWindow()));
if (foregroundProcess.ProcessName == "ApplicationFrameHost")
{
foregroundProcess = GetRealProcess(foregroundProcess);
}
if(foregroundProcess != null)
{
app = foregroundProcess.ProcessName;
}
return app;
}
private Process GetRealProcess(Process foregroundProcess)
{
WinAPIFunctions.EnumChildWindows(foregroundProcess.MainWindowHandle, ChildWindowCallback, IntPtr.Zero);
return _realProcess;
}
private bool ChildWindowCallback(IntPtr hwnd, IntPtr lparam)
{
var process = Process.GetProcessById(WinAPIFunctions.GetWindowProcessId(hwnd));
if (process.ProcessName != "ApplicationFrameHost")
{
_realProcess = process;
}
return true;
}
public class WinAPIFunctions
{
//Used to get Handle for Foreground Window
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr GetForegroundWindow();
//Used to get ID of any Window
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
public delegate bool WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc callback, IntPtr lParam);
public static int GetWindowProcessId(IntPtr hwnd)
{
int pid;
GetWindowThreadProcessId(hwnd, out pid);
return pid;
}
public static IntPtr GetforegroundWindow()
{
return GetForegroundWindow();
}
}
I believe what you are looking for is this:
Process.GetCurrentProcess().ProcessName
GetCurrentProcess
ProcessName
That should give you the name of the curent process

Error 6 when injecting DLL using C#

when I try to inject a DLL with C# into a java process (Minecraft specifically) I get an error "ERROR 6", I've been googling this error but couldnt find a solution.
The program is run in administrator mode, and it isnt trying to load from an admin path.
My code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
namespace Launcher
{
internal class InjectionUtils
{
public struct CTX_PROCS
{
public Process[] procs;
}
private const int PROCESS_CREATE_THREAD = 2;
private const int PROCESS_QUERY_INFORMATION = 1024;
private const int PROCESS_VM_OPERATION = 8;
private const int PROCESS_VM_WRITE = 32;
private const int PROCESS_VM_READ = 16;
private const uint MEM_COMMIT = 4096u;
private const uint MEM_RESERVE = 8192u;
private const uint PAGE_READWRITE = 4u;
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
private static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int MessageBox(IntPtr hWnd, string text, string caption, uint option);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
private static extern uint GetLastError();
private void MBox(string text)
{
InjectionUtils.MessageBox(IntPtr.Zero, text, "", 0u);
}
public void DoInjection(string dllPath)
{
InjectionUtils.CTX_PROCS cTX_PROCS = this.FindProcessByNameAndTitle("javaw", "Minecraft 1.7");
this.InjectDynamicLib(dllPath, cTX_PROCS.procs[0].Id);
}
public InjectionUtils.CTX_PROCS FindProcessByNameAndTitle(string processName, string title)
{
InjectionUtils.CTX_PROCS result = default(InjectionUtils.CTX_PROCS);
List<Process> list = new List<Process>();
Process[] processes = Process.GetProcesses();
for (int i = 0; i < processes.Length; i++)
{
Process process = processes[i];
if (process.ProcessName.Equals(processName) && process.MainWindowTitle.Contains(title))
{
list.Add(process);
}
}
result.procs = list.ToArray();
return result;
}
public void eject()
{
}
private bool InjectDynamicLib(string dllPath, int pId)
{
bool result = false;
IntPtr intPtr = InjectionUtils.OpenProcess(1082, false, pId);
uint num = (uint)((dllPath.Length + 1) * Marshal.SizeOf(typeof(char)));
if (intPtr != IntPtr.Zero)
{
IntPtr procAddress = InjectionUtils.GetProcAddress(InjectionUtils.GetModuleHandle("kernel32.dll"), "LoadLibraryA");
IntPtr intPtr2 = InjectionUtils.VirtualAllocEx(intPtr, IntPtr.Zero, num, 12288u, 4u);
UIntPtr uIntPtr;
// Write path of dll to remote process
if (InjectionUtils.WriteProcessMemory(intPtr, intPtr2, Encoding.Default.GetBytes(dllPath), num, out uIntPtr))
{
InjectionUtils.CloseHandle(InjectionUtils.CreateRemoteThread(intPtr, IntPtr.Zero, 0u, procAddress, intPtr2, 0u, IntPtr.Zero));
result = true;
}
InjectionUtils.CloseHandle(intPtr);
}
if (InjectionUtils.GetLastError() != 0u)
{
this.MBox("ERROR " + InjectionUtils.GetLastError());
}
return result;
}
If anyone could help I would appreciate it dearly :)
Thanks in advance :D
From MSDN Error Code List:
ERROR_INVALID_HANDLE
0x6
Before you call GetLastError() you call CloseHandle() twice, once on the thread handle and on the process handle.
To find the problem just check the returns from OpenProcess() and CreateRemoteThread() and compare against the info you find in the functions documentation on MSDN.
For a simple no frills C# injector, this is the code I like to use which includes some error checking and uses the managed Process::Dispose() method instead of calling the native CloseHandle() at least on the process handle:
public static bool InjectDLL(string dllpath, string procname)
{
Process[] procs = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(procname));
if (procs.Length == 0)
{
return false;
}
Process proc = procs[0];
if (proc.Handle != IntPtr.Zero)
{
IntPtr loc = VirtualAllocEx(proc.Handle, IntPtr.Zero, MAX_PATH, AllocationType.Commit | AllocationType.Reserve,
MemoryProtection.ReadWrite);
if (loc.Equals(0))
{
return false;
}
IntPtr bytesRead = IntPtr.Zero;
bool result = WriteProcessMemory(proc.Handle, loc, dllpath.ToCharArray(), dllpath.Length, out bytesRead);
if (!result || bytesRead.Equals(0))
{
return false;
}
IntPtr loadlibAddy = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
IntPtr hThread = CreateRemoteThread(proc.Handle, IntPtr.Zero, 0, loadlibAddy, loc, 0, out _);
if (!hThread.Equals(0))
{
CloseHandle(hThread);
}
else return false;
}
else return false;
//this will CloseHandle automatically using the managed method
proc.Dispose();
return true;
}
Make sure to run as admin and pinvoke any missing definitions.

Cant create HTML document from Hwnd using C#

We have an existing piece of software that uses shellwidnows to access an internet explorer page and modify data on a form. However, we are porting it to Citrix seamless application and shell windows does not work there.
I have looked around on the internet and found a way to create a HtmlDocument from an existing IE window.
However, I am having a problem when trying to run "SendMessageTimeout". It runs without error but the result returned is 0 when it should be a non-zero amount. And thus, I can not go to the next phase of creating the HTML Document.
The line causing the problem is:
IntPtr result = SendMessageTimeout(htmlWindow, lMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes);
Here is the full code. Iam using VS 2008 due to corporate conventions. I am new to C# so some conventions and styling may be incorrect. Thanks for any help.
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using mshtml;
using System.Diagnostics;
public delegate bool IECallBack(int hwnd, int lParam);
public delegate bool IEChildCallBack(int hWndParent, int lpEnumFunc, int lParam);
namespace GetIEWindows
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("Oleacc.Dll")]
public static extern int ObjectFromLresult(UIntPtr lResult, UUID _riid, int wParam, mshtml.HTMLDocument _ppvObject);
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
private static extern int FindWindowEx(int parentWindow, int childWindow, string _ClassName, string _WindowName);
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.Dll")]
public static extern int EnumWindows(IECallBack x, long y);
[DllImport("user32.Dll")]
public static extern int EnumChildWindows(int parent, IECallBack x, long y);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
[DllImport("User32.Dll")]
public static extern void GetWindowText(IntPtr h, StringBuilder s, long nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("User32.Dll")]
public static extern void GetClassName(int h, StringBuilder s, int
nMaxCount);
[DllImport("User32.Dll")]
public static extern uint RegisterWindowMessage(string lpString);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out UIntPtr result);
enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
[Flags]
public enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0,
SMTO_BLOCK = 0x1,
SMTO_ABORTIFHUNG = 0x2,
SMTO_NOTIMEOUTIFNOTHUNG = 0x8
}
public const int SMTO_ABORTIFHUNG = 0x2;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct UUID
{
public long Data1;
public int Data2;
public int Data3;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] Data4;
}
public static mshtml.HTMLDocument GetHTMLContent(IntPtr htmlWindow)
{
HTMLDocument htmlDocument = new mshtml.HTMLDocument();
HTMLDocument thedoc = new mshtml.HTMLDocument();
IHTMLDocument htmlDoc = null;
Guid guid = new Guid("626FC520-A41E-11cf-A731-00A0C9082637");
int foundWindow = htmlWindow.ToInt32();
string htmlContent = "";
UUID IID_IHTMLDocument = new UUID();
UIntPtr lRes;
uint lMsg = 0;
int hr = 0;
if (foundWindow != 0)
{
// Register the message
lMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
//lMsg = RegisterWindowMessage("WM_GETTEXT");
// Get the object
IntPtr result = SendMessageTimeout(htmlWindow, lMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes);
if (result.ToInt32() != 0)
{
if (lRes != UIntPtr.Zero)
{
// Initialize the interface ID
IID_IHTMLDocument.Data1 = 0x626FC520;
IID_IHTMLDocument.Data2 = 0xA41E;
IID_IHTMLDocument.Data3 = 0x11CF;
IID_IHTMLDocument.Data4 = new byte[8];
IID_IHTMLDocument.Data4[0] = 0xA7;
IID_IHTMLDocument.Data4[1] = 0x31;
IID_IHTMLDocument.Data4[2] = 0x0;
IID_IHTMLDocument.Data4[3] = 0xA0;
IID_IHTMLDocument.Data4[4] = 0xC9;
IID_IHTMLDocument.Data4[5] = 0x8;
IID_IHTMLDocument.Data4[6] = 0x26;
IID_IHTMLDocument.Data4[7] = 0x37;
// Get the object from lRes
try
{
hr = ObjectFromLresult(lRes, IID_IHTMLDocument, 0, thedoc);
//htmlDoc = (mshtml.IHTMLDocument)ObjectFromLresult(, IID_IHTMLDocument, 0, htmlDoc);
}
catch (Exception e)
{
MessageBox.Show("Did not get IHTMLDocument: " + e.Message);
}
}
}
}
return thedoc;
}
public static void getHWnd()
{
string currentTitle;
string windowName = null;
string windowClass = "#32770";
HTMLDocument pageToBeEdited;
IntPtr hWnd = FindWindow(windowClass, windowName);
while (hWnd.ToInt32() != 0) {
int length = GetWindowTextLength(hWnd);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(hWnd, sb, sb.Capacity);
currentTitle = sb.ToString();
if (currentTitle.Contains("Internet Explorer")) {
pageToBeEdited = GetHTMLContent(hWnd);
return;
}
hWnd = GetWindow(hWnd, GetWindow_Cmd.GW_HWNDNEXT);
}
return;
}
private void btnRun_Click(object sender, EventArgs e)
{
getHWnd();
}
}
}
For anybody who is interested, the problem was resolved by using a different way of getHWnd:
public static IntPtr getHWnd(string title)
{
IntPtr hWnd = FindWindow(null, title);
BringWindowToTop(hWnd);
SetActiveWindow(hWnd);
SetForegroundWindow(hWnd);
Thread.Sleep(500);
foreach (Process process in Process.GetProcessesByName("IExplore"))
{
if (process.MainWindowTitle.ToLower().Contains(title.ToLower()))
{
hWnd = process.MainWindowHandle;
break;
}
}
EnumProc proc = new EnumProc(EnumWindows);
EnumChildWindows(hWnd, proc, ref hWnd);
return hWnd;
}
public HTMLDocument GetHTMLDocument(IntPtr hWnd)
{
HTMLDocument document = null;
int iMsg = 0;
int iRes = 0;
iMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
if (iMsg != 0)
{
SendMessageTimeout(hWnd, iMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, out iRes);
if (iRes != 0)
{
int hr = ObjectFromLresult(iRes, ref IID_IHTMLDocument, 0, ref document);
}
}
return document;
}
private static int EnumWindows(IntPtr hWnd, ref IntPtr lParam)
{
int iRet = 1;
StringBuilder classname = new StringBuilder(128);
GetClassName(hWnd, classname, classname.Capacity);
if ((bool)(string.Compare(classname.ToString(), "Internet Explorer_Server") == 0))
{
lParam = hWnd;
iRet = 0;
}
return iRet;
}
Here is how you can get HTMLDocument using Hwnd :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using mshtml;
namespace HookBrowser
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
#region API CALLS
[DllImport("user32.dll", EntryPoint = "GetClassNameA")]
public static extern int GetClassName(IntPtr hwnd, StringBuilder lpClassName, int nMaxCount);
/*delegate to handle EnumChildWindows*/
public delegate int EnumProc(IntPtr hWnd, ref IntPtr lParam);
[DllImport("user32.dll")]
public static extern int EnumChildWindows(IntPtr hWndParent, EnumProc lpEnumFunc, ref IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "RegisterWindowMessageA")]
public static extern int RegisterWindowMessage(string lpString);
[DllImport("user32.dll", EntryPoint = "SendMessageTimeoutA")]
public static extern int SendMessageTimeout(IntPtr hwnd, int msg, int wParam, int lParam, int fuFlags, int uTimeout, out int lpdwResult);
[DllImport("OLEACC.dll")]
public static extern int ObjectFromLresult(int lResult, ref Guid riid, int wParam, ref IHTMLDocument2 ppvObject);
public const int SMTO_ABORTIFHUNG = 0x2;
public Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637");
#endregion
public IHTMLDocument2 document;
private void button1_Click(object sender, EventArgs e)
{
document = documentFromDOM();
/// check that we have hold of the IHTMLDocument2...
if (!(bool)(document == null))
{
this.Text = document.url;
}
}
private IHTMLDocument2 documentFromDOM()
{
Process[] processes = Process.GetProcessesByName("iexplore");
if (processes.Length > 0)
{
IntPtr hWnd = processes[0].MainWindowHandle;
int lngMsg = 0;
int lRes;
EnumProc proc = new EnumProc(EnumWindows);
EnumChildWindows(hWnd, proc, ref hWnd);
if (!hWnd.Equals(IntPtr.Zero))
{
lngMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
if (lngMsg != 0)
{
SendMessageTimeout(hWnd, lngMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, out lRes);
if (!(bool)(lRes == 0))
{
int hr = ObjectFromLresult(lRes, ref IID_IHTMLDocument, 0, ref document);
if ((bool)(document == null))
{
MessageBox.Show("NoLDocument Found!", "Warning");
}
}
}
}
}
return document;
}
private int EnumWindows(IntPtr hWnd, ref IntPtr lParam)
{
int retVal = 1;
StringBuilder classname = new StringBuilder(128);
GetClassName(hWnd, classname, classname.Capacity);
/// check if the instance we have found is Internet Explorer_Server
if ((bool)(string.Compare(classname.ToString(), "Internet Explorer_Server") == 0))
{
lParam = hWnd;
retVal = 0;
}
return retVal;
}
}
}
Please refer to this link for more info :
http://www.xtremevbtalk.com/code-library/295336-internet-explorer-dom-using-objectfromlresult.html

Do Windows API EnumWindows and EnumChildWindows functions behave differently in Windows XP and 7

I am using 2 Windows API exported functions from c#.NET 4.0.
private const string WINDOW_EXCEL7 = "XLMAIN";
private const string CHILDWINDOW_XLMAIN = "EXCEL7";
I am searching for windows titles of Excel main windows' child windows (Excel has an MDI window of class XLMAIN containing 0, 1 or more child windows with EXCEL7 window class).
The goal is to find if a an excel workbook is being opened in any instances of Excel application. I did it by finding all XLMAIN IntPtr (pointers) and traversing children until I get a IntPtr with EXCEL7 window class at which point I can read child windows title and determine if a file is opened.
Basically this works on Windows XP, but not on Windows 7. I didn't try in Windows Vista.
What has changed? Can someone debug the issue since I don't have Windows 7.
Thanks
Rad
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace ExcelChildWindowsTitle
{
public static void Main(string[] args)
{
//XLMAIN/EXCELDESK/EXCEL7 as seen by Spy++ VS 2010 utility
//IntPtr hWnd = WndSearcher.SearchForWindow("XLMAIN", "EXCEL7", "icui-20110331.xls", ref workbookTitle);
//bool excelProofFound = WindowTitleSearcher.SearchForWindow("XLMAIN", "EXCEL7", "testfileopenedinEXCEL.xls", ref workbookTitle);
bool excelProofFound = WindowTitleSearcher.SearchForWindow("icui-20110331.xls");
if (excelProofFound)
Console.Write(":)))))))) Proof File opened in an Excel process;");
else
{
Console.Write(":|Proof File not found");
}
}
public static class WindowTitleSearcher
{
private const string WINDOW_EXCEL7 = "XLMAIN";
private const string CHILDWINDOW_XLMAIN = "EXCEL7";
public static bool SearchForWindow(string title)
{
SearchData sd = new SearchData { Wndclass = WINDOW_EXCEL7, ChildWndclass = CHILDWINDOW_XLMAIN, ChildTitle = title, WorkbookTitle = String.Empty};
EnumWindows(new EnumWindowsProc(EnumProc), ref sd);
return (int)sd.hWnd > 0;
}
private static bool EnumProc(IntPtr hWnd, ref SearchData data)
{
const bool directOnly = false;
// Check classname and title
// This is different from FindWindow() in that the code below allows partial matches
StringBuilder sb1 = new StringBuilder(1024);
GetClassName(hWnd, sb1, sb1.Capacity);
Debug.WriteLine(sb1.ToString());
if (sb1.ToString().StartsWith(data.Wndclass))
{
RecursiveEnumChildWindows(hWnd, directOnly, ref data);
if ((int)data.hWnd > 0)
{
// Found the wnd, halt enumeration
return false;
}
}
return true;
}
private static void RecursiveEnumChildWindows(IntPtr parentHwnd, bool directOnly, ref SearchData data)
{
EnumChildWindows(parentHwnd, delegate(IntPtr hwnd, ref SearchData data1)
{
bool add = true;
if (directOnly)
{
add = GetParent(hwnd) == parentHwnd;
}
StringBuilder sb1 = new StringBuilder(1024);
GetClassName(hwnd, sb1, sb1.Capacity);
Debug.WriteLine("Child:" + sb1.ToString());
if (add)
{
if (sb1.ToString().StartsWith(data1.ChildWndclass))
{
sb1 = new StringBuilder(1024);
//Window Caption
GetWindowText(hwnd, sb1, sb1.Capacity);
if (sb1.ToString().Contains(data1.ChildTitle))
{
data1.hWnd = hwnd;
data1.WorkbookTitle = sb1.ToString();
return false; // Found the wnd, halt enumeration
}
}
}
return true;
}, ref data);
}
private struct SearchData
{
// You can put any vars in here...
public string Wndclass;
public string ChildWndclass;
public string ChildTitle;
public IntPtr hWnd;
public string WorkbookTitle;
}
# region Windows API declarations
private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData data);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, ref SearchData data);
//private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, [MarshalAsAttribute(UnmanagedType.Struct)] ref SearchData data);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, ref SearchData data);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
private static extern IntPtr GetParent(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
# endregion
}
}
Why use hacks like this when MS Office has documented automation support?
You can use .NET, the older COM/OLE automation interfaces or the super old DDE interface.
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace ExcelChildWindowsTitle
{
class Program
{
static void Main(string[] args)
{
//XLMAIN/EXCELDESK/EXCEL7 as seen by Spy++ VS 2010 utility
//IntPtr hWnd = WndSearcher.SearchForWindow("XLMAIN", "EXCEL7", "icui-20110331.xls", ref workbookTitle);
//bool excelProofFound = WindowTitleSearcher.SearchForWindow("XLMAIN", "EXCEL7", "testfileopenedinEXCEL.xls", ref workbookTitle);
bool excelProofFound = WindowTitleSearcher.SearchForWindow("file name here");
if (excelProofFound)
Console.Write(":)))))))) Proof File opened in an Excel process;");
else
{
Console.Write(":|Proof File not found");
}
}
public static class WindowTitleSearcher
{
private const string WINDOW_EXCEL7 = "XLMAIN";
private const string CHILDWINDOW_XLMAIN = "EXCEL7";
public static bool SearchForWindow(string title)
{
SearchData sd = new SearchData { Wndclass = WINDOW_EXCEL7, ChildWndclass = CHILDWINDOW_XLMAIN, ChildTitle = title, WorkbookTitle = String.Empty };
EnumWindows(new EnumWindowsProc(EnumProc), ref sd);
return (int)sd.hWnd > 0;
}
private static bool EnumProc(IntPtr hWnd, ref SearchData data)
{
const bool directOnly = false;
// Check classname and title
// This is different from FindWindow() in that the code below allows partial matches
StringBuilder sb1 = new StringBuilder(1024);
GetClassName(hWnd, sb1, sb1.Capacity);
Debug.WriteLine(sb1.ToString());
if (sb1.ToString().StartsWith(data.Wndclass))
{
RecursiveEnumChildWindows(hWnd, directOnly, ref data);
if ((int)data.hWnd > 0)
{
// Found the wnd, halt enumeration
return false;
}
}
return true;
}
private static void RecursiveEnumChildWindows(IntPtr parentHwnd, bool directOnly, ref SearchData data)
{
EnumChildWindows(parentHwnd, delegate(IntPtr hwnd, ref SearchData data1)
{
bool add = true;
if (directOnly)
{
add = GetParent(hwnd) == parentHwnd;
}
StringBuilder sb1 = new StringBuilder(1024);
GetClassName(hwnd, sb1, sb1.Capacity);
Debug.WriteLine("Child:" + sb1.ToString());
if (add)
{
if (sb1.ToString().StartsWith(data1.ChildWndclass))
{
sb1 = new StringBuilder(1024);
//Window Caption
GetWindowText(hwnd, sb1, sb1.Capacity);
if (sb1.ToString().Contains(data1.ChildTitle))
{
data1.hWnd = hwnd;
data1.WorkbookTitle = sb1.ToString();
return false; // Found the wnd, halt enumeration
}
}
}
return true;
}, ref data);
}
private struct SearchData
{
// You can put any vars in here...
public string Wndclass;
public string ChildWndclass;
public string ChildTitle;
public IntPtr hWnd;
public string WorkbookTitle;
}
# region Windows API declarations
private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData data);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, ref SearchData data);
//private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, [MarshalAsAttribute(UnmanagedType.Struct)] ref SearchData data);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, ref SearchData data);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
private static extern IntPtr GetParent(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
# endregion
}
}
}
/////////////////////Work good on Windows 10 64 bit

Categories

Resources