Detect heap corruption BEFORE garbage collect - c#

I am using CDB (Microsoft Console Debugger,) and WinDbg to try to force a break when heap corruption occurs by P/Invoke into ReadFile. I read many more bytes from a text file than what I've allocated to the chBuf array. The debugger does not see the access violation until after GC.Collect, which is too late for me. Prior to running my program, I run
gflags -p /enable testheap.exe /unaligned
The effect seems useless. I wrote this little test program to apply what I find to debugging a much larger commercial program that is having heap corruption issues.
I have also tried DebugDiag with Application Verifier and MDA callbackOnCollectedDelegate without success. Isn't my use of gflags supposed to detect heap corruption immediately after ReadFile?
The code:
namespace TestHeap
public partial class Form1 : Form
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(SafeFileHandle hFile, [Out] byte[] lpBuffer,
uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
string fileName = "testHeap.txt";
const uint GENERIC_READ = 0x80000000;
const uint OPEN_EXISTING = 3;
SafeFileHandle sh;
byte[] chBuf = new byte[8];
public Form1()
{
InitializeComponent();
}
private void testBtn_Click(object sender, EventArgs e)
{
bool nStat;
uint bytesToRead = 1025;
uint bytesRead = 0;
if (!(nStat = ReadFile( sh, chBuf, bytesToRead, out bytesRead, IntPtr.Zero)))
Debug.Print("testBtn_Click error in ReadFile, nStat = {0}", nStat);
MessageBox.Show(string.Format("After ReadFile, bytesToRead = {0},\n bytes read = {1}", bytesToRead, bytesRead));
GC.Collect();
MessageBox.Show("testBtn_Click end, after GC.Collect");
}
private void Form1_Load(object sender, EventArgs e)
{
sh = CreateFile(fileName, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
}
}
}

Just a guess but I believe the unexpected gflags behaviour is caused by this line:
byte[] chBuf = new byte[8];
Since chBuf is managed by the CLR, gflags is not able to put the fill pattern after it to detect buffer overruns. Try changing that to:
IntPtr chBuf = Marshal.AllocHGlobal(8);
So that you will be allocating in the unmanaged heap. Gflags should be able to work with that. Also, you may need to change the signature of ReadFile for that to work:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(SafeFileHandle hFile, [Out] IntPtr lpBuffer,
uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);

Related

Console.Out Output is showing in Output Window, Needed in AllocConsole()

