How to use Win32Api in C# Windows Service App - c#

I'm creating a windows service app in visual studio and I want to get the currently active window title.
below is the code I have tried but the function GetForegroundWindow() returns 0 every time.
Is it okay to use win32api in windows services?
public partial class My_Service: ServiceBase
{
Timer timer = new Timer();
[DllImport("User32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("User32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
public My_Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
WriteToFile("Service is started at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 10000; //number in milisecinds
timer.Enabled = true;
}
protected override void OnStop()
{
WriteToFile("Service is stopped at " + DateTime.Now);
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
string title = GetActivewindow();
WriteToFile("Service is recall at " + title + DateTime.Now);
}
public void WriteToFile(string Message)
{
....
}
public string GetActivewindow()
{
const int nChars = 256;
StringBuilder buff = new StringBuilder(nChars);
string title = "- ";
IntPtr handle;
handle = GetForegroundWindow();
if( GetWindowText(handle,buff,nChars) > 0)
{
title = buff.ToString();
}
return title;
}
}

As comments, and also according to the document: About Window Stations and Desktops - Window Station and Desktop Creation.
Your service may be running under Service-0x0-3e7$\default, but the foreground window you want to retrieve is in the default desktop of the interactive window station (Winsta0\default)
The interactive window station is the only window station that can
display a user interface or receive user input. It is assigned to the
logon session of the interactive user, and contains the keyboard,
mouse, and display device. It is always named "WinSta0". All other
window stations are noninteractive, which means they cannot display a
user interface or receive user input.
That means you cannot use GetForegroundWindow directly from the service. You could create a child process in Winsta0\default and redirect its output. Then call GetForegroundWindow in the child process and output.
Sample(removed error checking):
Child:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
[DllImport("User32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("User32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
static void Main(string[] args)
{
const int nChars = 256;
StringBuilder buff = new StringBuilder(nChars);
string title = "- ";
IntPtr handle;
handle = GetForegroundWindow();
if (GetWindowText(handle, buff, nChars) > 0)
{
title = buff.ToString();
}
Console.WriteLine(title);
return;
}
}
}
Service:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics.Tracing;
namespace WindowsService3
{
public partial class MyNewService : ServiceBase
{
[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, CharSet = CharSet.Unicode)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessId;
public Int32 dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
IntPtr lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CreatePipe(
ref IntPtr hReadPipe,
ref IntPtr hWritePipe,
ref SECURITY_ATTRIBUTES lpPipeAttributes,
uint nSize);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool ReadFile(
IntPtr hFile,
byte[] lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool WTSQueryUserToken(UInt32 SessionId, out IntPtr hToken);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint WaitForSingleObject(IntPtr hProcess, uint dwMilliseconds);
public MyNewService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
System.Diagnostics.Debugger.Launch();
using (StreamWriter sw = File.CreateText("Path\\Log.txt"))
{
IntPtr read = new IntPtr();
IntPtr write = new IntPtr();
IntPtr read2 = new IntPtr();
IntPtr write2 = new IntPtr();
SECURITY_ATTRIBUTES saAttr = new SECURITY_ATTRIBUTES();
saAttr.nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES));
saAttr.bInheritHandle = 1;
saAttr.lpSecurityDescriptor = IntPtr.Zero;
CreatePipe(ref read, ref write, ref saAttr, 0);
CreatePipe(ref read2, ref write2, ref saAttr, 0);
uint CREATE_NO_WINDOW = 0x08000000;
int STARTF_USESTDHANDLES = 0x00000100;
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(typeof(STARTUPINFO));
si.hStdOutput = write;
si.hStdError = write;
si.hStdInput = read2;
si.lpDesktop = "Winsta0\\default";
si.dwFlags = STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi;
IntPtr hToken;
bool err = WTSQueryUserToken(WTSGetActiveConsoleSessionId(), out hToken);
string path = "Path\\ConsoleApp1.exe";
if (CreateProcessAsUser(hToken, path, null, IntPtr.Zero, IntPtr.Zero, true, CREATE_NO_WINDOW, IntPtr.Zero, IntPtr.Zero, ref si, out pi))
{
uint ret = WaitForSingleObject(pi.hProcess, 2000); //wait for the child process exit.
if (ret == 0)
{
byte[] title = new byte[200];
uint reads = 0;
CloseHandle(write);
err = ReadFile(read, title, 200, out reads, IntPtr.Zero);
string result = System.Text.Encoding.UTF8.GetString(title).Replace("\0","").Replace("\r", "").Replace("\n", "");
sw.WriteLine(result);
}
}
CloseHandle(read2);
CloseHandle(write2);
CloseHandle(read);
}
}
protected override void OnStop()
{
}
}
}

