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
Related
Although I searched this site and the internet I could not find any way to achieve enabling or disabling TouchPad programmatically for Windows 11. However this can be achieved easly via this page in settings:
Can anyone show me how to achieve this programmatically, preferably via C#.Net
PS: I need this to affect immediately. I mean without a reboot or log out/log in.
Backup your registry before making changes to it
This registry key is the one to change (which you can change using c#).
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\PrecisionTouchPad\Status
You need to set the Enabled REG_DWORD to 0
const string userRoot = "HKEY_CURRENT_USER";
const string subkey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PrecisionTouchPad\\Status";
const string keyName = userRoot + "\\" + subkey;
// ON
Registry.SetValue(keyName, "Enabled", 1, RegistryValueKind.DWord);
// OFF
Registry.SetValue(keyName, "Enabled", 0, RegistryValueKind.DWord);
You will then need to broadcast a message to tell Windows the setting has changed.
This is the c# (untested sorry). The documentation for the flags can be found here: https://learn.microsoft.com/en-us/dotnet/api/microsoft.crm.unifiedservicedesk.dynamics.controls.nativemethods.sendmessagetimeoutflags?view=dynamics-usd-3
[Flags]
public enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0,
SMTO_BLOCK = 0x1,
SMTO_ABORTIFHUNG = 0x2,
SMTO_NOTIMEOUTIFNOTHUNG = 0x8
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(IntPtr hWnd,uint Msg,UIntPtr wParam,IntPtr lParam,
SendMessageTimeoutFlags fuFlags,uint uTimeout,out UIntPtr lpdwResult);
IntPtr HWND_BROADCAST = new IntPtr(0xffff);
const uint WM_SETTINGCHANGE = 0x1A;
const int MSG_TIMEOUT = 15000;
UIntPtr RESULT;
string ENVIRONMENT = "Environment";
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, UIntPtr.Zero, (IntPtr)Marshal.StringToHGlobalAnsi(ENVIRONMENT), SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, MSG_TIMEOUT, out RESULT);
This is the powershell script
if (-not ("win32.nativemethods" -as [type])) {
add-type -Namespace Win32 -Name NativeMethods -MemberDefinition #"
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
"#
}
$HWND_BROADCAST = [intptr]0xffff;
$WM_SETTINGCHANGE = 0x1a;
$result = [uintptr]::zero
[win32.nativemethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE,[uintptr]::Zero, "Environment", 2, 5000, [ref]$result);
I'd like to get content of a document sent to printing.
Google said an only way to do that is to use WinAPI method ReadPrinter().
I've implemented a sketch but can't get it work.
A trouble is the ReadPrinter() method always returns nothing.
Please give me a hint what is wrong.
Simplified code below:
string printerName = "Microsoft XPS Document Writer";
const uint firstJob = 0u;
const uint noJobs = 10u;
const uint level = 1u;
uint bytesNeeded;
uint returned;
uint bytesCopied;
uint structsCopied;
// Open printer
IntPtr printerHandle = OpenPrinterW(printerName.Normalize(), out printerHandle, IntPtr.Zero);
// Get byte size required for a data
EnumJobsW(printerHandle, firstJob, noJobs, level, IntPtr.Zero, 0, out bytesNeeded, out returned);
// Now we know how much memory we need to read the data (bytesNeeded value)
IntPtr pJob = Marshal.AllocHGlobal((int)bytesNeeded);
// Read the data
EnumJobsW(printerHandle, firstJob, noJobs, level, pJob, bytesNeeded, out bytesCopied, out structsCopied);
// Convert pJob to jobInfos
JOB_INFO_1W[] jobInfos = null;
// ... actual convert code missed ...
// Iterate through the jobs and try to get their content
foreach (JOB_INFO_1W jobInfo in jobInfos)
{
// Open print job
string printJobName = string.Format("{0}, Job {1}", printerName, jobInfo.JobId);
IntPtr printJobHandle;
OpenPrinterW(printJobName.Normalize(), out printJobHandle, IntPtr.Zero);
// Read print job
const int printJobBufLen = 1024;
StringBuilder printJobSb = new StringBuilder(printJobBufLen);
int printJobBytesRead = 0;
while (printJobBytesRead == 0)
{
ReadPrinter(printJobHandle, printJobSb, printJobBufLen, out printJobBytesRead);
// !!! printJobBytesRead is 0 and printJobSb is empty
}
// Close print job
ClosePrinter(printJobHandle);
}
// Close printer
ClosePrinter(printerHandle);
P/Invoke signatures:
[DllImport("winspool.drv", EntryPoint = "OpenPrinterW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int OpenPrinterW(
[In] string pPrinterName,
[Out] out IntPtr phPrinter,
[In] IntPtr pDefault);
[DllImport("spoolss.dll", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int ClosePrinter(
[In] IntPtr hPrinter);
[DllImport("winspool.drv", EntryPoint = "EnumJobsW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int EnumJobsW(
[In] IntPtr hPrinter,
[In] uint FirstJob,
[In] uint NoJobs,
[In] uint Level,
[Out] IntPtr pJob,
[In] uint cbBuf,
[Out] out uint pcbNeeded,
[Out] out uint pcReturned);
[DllImport("spoolss.dll", EntryPoint = "ReadPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int ReadPrinter(
[In] IntPtr hPrinter,
[Out] StringBuilder data,
[In] Int32 cbBuf,
[Out] out Int32 pNoBytesRead);
Is this code inside a driver's Print Processor component? (Link updated to web archive.) If not, I don't think it will work.
So you either use a print driver component, or read from the spool file on disk. See here.
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.
FileSystemInfo.LastWriteTime property is readonly in CF.
Is there an alternative way to change that date?
P/Invoke SetFileTime.
EDIT
Something along these lines (warning: untested)
[DllImport("coredll.dll")]
private static extern bool SetFileTime(string path,
ref long creationTime,
ref long lastAccessTime,
ref long lastWriteTime);
public void SetFileTimes(string path, DateTime time)
{
var ft = time.ToFileTime();
SetFileTime(path, ref ft, ref ft, ref ft);
}
Here is a fuller implementation, adapted from the answer ctacke provides above and this StackOverflow question. I hope this proves useful to someone:
// Some Windows constants
// File access (using CreateFileW)
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const uint GENERIC_READ_WRITE = (GENERIC_READ + GENERIC_WRITE);
public const int INVALID_HANDLE_VALUE = -1;
// File creation (using CreateFileW)
public const int CREATE_NEW = 1;
public const int OPEN_EXISTING = 3;
// File attributes (using CreateFileW)
public const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
// P/Invokes
[DllImport("coredll.dll", SetLastError = true)]
public static extern IntPtr CreateFileW(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr pSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplatefile);
[DllImport("coredll.dll", SetLastError = true)]
public static extern int CloseHandle(IntPtr hObject);
// Note: Create related P/Invokes to change creation or last access time.
// This one modifies the last write time only.
[DllImport("coredll.dll", EntryPoint = "SetFileTime", SetLastError = true)]
private static extern bool SetFileWriteTime(
IntPtr hFile,
IntPtr lpCreationTimeUnused,
IntPtr lpLastAccessTimeUnused,
ref long lpLastWriteTime);
// Open a handle to the file you want changed
IntPtr hFile = CreateFileW(
path, GENERIC_READ_WRITE, 0,
IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero);
// Modify the last write time and close the file
long lTimeNow = DateTime.Now.ToFileTime();
SetFileWriteTime(hFile, IntPtr.Zero, IntPtr.Zero, ref lTimeNow);
CloseHandle(hFile);
Note that you can use System.IO.File.GetLastWriteTime (which is exposed in the .NET Compact Framework) to read the last write time if required.
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;
}
}
}
}