Ok, I've always used the AllocConsole() method for console output when it comes to needing a Winform as well, because I use a wide variety of color when it comes to writing to console.
Using VS 2015 and below, AllocConsole in Debug mode always worked properly, Console.WriteLine wrote to it properly. Now using VS 2017, The Console Shows when AllocConsole is called, however, instead of console.WriteLine outputs going to that console, it is going to the Output window of Visual Studio.
I prefer to use the AllocConsole rather than the Output window because I rely heavily on color. I've done plenty of searching on how to fix this, but I can't seem to find an answer.
AllocConsole() does not work on it's own, because VS 2017 does some "debug stdout redirect magic". To fix this you need to create a console with AllocConsole() and fix the stdout handle.
Here is the snipped I found:
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
uint lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
uint hTemplateFile);
private const int MY_CODE_PAGE = 437;
private const uint GENERIC_WRITE = 0x40000000;
private const uint FILE_SHARE_WRITE = 0x2;
private const uint OPEN_EXISTING = 0x3;
public static void CreateConsole()
{
AllocConsole();
IntPtr stdHandle = CreateFile(
"CONOUT$",
GENERIC_WRITE,
FILE_SHARE_WRITE,
0, OPEN_EXISTING, 0, 0
);
SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true);
FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
Encoding encoding = System.Text.Encoding.GetEncoding(MY_CODE_PAGE);
StreamWriter standardOutput = new StreamWriter(fileStream, encoding);
standardOutput.AutoFlush = true;
Console.SetOut(standardOutput);
Console.Write("This will show up in the Console window.");
}
Special thanks to Ramkumar Ramesh for the work-around:
Console Output is gone in VS2017
Building on the answer from wischi, if you want properties for the static Console class to work correctly, for instance Console.ForegroundColor it is important to set the desiredAccess to GENERIC_READ | GENERIC_WRITE. I think the reason for this is that Console is using GetConsoleScreenBufferInfo internally and when I tried to use that method on the handle returned by CreateFile with only GENERIC_WRITE that gave me an ACCESS_DENIED error.
[DllImport("kernel32.dll")]
private static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateFile(string lpFileName
, [MarshalAs(UnmanagedType.U4)] DesiredAccess dwDesiredAccess
, [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode
, uint lpSecurityAttributes
, [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition
, [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes
, uint hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetStdHandle(StdHandle nStdHandle, IntPtr hHandle);
private enum StdHandle : int
{
Input = -10,
Output = -11,
Error = -12
}
[Flags]
enum DesiredAccess : uint
{
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000
}
public static void CreateConsole()
{
if (AllocConsole())
{
//https://developercommunity.visualstudio.com/content/problem/12166/console-output-is-gone-in-vs2017-works-fine-when-d.html
// Console.OpenStandardOutput eventually calls into GetStdHandle. As per MSDN documentation of GetStdHandle: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231(v=vs.85).aspx will return the redirected handle and not the allocated console:
// "The standard handles of a process may be redirected by a call to SetStdHandle, in which case GetStdHandle returns the redirected handle. If the standard handles have been redirected, you can specify the CONIN$ value in a call to the CreateFile function to get a handle to a console's input buffer. Similarly, you can specify the CONOUT$ value to get a handle to a console's active screen buffer."
// Get the handle to CONOUT$.
var stdOutHandle = CreateFile("CONOUT$", DesiredAccess.GenericRead | DesiredAccess.GenericWrite, FileShare.ReadWrite, 0, FileMode.Open, FileAttributes.Normal, 0);
if (stdOutHandle == new IntPtr(-1))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (!SetStdHandle(StdHandle.Output, stdOutHandle))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
var standardOutput = new StreamWriter(Console.OpenStandardOutput());
standardOutput.AutoFlush = true;
Console.SetOut(standardOutput);
}
}

Microchip HID_PnP_Demo, WinForm to WPF

I've been trying to learn about WPF since I've been using VB.NET and WindowsForm for the past 10 years in a very few small projects.
I'm planning a simple interface to control my house with a PIC18F97J94.
Microchip provides an example (That's part of the MLA solution, it's in C# and WinForm) which I could workaround and finish my project but I want to learn WPF and C#.
The problem I'm encountering is with the .Handle:
RegisterDeviceNotification(this.Handle, pDeviceBroadcastHeader, DEVICE_NOTIFY_WINDOW_HANDLE);
Error CS1061 'MainWindow' does not contain a definition for 'Handle' and no extension method 'Handle' accepting a first argument of type 'MainWindow' could be found.
The full code block is the next one:
public MainWindow()
{
InitializeComponent();
ProgressBar1.ToolTip = ("If using a board/PIM without a potentiometer, apply an adjustable voltage to the I/O pin.");
ANxVoltage_lbl.ToolTip = ("If using a board/PIM without a potentiometer, apply an adjustable voltage to the I/O pin.");
ToggleLEDs_btn.ToolTip = ("Sends a packet of data to the USB device.");
PushbuttonState_lbl.ToolTip = ("Try pressing pushbuttons on the USB demo board/PIM.");
//Register for WM_DEVICECHANGE notifications. This code uses these messages to detect plug and play connection/disconnection events for USB devices
DEV_BROADCAST_DEVICEINTERFACE DeviceBroadcastHeader = new DEV_BROADCAST_DEVICEINTERFACE();
DeviceBroadcastHeader.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
DeviceBroadcastHeader.dbcc_size = (uint)Marshal.SizeOf(DeviceBroadcastHeader);
DeviceBroadcastHeader.dbcc_reserved = 0; //Reserved says not to use...
DeviceBroadcastHeader.dbcc_classguid = InterfaceClassGuid;
//Need to get the address of the DeviceBroadcastHeader to call RegisterDeviceNotification(), but
//can't use "&DeviceBroadcastHeader". Instead, using a roundabout means to get the address by
//making a duplicate copy using Marshal.StructureToPtr().
IntPtr pDeviceBroadcastHeader = IntPtr.Zero; //Make a pointer.
pDeviceBroadcastHeader = Marshal.AllocHGlobal(Marshal.SizeOf(DeviceBroadcastHeader)); //allocate memory for a new DEV_BROADCAST_DEVICEINTERFACE structure, and return the address
Marshal.StructureToPtr(DeviceBroadcastHeader, pDeviceBroadcastHeader, false); //Copies the DeviceBroadcastHeader structure into the memory already allocated at DeviceBroadcastHeaderWithPointer
RegisterDeviceNotification(this.Handle, pDeviceBroadcastHeader, DEVICE_NOTIFY_WINDOW_HANDLE);
//Now make an initial attempt to find the USB device, if it was already connected to the PC and enumerated prior to launching the application.
//If it is connected and present, we should open read and write handles to the device so we can communicate with it later.
//If it was not connected, we will have to wait until the user plugs the device in, and the WM_DEVICECHANGE callback function can process
//the message and again search for the device.
if (CheckIfPresentAndGetUSBDevicePath()) //Check and make sure at least one device with matching VID/PID is attached
{
uint ErrorStatusWrite;
uint ErrorStatusRead;
//We now have the proper device path, and we can finally open read and write handles to the device.
WriteHandleToUSBDevice = CreateFile(DevicePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
ErrorStatusWrite = (uint)Marshal.GetLastWin32Error();
ReadHandleToUSBDevice = CreateFile(DevicePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
ErrorStatusRead = (uint)Marshal.GetLastWin32Error();
if ((ErrorStatusWrite == ERROR_SUCCESS) && (ErrorStatusRead == ERROR_SUCCESS))
{
AttachedState = true; //Let the rest of the PC application know the USB device is connected, and it is safe to read/write to it
AttachedButBroken = false;
StatusBox_txtbx.Text = "Device Found, AttachedState = TRUE";
}
else //for some reason the device was physically plugged in, but one or both of the read/write handles didn't open successfully...
{
AttachedState = false; //Let the rest of this application known not to read/write to the device.
AttachedButBroken = true; //Flag so that next time a WM_DEVICECHANGE message occurs, can retry to re-open read/write pipes
if (ErrorStatusWrite == ERROR_SUCCESS)
WriteHandleToUSBDevice.Close();
if (ErrorStatusRead == ERROR_SUCCESS)
ReadHandleToUSBDevice.Close();
}
}
else //Device must not be connected (or not programmed with correct firmware)
{
AttachedState = false;
AttachedButBroken = false;
}
if (AttachedState == true)
{
StatusBox_txtbx.Text = "Device Found, AttachedState = TRUE";
}
else
{
StatusBox_txtbx.Text = "Device not found, verify connect/correct firmware";
}
ReadWriteThread.RunWorkerAsync();
}
Added info:
The next code block is what I transferred from the WinForm example, however I get the warning CS0649 in the line:
internal char[] DevicePath; //TCHAR array of any size
and
internal char[] dbcc_name; //TCHAR array
Code:
public partial class MainWindow : Window
{
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------BEGIN CUT AND PASTE BLOCK-----------------------------------------------------------------------------------
//Constant definitions from setupapi.h, which we aren't allowed to include directly since this is C#
internal const uint DIGCF_PRESENT = 0x02;
internal const uint DIGCF_DEVICEINTERFACE = 0x10;
//Constants for CreateFile() and other file I/O functions
internal const short FILE_ATTRIBUTE_NORMAL = 0x80;
internal const short INVALID_HANDLE_VALUE = -1;
internal const uint GENERIC_READ = 0x80000000;
internal const uint GENERIC_WRITE = 0x40000000;
internal const uint CREATE_NEW = 1;
internal const uint CREATE_ALWAYS = 2;
internal const uint OPEN_EXISTING = 3;
internal const uint FILE_SHARE_READ = 0x00000001;
internal const uint FILE_SHARE_WRITE = 0x00000002;
//Constant definitions for certain WM_DEVICECHANGE messages
internal const uint WM_DEVICECHANGE = 0x0219;
internal const uint DBT_DEVICEARRIVAL = 0x8000;
internal const uint DBT_DEVICEREMOVEPENDING = 0x8003;
internal const uint DBT_DEVICEREMOVECOMPLETE = 0x8004;
internal const uint DBT_CONFIGCHANGED = 0x0018;
//Other constant definitions
internal const uint DBT_DEVTYP_DEVICEINTERFACE = 0x05;
internal const uint DEVICE_NOTIFY_WINDOW_HANDLE = 0x00;
internal const uint ERROR_SUCCESS = 0x00;
internal const uint ERROR_NO_MORE_ITEMS = 0x00000103;
internal const uint SPDRP_HARDWAREID = 0x00000001;
enum WM_DEVICECHANGE_ENUM : int//Public Enum WM_DEVICECHANGE As Integer
{
DBT_CONFIGCHANGECANCELED = 0x19,
DBT_CONFIGCHANGED = 0x18,
DBT_CUSTOMEVENT = 0x8006,
DBT_DEVICEARRIVAL = 0x8000,
DBT_DEVICEQUERYREMOVE = 0x8001,
DBT_DEVICEQUERYREMOVEFAILED = 0x8002,
DBT_DEVICEREMOVECOMPLETE = 0x8004,
DBT_DEVICEREMOVEPENDING = 0x8003,
DBT_DEVICETYPESPECIFIC = 0x8005,
DBT_DEVNODES_CHANGED = 0x7,
DBT_QUERYCHANGECONFIG = 0x17,
DBT_USERDEFINED = 0xFFFF
}//End Enum
//Various structure definitions for structures that this code will be using
internal struct SP_DEVICE_INTERFACE_DATA
{
internal uint cbSize; //DWORD
internal Guid InterfaceClassGuid; //GUID
internal uint Flags; //DWORD
internal uint Reserved; //ULONG_PTR MSDN says ULONG_PTR is "typedef unsigned __int3264 ULONG_PTR;"
}
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
internal uint cbSize; //DWORD
internal char[] DevicePath; //TCHAR array of any size
}
internal struct SP_DEVINFO_DATA
{
internal uint cbSize; //DWORD
internal Guid ClassGuid; //GUID
internal uint DevInst; //DWORD
internal uint Reserved; //ULONG_PTR MSDN says ULONG_PTR is "typedef unsigned __int3264 ULONG_PTR;"
}
internal struct DEV_BROADCAST_DEVICEINTERFACE
{
internal uint dbcc_size; //DWORD
internal uint dbcc_devicetype; //DWORD
internal uint dbcc_reserved; //DWORD
internal Guid dbcc_classguid; //GUID
internal char[] dbcc_name; //TCHAR array
}
//DLL Imports. Need these to access various C style unmanaged functions contained in their respective DLL files.
//--------------------------------------------------------------------------------------------------------------
//Returns a HDEVINFO type for a device information set. We will need the
//HDEVINFO as in input parameter for calling many of the other SetupDixxx() functions.
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr SetupDiGetClassDevs(
ref Guid ClassGuid, //LPGUID Input: Need to supply the class GUID.
IntPtr Enumerator, //PCTSTR Input: Use NULL here, not important for our purposes
IntPtr hwndParent, //HWND Input: Use NULL here, not important for our purposes
uint Flags); //DWORD Input: Flags describing what kind of filtering to use.
//Gives us "PSP_DEVICE_INTERFACE_DATA" which contains the Interface specific GUID (different
//from class GUID). We need the interface GUID to get the device path.
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool SetupDiEnumDeviceInterfaces(
IntPtr DeviceInfoSet, //Input: Give it the HDEVINFO we got from SetupDiGetClassDevs()
IntPtr DeviceInfoData, //Input (optional)
ref Guid InterfaceClassGuid, //Input
uint MemberIndex, //Input: "Index" of the device you are interested in getting the path for.
ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); //Output: This function fills in an "SP_DEVICE_INTERFACE_DATA" structure.
//SetupDiDestroyDeviceInfoList() frees up memory by destroying a DeviceInfoList
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool SetupDiDestroyDeviceInfoList(
IntPtr DeviceInfoSet); //Input: Give it a handle to a device info list to deallocate from RAM.
//SetupDiEnumDeviceInfo() fills in an "SP_DEVINFO_DATA" structure, which we need for SetupDiGetDeviceRegistryProperty()
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool SetupDiEnumDeviceInfo(
IntPtr DeviceInfoSet,
uint MemberIndex,
ref SP_DEVINFO_DATA DeviceInterfaceData);
//SetupDiGetDeviceRegistryProperty() gives us the hardware ID, which we use to check to see if it has matching VID/PID
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool SetupDiGetDeviceRegistryProperty(
IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
uint Property,
ref uint PropertyRegDataType,
IntPtr PropertyBuffer,
uint PropertyBufferSize,
ref uint RequiredSize);
//SetupDiGetDeviceInterfaceDetail() gives us a device path, which is needed before CreateFile() can be used.
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool SetupDiGetDeviceInterfaceDetail(
IntPtr DeviceInfoSet, //Input: Wants HDEVINFO which can be obtained from SetupDiGetClassDevs()
ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, //Input: Pointer to an structure which defines the device interface.
IntPtr DeviceInterfaceDetailData, //Output: Pointer to a SP_DEVICE_INTERFACE_DETAIL_DATA structure, which will receive the device path.
uint DeviceInterfaceDetailDataSize, //Input: Number of bytes to retrieve.
ref uint RequiredSize, //Output (optional): The number of bytes needed to hold the entire struct
IntPtr DeviceInfoData); //Output (optional): Pointer to a SP_DEVINFO_DATA structure
//Overload for SetupDiGetDeviceInterfaceDetail(). Need this one since we can't pass NULL pointers directly in C#.
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool SetupDiGetDeviceInterfaceDetail(
IntPtr DeviceInfoSet, //Input: Wants HDEVINFO which can be obtained from SetupDiGetClassDevs()
ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, //Input: Pointer to an structure which defines the device interface.
IntPtr DeviceInterfaceDetailData, //Output: Pointer to a SP_DEVICE_INTERFACE_DETAIL_DATA structure, which will contain the device path.
uint DeviceInterfaceDetailDataSize, //Input: Number of bytes to retrieve.
IntPtr RequiredSize, //Output (optional): Pointer to a DWORD to tell you the number of bytes needed to hold the entire struct
IntPtr DeviceInfoData); //Output (optional): Pointer to a SP_DEVINFO_DATA structure
//Need this function for receiving all of the WM_DEVICECHANGE messages. See MSDN documentation for
//description of what this function does/how to use it. Note: name is remapped "RegisterDeviceNotificationUM" to
//avoid possible build error conflicts.
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr RegisterDeviceNotification(
IntPtr hRecipient,
IntPtr NotificationFilter,
uint Flags);
//Takes in a device path and opens a handle to the device.
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
//Uses a handle (created with CreateFile()), and lets us write USB data to the device.
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool WriteFile(
SafeFileHandle hFile,
byte[] lpBuffer,
uint nNumberOfBytesToWrite,
ref uint lpNumberOfBytesWritten,
IntPtr lpOverlapped);
//Uses a handle (created with CreateFile()), and lets us read USB data from the device.
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool ReadFile(
SafeFileHandle hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToRead,
ref uint lpNumberOfBytesRead,
IntPtr lpOverlapped);
//--------------- Global Varibles Section ------------------
//USB related variables that need to have wide scope.
bool AttachedState = false; //Need to keep track of the USB device attachment status for proper plug and play operation.
bool AttachedButBroken = false;
SafeFileHandle WriteHandleToUSBDevice = null;
SafeFileHandle ReadHandleToUSBDevice = null;
String DevicePath = null; //Need the find the proper device path before you can open file handles.
//Variables used by the application/form updates.
bool PushbuttonPressed = false; //Updated by ReadWriteThread, read by FormUpdateTimer tick handler (needs to be atomic)
bool ToggleLEDsPending = false; //Updated by ToggleLED(s) button click event handler, used by ReadWriteThread (needs to be atomic)
uint ADCValue = 0; //Updated by ReadWriteThread, read by FormUpdateTimer tick handler (needs to be atomic)
uint ADCDiff = 0;
//Globally Unique Identifier (GUID) for HID class devices. Windows uses GUIDs to identify things.
Guid InterfaceClassGuid = new Guid(0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30);
//--------------- End of Global Varibles ------------------
//-------------------------------------------------------END CUT AND PASTE BLOCK-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------
WindowInteropHelper interopHelper;
private BackgroundWorker ReadWriteThread = new BackgroundWorker();
private DispatcherTimer timer;
private Int32 BytesControl = 0;//Convert.ToInt32("000000000000000000000001", 2);
Replace this.Handle with the following:
new WindowInteropHelper(myWindow).Handle
WindowInteropHelper class is in the System.Windows.Interop namespace. And myWindow is the name of your Window.
Nevermind. The Window_Loaded event wasn't related to the function:
Here's my fix:
MainWindow_Loaded isn't triggered on my WPF Application

Change process name for Windows Task Manager

I have an C#/.NET application that behaves similarly to svchost--we use it to start our services, each of which resides in a separate DLL. When looking in the Task Manager, all of these show up with the same name--the name of the executable process that started them.
We would like to make each of these be named uniquely. Is there an API call that can be made to set the process name dynamically--i.e. to a string that is read from a configuration file?
I've read the other similar topics, but they haven't helped. A response to Question #14711100 suggested using symlinks, to which the response was that doesn't work. That question was also about killing and starting, so the answers were geared toward that problem.
Others mentioned setting the window title bar text or the process name of the executable. Those don't apply here because there is no window title bar, and the same executable is used to launch different processes.
Question #1402824 seems to be the closest. Is there any libc implementation available under Windows that would work?
If this can't be done, then are there any ways to somehow fake it? Our main goal is to be able to distinguish which process is which in Task Manager and similar process lists.
If we could even use the PID to get at the full command line, that would probably help.
As a last resort, if I set up some sort of supervisor that copies the EXE to a new name before launching, what are the implications that I should consider? Would I need to worry about anything duplicated in memory? Anything shared in memory? Anyone stomping on anyone's data, files, etc? An answer to Question #1402824 mentioned the same context. What do we need to know about that?
Thanks.
EDIT
I learned that I could get the process information using the wmic tool:
wmic service where (pathname like "%%svchostOrWhatever.exe%%" and state="Running") get DisplayName,Name,PathName,ProcessId,StartMode
This might end up being what we have to live with if we can't change the image name. Regarding that, I did find this VB 6.0 project by Billy Conner:
http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=66443&lngWId=1
I understand things have changed a lot since 2006, but I thought it's worth a try. (FYI I'm on Windows 7.)
It looks like it's basically using SendMessage to send a LVM_SETITEMTEXT message with the desired process name. I translated the calls to C# using P/Invoke, but it doesn't appear to work.
If I understand the API correctly, SendMessage will return true (nonzero) for LVM_SETITEMTEXT if it succeeded and false (zero) if failed, and then I can find out more information as usual using the managed version of GetLastError.
When I ran this in my svchost equivalent, SendMessage() returned zero. I called Marshal.GetLastWin32Error() and got back 1400, which looks like I'm getting ERROR_INVALID_WINDOW_HANDLE. Ok, maybe I can't run this on a Windows service since it doesn't have a window.
Then, I tried it in a dummy WPF application. This time, I still got a 0 back from SendMessage(), but GetLastWin32Error is also returning zero.
The dummy application has an App.xaml and a MainWindow.xaml. I placed the following call at the end of my MainWindow constructor in the code behind:
IntPtr handle = System.Diagnostics.Process.GetCurrentProcess().Handle;
SetItemText(handle, "Gobbledygook.exe", 0);
Here is the definition of SetItemText as taken and translated from Connor's project:
public static void SetItemText(IntPtr handle,
string desiredImageName,
long index,
long subIndex = 0)
{
// TODO: Check return values for errors...
desiredImageName = string.Format("{0}\0", desiredImageName); // TODO: Is the nul character required?
byte[] memStorage = System.Text.Encoding.ASCII.GetBytes(desiredImageName);
long size = memStorage.Length;
// allocate some shared memory for our string
IntPtr sharedProcMemString = VirtualAllocEx(handle,
IntPtr.Zero,
(uint)size,
AllocationType.Reserve | AllocationType.Commit,
MemoryProtection.ReadWrite);
// setup some info
LVITEM lvi = new LVITEM()
{
iItem = (int)index,
iSubItem = (int)subIndex,
cchTextMax = (int)size,
pszText = sharedProcMemString // store our string handle
};
// allocate some shared memory for our Struct
IntPtr sharedProcMem = VirtualAllocEx(handle,
IntPtr.Zero,
(uint)System.Runtime.InteropServices.Marshal.SizeOf(lvi),
AllocationType.Reserve | AllocationType.Commit,
MemoryProtection.ReadWrite);
// write to memory
WriteProcessMemory(handle, sharedProcMemString, memStorage);
WriteProcessMemory(handle, sharedProcMem, GetBytes(lvi));
// get the text
IntPtr result = SendMessage(handle, LVM_SETITEMTEXTA, (IntPtr)index, sharedProcMem);
if ((int)result == 0) // false, i.e. error
{
int errorCode = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
// TODO: do something with errorCode - e.g. log it?
}
// clean up
VirtualFreeEx(handle, sharedProcMem, System.Runtime.InteropServices.Marshal.SizeOf(lvi), AllocationType.Release);
VirtualFreeEx(handle, sharedProcMemString, (int)size, AllocationType.Release);
}
Here are some supporting routines:
private static byte[] GetBytes(LVITEM str)
{
int size = System.Runtime.InteropServices.Marshal.SizeOf(str);
byte[] arr = new byte[size];
IntPtr ptr = System.Runtime.InteropServices.Marshal.AllocHGlobal(size);
System.Runtime.InteropServices.Marshal.StructureToPtr(str, ptr, true);
System.Runtime.InteropServices.Marshal.Copy(ptr, arr, 0, size);
System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr);
return arr;
}
public static void WriteProcessMemory(IntPtr handle, IntPtr writeAddress, byte[] buffer)
{
int bytesWritten;
WriteProcessMemory(handle, writeAddress, buffer, (uint)buffer.Length, out bytesWritten);
}
Here are the necessary P/Invoke declarations:
private const int LVM_FIRST = 0x1000;
private const int LVM_GETITEMCOUNT = LVM_FIRST + 4;
private const int LVM_GETITEM = LVM_FIRST + 75;
private const int LVIF_TEXT = 0x0001;
private const int LVM_SETITEMTEXTA = (LVM_FIRST + 46);
[Flags]
public enum AllocationType
{
Commit = 0x1000,
Reserve = 0x2000,
Decommit = 0x4000,
Release = 0x8000,
Reset = 0x80000,
Physical = 0x400000,
TopDown = 0x100000,
WriteWatch = 0x200000,
LargePages = 0x20000000
}
[Flags]
public enum MemoryProtection
{
Execute = 0x10,
ExecuteRead = 0x20,
ExecuteReadWrite = 0x40,
ExecuteWriteCopy = 0x80,
NoAccess = 0x01,
ReadOnly = 0x02,
ReadWrite = 0x04,
WriteCopy = 0x08,
GuardModifierflag = 0x100,
NoCacheModifierflag = 0x200,
WriteCombineModifierflag = 0x400
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
private struct LVITEM
{
public uint mask;
public int iItem;
public int iSubItem;
public uint state;
public uint stateMask;
public IntPtr pszText;
public int cchTextMax;
public int iImage;
public IntPtr lParam;
}
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd,
int Msg,
IntPtr wParam,
IntPtr lParam);
[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern IntPtr VirtualAllocEx(IntPtr hProcess,
IntPtr lpAddress,
uint dwSize,
AllocationType flAllocationType,
MemoryProtection flProtect);
[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern bool VirtualFreeEx(IntPtr hProcess,
IntPtr lpAddress,
int dwSize,
AllocationType dwFreeType);
[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
private static extern bool WriteProcessMemory(IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
uint nSize,
out int lpNumberOfBytesWritten);
Any thoughts? Thanks.

how to get the tray button text wiht ReadProcessMemory

I want to get all tray icons on windows7(64bit) with C#,but when i used the windows api "ReadProcessMemory" ,the tray button Text can't be recognied.
codes below
IntPtr pid = IntPtr.Zero;
IntPtr ipHandle = IntPtr.Zero;
IntPtr lTextAdr = IntPtr.Zero;
IntPtr ipTray = TrayToolbarWindow32();
WinApiHelper.GetWindowThreadProcessId(ipTray, ref pid);
if (pid.Equals(0))
return iconList;
IntPtr hProcess = WinApiHelper.OpenProcess(WinApiHelper.PROCESS_ALL_ACCESS | WinApiHelper.PROCESS_VM_OPERATION | WinApiHelper.PROCESS_VM_READ | WinApiHelper.PROCESS_VM_WRITE, IntPtr.Zero, pid);
IntPtr lAddress = WinApiHelper.VirtualAllocEx(hProcess, 0, 4096, WinApiHelper.MEM_COMMIT, WinApiHelper.PAGE_READWRITE);
int lButton = WinApiHelper.SendMessage(ipTray, WinApiHelper.TB_BUTTONCOUNT, 0, 0);
for (int i = 0; i < lButton; i++)
{
WinApiHelper.SendMessage(ipTray, WinApiHelper.TB_GETBUTTON, i, lAddress);
WinApiHelper.ReadProcessMemory(hProcess, (IntPtr)(lAddress.ToInt32() + 16), ref lTextAdr, 4, 0);
if (!lTextAdr.Equals(-1))
{
byte[] buff = new byte[ 1024 ];
WinApiHelper.ReadProcessMemory(hProcess, lTextAdr, buff, 1024, 0);
string title = System.Text.ASCIIEncoding.Unicode.GetString(buff);
and api declaration
[DllImport("kernel32", EntryPoint = "ReadProcessMemory")]
public static extern int ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref IntPtr lpBuffer, int nSize, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll", EntryPoint = "ReadProcessMemory")]
public static extern bool ReadProcessMemoryEx(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, IntPtr size, out IntPtr lpNumberOfBytesRead);
[DllImport("kernel32", EntryPoint = "ReadProcessMemory")]
public static extern int ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] lpBuffer, int nSize, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, UIntPtr nSize, IntPtr lpNumberOfBytesRead);
the problem is here
string title = System.Text.ASCIIEncoding.Unicode.GetString(buff);
when converted , the string "title" can't be recognized,it maybe like
ǎ\0\0\0\0Д\0\0à\0\0ƿ\r\0\0\0\0\0\0\0\0\0\0D:\\Tools\\ESET Smart Security\\egui.exe\0\0\0\0\0\0\0\0\0\0\0\0\0\
i don't know why, help.
You may want to consider what you are doing. ReadProcessMemory is a debug function designed for debuggers which requires SeDebugPrivilege, so I hope you are writing a debugger. Ignoring the queasiness I get from considering use of these functions in a non-debug capacity, you are leaking the buffer you allocated and requiring that your application run as administrator.
If this application is only for your own purposes and for no-one else, then check out the related question Systray Access, as it seems that there is a separate TB_GETBUTTONTEXT message. I imagine that you are actually receiving the button data, rather than text in the copied memory, causing issues.

How to Eject CD-ROM [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
Windows CDROM Eject
Open CD/DVD door with a Windows API call?
I have looked around and can't find a simple solution to what I want to do.
I want to open a CD-Rom from my C# app. It should check if the media is in fact a cd- rom and then open it. Is there a quick solution to this or am I missing something?
Check this URL, it has both managed and unmanaged code for .net
http://bytes.com/topic/c-sharp/answers/273513-how-eject-cd-rom-c
Try below code :
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace EjectMedia
{
class Program
{
static void Main(string[] args)
{
// My CDROM is on drive E:
EjectMedia.Eject(#"\\.\E:");
}
}
class EjectMedia
{
// Constants used in DLL methods
const uint GENERICREAD = 0x80000000;
const uint OPENEXISTING = 3;
const uint IOCTL_STORAGE_EJECT_MEDIA = 2967560;
const int INVALID_HANDLE = -1;
// File Handle
private static IntPtr fileHandle;
private static uint returnedBytes;
// Use Kernel32 via interop to access required methods
// Get a File Handle
[DllImport("kernel32", SetLastError = true)]
static extern IntPtr CreateFile(string fileName,
uint desiredAccess,
uint shareMode,
IntPtr attributes,
uint creationDisposition,
uint flagsAndAttributes,
IntPtr templateFile);
[DllImport("kernel32", SetLastError=true)]
static extern int CloseHandle(IntPtr driveHandle);
[DllImport("kernel32", SetLastError = true)]
static extern bool DeviceIoControl(IntPtr driveHandle,
uint IoControlCode,
IntPtr lpInBuffer,
uint inBufferSize,
IntPtr lpOutBuffer,
uint outBufferSize,
ref uint lpBytesReturned,
IntPtr lpOverlapped);
public static void Eject(string driveLetter)
{
try
{
// Create an handle to the drive
fileHandle = CreateFile(driveLetter,
GENERICREAD,
0,
IntPtr.Zero,
OPENEXISTING,
0,
IntPtr.Zero);
if ((int)fileHandle != INVALID_HANDLE)
{
// Eject the disk
DeviceIoControl(fileHandle,
IOCTL_STORAGE_EJECT_MEDIA,
IntPtr.Zero, 0,
IntPtr.Zero, 0,
ref returnedBytes,
IntPtr.Zero);
}
}
catch
{
throw new Exception(Marshal.GetLastWin32Error().ToString());
}
finally
{
// Close Drive Handle
CloseHandle(fileHandle);
fileHandle = IntPtr.Zero;
}
}
}
}

Categories

Resources