Related

How to PInvoke UpdateProcThreadAttribute with PROC_THREAD_ATTRIBUTE_PREFERRED_NODE attribute

I'm trying to PInvoke UpdateProcThreadAttribute() with PROC_THREAD_ATTRIBUTE_PREFERRED_NODE attribute, so that I could launch a process on a specific NUMA node. I'm working on Windows Server 2019.
I found this question that helped me to PInvoke UpdateProcThreadAttribute():
How to call CreateProcess() with STARTUPINFOEX from C# and re-parent the child
When I'm using PROC_THREAD_ATTRIBUTE_PARENT_PROCESS everything works fine, but when trying to set PROC_THREAD_ATTRIBUTE_PREFERRED_NODE as an attribute I keep getting error 24: ERROR_BAD_LENGTH (The program issued a command but the command length is incorrect).
public class ProcessCreator
{
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
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 PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UpdateProcThreadAttribute(
IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue,
IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InitializeProcThreadAttributeList(
IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteProcThreadAttributeList(IntPtr lpAttributeList);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
static extern uint GetLastError();
public static bool CreateProcess(string appName, string args, string dir, out PROCESS_INFORMATION pInfo, ILogger logger)
{
const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
const int PROC_THREAD_ATTRIBUTE_PREFERRED_NODE = 0x00020004;
pInfo = new PROCESS_INFORMATION();
var sInfoEx = new STARTUPINFOEX();
sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx);
IntPtr lpValue = IntPtr.Zero;
try
{
var lpSize = IntPtr.Zero;
var success = InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize);
if (success || lpSize == IntPtr.Zero)
{
return false;
}
sInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize);
success = InitializeProcThreadAttributeList(sInfoEx.lpAttributeList, 1, 0, ref lpSize);
if (!success)
{
return false;
}
// This value should persist until the attribute list is destroyed using the DeleteProcThreadAttributeList function
lpValue = Marshal.AllocHGlobal(IntPtr.Size);
// Setting preferred NUMA to be 0, for example.
Marshal.WriteIntPtr(lpValue, (IntPtr)0);
success = UpdateProcThreadAttribute(
sInfoEx.lpAttributeList,
0,
(IntPtr)PROC_THREAD_ATTRIBUTE_PREFERRED_NODE,
lpValue,
(IntPtr)IntPtr.Size,
IntPtr.Zero,
IntPtr.Zero);
if (!success)
{
logger.Info($"Error: {GetLastError()}");
return false;
}
var pSec = new SECURITY_ATTRIBUTES();
var tSec = new SECURITY_ATTRIBUTES();
pSec.nLength = Marshal.SizeOf(pSec);
tSec.nLength = Marshal.SizeOf(tSec);
return CreateProcess(appName, args, ref pSec, ref tSec, false, 0, IntPtr.Zero, dir, ref sInfoEx, out pInfo);
}
finally
{
// Free the attribute list
if (sInfoEx.lpAttributeList != IntPtr.Zero)
{
DeleteProcThreadAttributeList(sInfoEx.lpAttributeList);
Marshal.FreeHGlobal(sInfoEx.lpAttributeList);
}
Marshal.FreeHGlobal(lpValue);
// Close process and thread handles
if (pInfo.hProcess != IntPtr.Zero)
{
CloseHandle(pInfo.hProcess);
}
if (pInfo.hThread != IntPtr.Zero)
{
CloseHandle(pInfo.hThread);
}
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
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 PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
}
Any help would be much appreciated.

Getting all processes in desktop

I have created a new desktop using CreateDesktop and would like to be able to enumerate all processes within that desktop.
I have tried this:
foreach (Process process in Process.GetProcesses())
{
foreach (ProcessThread processThread in process.Threads)
{
IntPtr hDesk = GetThreadDesktop((uint)processThread.Id);
if (hDesk == desk)
{
// Do something
}
}
}
However, I get Access is denied exception. I can also use
EnumDesktopWindows
However, this doesn't work for command line applications. (I am trying to prevent keyloggers)
Is there any way to get all processes within a desktop?
Thanks
I spent the last hour playing with this and I have it working fine from a console window. The code is messy, but you should be able to make your way through it:
class Program
{
private static class Win32Native
{
[Flags]
public enum CreateDesktopFlags : uint
{
DF_NONE = 0,
DF_ALLOWOTHERACCOUNTHOOK = 1
}
[Flags]
public enum CreateWindowAccessMask : uint
{
DESKTOP_READOBJECTS = 0x0001,
DESKTOP_CREATEWINDOW = 0x0002,
DESKTOP_CREATEMENU = 0x0004,
DESKTOP_HOOKCONTROL = 0x0008,
DESKTOP_JOURNALRECORD = 0x0010,
DESKTOP_JOURNALPLAYBACK = 0x0020,
DESKTOP_ENUMERATE = 0x0040,
DESKTOP_WRITEOBJECTS = 0x0080,
DESKTOP_SWITCHDESKTOP = 0x0100,
DESKTOP_ALL_ACCESS = 0x01FF
}
[Flags]
public enum CreateProcessFlags : uint
{
CREATE_NEW_CONSOLE = 0x00000010,
CREATE_NEW_PROCESS_GROUP = 0x00000200
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[DllImport("user32.dll")]
public static extern IntPtr GetProcessWindowStation();
[return: MarshalAs(UnmanagedType.Bool)]
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[return: MarshalAs(UnmanagedType.Bool)]
public delegate bool EnumDesktopProc([MarshalAs(UnmanagedType.LPWStr)] string lpszDesktop, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc lpfn, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "GetWindowTextW", CharSet = CharSet.Unicode)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "GetClassNameW", CharSet = CharSet.Unicode)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateDesktopW", CharSet = CharSet.Unicode)]
public static extern IntPtr CreateDesktop(
string lpszDesktop, IntPtr lpszDevice,
IntPtr pDevMode, CreateDesktopFlags dwFlags,
CreateWindowAccessMask dwDesiredAccess,
IntPtr lpsa);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "EnumDesktopsW", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumDesktops(IntPtr hwinsta, EnumDesktopProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseDesktop(IntPtr hDesktop);
[DllImport("kernel32.dll", SetLastError = true, EntryPoint = "CreateProcessW", CharSet = CharSet.Unicode)]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
CreateProcessFlags dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll")]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);
}
static int Main(string[] args)
{
StringBuilder sbWndText = new StringBuilder(512),
sbWndClass = new StringBuilder(512);
Console.WriteLine("Trying current desktop:");
if(!Win32Native.EnumDesktopWindows(IntPtr.Zero, (hWnd, lParam) =>
{
Win32Native.GetWindowText(hWnd, sbWndText, sbWndText.Capacity);
Win32Native.GetClassName(hWnd, sbWndClass, sbWndClass.Capacity);
Console.WriteLine($"Found Window: {hWnd} with title \"{sbWndText}\" and class name \"{sbWndClass}\"");
return true;
}, IntPtr.Zero))
{
var error = Marshal.GetLastWin32Error();
Console.WriteLine($"EnumDesktopWindows for current desktop failed with error {error}");
}
Console.WriteLine("Current desktops: ");
Win32Native.EnumDesktops(Win32Native.GetProcessWindowStation(), (desktopName, lParam) =>
{
Console.WriteLine($"Found desktop: {desktopName}");
return true;
}, IntPtr.Zero);
Console.WriteLine("Trying new desktop:");
const string DesktopName = "ANDY DESKTOP NEATO 2";
var hDesktop = Win32Native.CreateDesktop(
DesktopName, IntPtr.Zero, IntPtr.Zero,
Win32Native.CreateDesktopFlags.DF_ALLOWOTHERACCOUNTHOOK,
Win32Native.CreateWindowAccessMask.DESKTOP_ALL_ACCESS,
IntPtr.Zero);
if(hDesktop != IntPtr.Zero)
{
Win32Native.EnumDesktops(Win32Native.GetProcessWindowStation(), (desktopName, lParam) =>
{
Console.WriteLine($"Found desktop: {desktopName}");
return true;
}, IntPtr.Zero);
var si = new Win32Native.STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = DesktopName;
var pi = new Win32Native.PROCESS_INFORMATION();
if(!Win32Native.CreateProcess(
null, "cmd.exe", IntPtr.Zero, IntPtr.Zero, false,
Win32Native.CreateProcessFlags.CREATE_NEW_CONSOLE |
Win32Native.CreateProcessFlags.CREATE_NEW_PROCESS_GROUP,
IntPtr.Zero, null, ref si, out pi))
{
var error = Marshal.GetLastWin32Error();
Console.WriteLine($"Unable to create process on new desktop: {error}");
}
Console.WriteLine("WAITING 2 SECONDS FOR PROCESS TO START...");
Thread.Sleep(2000); // breath so the process starts
if (!Win32Native.EnumDesktopWindows(hDesktop, (hWnd, lParam) =>
{
Win32Native.GetWindowText(hWnd, sbWndText, sbWndText.Capacity);
Win32Native.GetClassName(hWnd, sbWndClass, sbWndClass.Capacity);
Console.WriteLine($"Found Window: {hWnd} with title \"{sbWndText}\" and class name \"{sbWndClass}\"");
return true;
}, IntPtr.Zero))
{
var error = Marshal.GetLastWin32Error();
Console.WriteLine($"EnumDesktopWindows for new desktop failed with error {error}");
}
// IMPORTANT: close the processes you start, otherwise you desktop won't self-destruct.
Win32Native.TerminateProcess(pi.hProcess, 42);
Win32Native.CloseHandle(pi.hProcess);
Win32Native.CloseHandle(pi.hThread);
Win32Native.CloseDesktop(hDesktop);
}
else
{
Console.WriteLine($"Unable to create desktop: {Marshal.GetLastWin32Error()}");
}
return 0;
}
}
So the issue I think you were having with EnumDesktopWindows is that when you called CreateDesktop, you didn't ask for sufficient privileges. I set all privileges on (value of 0x1FF) and then EnumDesktopWindows worked for me.
Keep in mind if you call EnumDesktopWindows and there are no windows to enumerate, it will return false with a value of 0 when you call GetLastError.
So what I did to prove that it actually is working is I created a process (cmd.exe) in the new desktop, then called EnumDesktopWindows.
Also keep in mind if you don't destroy all the processes in your new desktop, the desktop will not "self-destruct" and it will be alive until all the processes are destroyed or you logoff/reboot.
I also ran this as a normal user. I didn't need to elevate to administrator to make this work.
However, this doesn't work for command line applications. (I am trying
to prevent keyloggers)
Assume that you want to prevent from hooking keyboard input of the desktop.
Since hook need a message loop to receive keyboard messages, which requires to create a window. So restrict other users to create window application associate to your desktop can prevent them from logging keyboard inputs.
If you want to check the desktop name of a given process to see if it is same with your desktop's name (applied for window application) you can follow these steps:
Call OpenProcess() to get a HANDLE from the target process ID.
Call NtQueryInformationProcess() to retrieve the address of the process's PEB structure.
Call ReadProcessMemory() to read the PEB. It's ProcessParams.DesktopName field contains the name of the workstation/desktop currently associated with the process (there are many more fields available in the PEB.ProcessParams then what MSDN shows).
Refer to "How to get window station for a given process?"

Why i can't capture a process window and display it in a pictureBox?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Drawing.Imaging;
namespace CaptureProcessWindow
{
public partial class Form1 : Form
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
public static extern long SetWindowPos(IntPtr hwnd, IntPtr hWndInsertAfter, long x, long y, long cx, long cy,
long wFlags);
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
[DllImport("kernel32.dll")]
static extern bool CreateProcess(string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
public const int WM_SYSCOMMAND = 0x112;
public const int SC_MINIMIZE = 0xf020;
public const int SC_MAXIMIZE = 0xf030;
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
public struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
public struct SECURITY_ATTRIBUTES
{
public int length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
public Form1()
{
InitializeComponent();
}
public void CaptureApplication(string _title)
{
string _wndcls = "ConsoleWindowClass";
STARTUPINFO si = new STARTUPINFO();
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
CreateProcess(_title, null, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref si, out pi);
IntPtr _wndConsole = IntPtr.Zero;
for (int i = 0; i < 30; i++)
{
_wndConsole = FindWindow(_wndcls, _title);
if (_wndConsole == IntPtr.Zero)
{
System.Threading.Thread.Sleep(10);
continue;
}
break;
}
IntPtr value = SetParent(_wndConsole, this.pictureBox1.Handle);
int style = GetWindowLong(_wndConsole, -16);
style &= -12582913;
SetWindowLong(_wndConsole, -16, style);
SendMessage(_wndConsole, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
Process[] processlist = Process.GetProcesses();
List<string> names = new List<string>();
foreach (Process process in processlist)
{
if (process.MainWindowTitle.Contains("Notepad"))
{
CaptureApplication(process.MainWindowTitle);
break;
}
else
{
string t = "";
}
}
}
}
}
When using a break point it stop on the line:
CaptureApplication(process.MainWindowTitle);
But it's not showing the window in the pictureBox.
I didn't check all the processes in the list but i checked like 20 and they are all empty in the MainWindowTitle ""
I checked now the notepad it's in the list in index 112 and it does have mainwindowtitle: MainWindowTitle = "New Text Document (11) - Notepad" but still it's not showing anything in the picturebox.
Maybe there is a way to capture the window of the process/s using the id number ?

C#: OpenFileDialog to find path and extesion of file name

I am trying to find the File extension, path and file size using user32 or kernal32 in c#.
My scenario : While uploading some files in web (email,application etc..) I need to fetch the filename, its path and size of the file (size of the file is optional). I am using OpenFileDialog handle and I can able to retrieve the filename of the selected file to be uploaded. Could you please help me to retrieve the path and size of the file using the same. I can able to find the handle for OpenFileDialog how to proceed to retrieve information using those handle
please find my below code (some of the dll reference will not be useful):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using System.Security.Principal;
using `enter code here`System.Diagnostics;
namespace Opendailoghandle
{
class Program
{
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, int wParam, StringBuilder lParam);
// [DllImport("user32.dll", CharSet = CharSet.Auto)]
// public static extern int SendMessage(int hWnd, int msg, int wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetDlgItem(IntPtr hwnd, int childID);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int SendMessage(HandleRef hwnd, int wMsg, int wParam, String s);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern String SendMessage(HandleRef hwnd, uint WM_GETTEXT);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(int hWnd, int msg, int wParam, IntPtr lParam);
// to get file size import
[DllImport("kernel32.dll")]
static extern bool GetFileSizeEx(IntPtr hFile, out long lpFileSize);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateFile(
[MarshalAs(UnmanagedType.LPTStr)] string filename,
[MarshalAs(UnmanagedType.U4)] FileAccess access,
[MarshalAs(UnmanagedType.U4)] FileShare share,
IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
[MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
IntPtr templateFile);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct WIN32_FIND_DATA
{
public int dwFileAttributes;
public FILETIME ftCreationTime;
public FILETIME ftLastAccessTime;
public FILETIME ftLastWriteTime;
public int nFileSizeHigh;
public int nFileSizeLow;
public int dwReserved0;
public int dwReserved1;
public string cFileName; //mite need marshalling, TCHAR size = MAX_PATH???
public string cAlternateFileName; //mite need marshalling, TCHAR size = 14
}
public struct WIN32_FIND_DATA1
{
public int dwFileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
public int nFileSizeHigh;
public int nFileSizeLow;
public int dwReserved0;
public int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll")]
static extern IntPtr FindFirstFile(IntPtr lpfilename, ref WIN32_FIND_DATA findfiledata);
[DllImport("kernel32.dll")]
static extern IntPtr FindClose(IntPtr pff);
[DllImport("User32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public static Process[] myProcess = Process.GetProcessesByName("program name here");
const uint WM_GETTEXT = 0x0D;
const uint WM_GETTEXTLENGTH = 0X0E;
const int BN_CLICKED = 245;
private const int WM_SETTEXT = 0x000C;
static void Main()
{
IntPtr hWnd = FindWindow(null, "Open");
if (hWnd != IntPtr.Zero)
{
Console.WriteLine("Open File Dialog is open");
IntPtr hwndButton = FindWindowEx(hWnd, IntPtr.Zero, "Button", "&Open");
Console.WriteLine("The handle of the Open button is " + hwndButton);
IntPtr FileDialogHandle = FindWindow(null, "Open");
IntPtr iptrHWndControl = GetDlgItem(FileDialogHandle, 1148);
HandleRef hrefHWndTarget = new HandleRef(null, iptrHWndControl);
//SendMessage(hrefHWndTarget, WM_SETTEXT, 0, "your file path");
IntPtr opnButton = FindWindowEx(FileDialogHandle, IntPtr.Zero, "Open", null);
SendMessage((int)opnButton, BN_CLICKED, 0, IntPtr.Zero);
int len = (int)SendMessage(hrefHWndTarget, WM_GETTEXTLENGTH, 0, null);
var sb = new StringBuilder(len + 1);
SendMessage(hrefHWndTarget, WM_GETTEXT, sb.Capacity, sb);
string text = sb.ToString();
//FileInfo f = new FileInfo(text);
DirectoryInfo hdDirectoryInWhichToSearch = new DirectoryInfo(#"c:\");
FileInfo[] filesInDir = hdDirectoryInWhichToSearch.GetFiles("*" + text + "*.*");
foreach (FileInfo foundFile in filesInDir)
{
string fullName = foundFile.FullName;
Console.WriteLine(fullName);
}
var newName = DateTime.Now;
var Username = (WindowsIdentity.GetCurrent().Name);
//var contentArray = GetFileSizeB(text);
Console.WriteLine("The Edit box contains " + text+"\tsize:"+contentArray + "\nUser Name "+Username +"\tTime : "+newName );
}
else
{
Console.WriteLine("Open File Dialog is not open");
}
Console.ReadKey();
}
//public static uint GetFileSizeB(string filename)
//{
// IntPtr handle = CreateFile(
// filename,
// FileAccess.Read,
// FileShare.Read,
// IntPtr.Zero,
// FileMode.Open,
// FileAttributes.ReadOnly,
// IntPtr.Zero);
// if (handle.ToInt32() == -1)
// {
// return 1;
// }
// long fileSize;
// GetFileSizeEx(handle, out fileSize);
// CloseHandle(handle);
// return (uint)fileSize;
//}
}
}*
Check your FileInfo class it contains properties like Length,path,extension..
Example in the loop through the files in filesInDir...
You can get the fileName, Path, Length etc., like below
int LengthInBytes = foundFile.Length;
Hope This Helps...
string path = "C:\\Test";
DirectoryInfo di = new DirectoryInfo(path);
FileInfo[] filesInDir = di.GetFiles();
foreach (FileInfo foundFile in filesInDir)
{
string fullName = foundFile.FullName;
long fileLength = foundFile.Length;
string fileName = foundFile.Name;
string extension = foundFile.Extension;
/// etc
Console.WriteLine(fullName);
}
Using an OpenFileDialog
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == DialogResult.OK)
{
string fileName = ofd.FileName;
MessageBox.Show("FName: " + fileName);
}
This will be a string of the full path to the file. If you have MultiSelect set on the OpenDialogBox it will return a string array of full filenames.
Edited as per OP's further specs
You can able to get file information using System.IO.FileInfo class. Here below the sample code.
private static void ShowFileDetails()
{
List<string> lstFiles = System.IO.Directory.GetFiles(#"D:\downloads").ToList(); //Need to pass the folder path to get the files.
foreach (string file in lstFiles)
{
System.IO.FileInfo fi = new System.IO.FileInfo(file);
Console.WriteLine(string.Format("Extension={0}\tFile Name={1}\tFile Size={2} bytes\tFile Path={3}\tCreated On={4}\tModified On={5}",
fi.Extension,
fi.Name,
fi.Length,
fi.FullName,
fi.CreationTime,
fi.LastWriteTime));
}
Console.ReadLine();
}

How to call CreateProcess() with STARTUPINFOEX from C# and re-parent the child

I need to create a new process but so that it is a "child" of another process not the current process eg re-parent the new process.
The following have got me almost there .NET : How to call CreateProcessAsUser() with STARTUPINFOEX from C# and .NET : How to PInvoke UpdateProcThreadAttribute and http://winprogger.com/launching-a-non-child-process/
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
public class ProcessCreator
{
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
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 PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UpdateProcThreadAttribute(
out IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue,
IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InitializeProcThreadAttributeList(
out IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
public static bool CreateProcess(int parentProcessId)
{
const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
var pInfo = new PROCESS_INFORMATION();
var sInfoEx = new STARTUPINFOEX();
sInfoEx.StartupInfo = new STARTUPINFO();
if (parentProcessId > 0)
{
var lpSize = IntPtr.Zero;
IntPtr dummyPtr;
var success = InitializeProcThreadAttributeList(out dummyPtr, 1, 0, ref lpSize);
if (success || lpSize == IntPtr.Zero)
{
return false;
}
sInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize);
if (sInfoEx.lpAttributeList == IntPtr.Zero)
{
return false;
}
success = InitializeProcThreadAttributeList(out sInfoEx.lpAttributeList, 1, 0, ref lpSize);
if (!success)
{
return false;
}
var parentHandle = Process.GetProcessById(parentProcessId).Handle;
success = UpdateProcThreadAttribute(
out sInfoEx.lpAttributeList,
0,
(IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
parentHandle,
(IntPtr)IntPtr.Size,
IntPtr.Zero,
IntPtr.Zero);
if (!success)
{
return false;
}
sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx);
}
var pSec = new SECURITY_ATTRIBUTES();
var tSec = new SECURITY_ATTRIBUTES();
pSec.nLength = Marshal.SizeOf(pSec);
tSec.nLength = Marshal.SizeOf(tSec);
var lpApplicationName = Path.Combine(Environment.SystemDirectory, "notepad.exe");
return CreateProcess(lpApplicationName, null, ref pSec, ref tSec, false, EXTENDED_STARTUPINFO_PRESENT, IntPtr.Zero, null, ref sInfoEx, out pInfo);
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
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)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
}
ProcessCreator.CreateProcess(0) starts Notepad as a child of current process which is the default behaviour. So far so good.
If the value passed in is non 0 the code attempts to start Notepad as a child of the process whose process ID matches the input value (I am assuming that process exists for now).
Unfortunately that part does not work and throws the following exception:
FatalExecutionEngineError was detected
Message: The runtime has encountered a fatal error. The address of the error was at 0x69a2c7ad, on thread 0x1de0. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
Any pointers much appreciated.
There are two issues with your code. First, the lpAttributeList parameter of the InitializeProcThreadAttributeList and UpdateProcThreadAttribute functions must be typed as IntPtr with no out modifier. Second, the lpValue parameter of the UpdateProcThreadAttribute function must be a pointer to the attribute value (in your case, parentHandle), not the value itself. Below is the fixed code.
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
public class ProcessCreator
{
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
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 PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UpdateProcThreadAttribute(
IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue,
IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InitializeProcThreadAttributeList(
IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteProcThreadAttributeList(IntPtr lpAttributeList);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
public static bool CreateProcess(int parentProcessId)
{
const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
var pInfo = new PROCESS_INFORMATION();
var sInfoEx = new STARTUPINFOEX();
sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx);
IntPtr lpValue = IntPtr.Zero;
try
{
if (parentProcessId > 0)
{
var lpSize = IntPtr.Zero;
var success = InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize);
if (success || lpSize == IntPtr.Zero)
{
return false;
}
sInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize);
success = InitializeProcThreadAttributeList(sInfoEx.lpAttributeList, 1, 0, ref lpSize);
if (!success)
{
return false;
}
var parentHandle = Process.GetProcessById(parentProcessId).Handle;
// This value should persist until the attribute list is destroyed using the DeleteProcThreadAttributeList function
lpValue = Marshal.AllocHGlobal(IntPtr.Size);
Marshal.WriteIntPtr(lpValue, parentHandle);
success = UpdateProcThreadAttribute(
sInfoEx.lpAttributeList,
0,
(IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
lpValue,
(IntPtr)IntPtr.Size,
IntPtr.Zero,
IntPtr.Zero);
if (!success)
{
return false;
}
}
var pSec = new SECURITY_ATTRIBUTES();
var tSec = new SECURITY_ATTRIBUTES();
pSec.nLength = Marshal.SizeOf(pSec);
tSec.nLength = Marshal.SizeOf(tSec);
var lpApplicationName = Path.Combine(Environment.SystemDirectory, "notepad.exe");
return CreateProcess(lpApplicationName, null, ref pSec, ref tSec, false, EXTENDED_STARTUPINFO_PRESENT, IntPtr.Zero, null, ref sInfoEx, out pInfo);
}
finally
{
// Free the attribute list
if (sInfoEx.lpAttributeList != IntPtr.Zero)
{
DeleteProcThreadAttributeList(sInfoEx.lpAttributeList);
Marshal.FreeHGlobal(sInfoEx.lpAttributeList);
}
Marshal.FreeHGlobal(lpValue);
// Close process and thread handles
if (pInfo.hProcess != IntPtr.Zero)
{
CloseHandle(pInfo.hProcess);
}
if (pInfo.hThread != IntPtr.Zero)
{
CloseHandle(pInfo.hThread);
}
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
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)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
}

Categories