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.
Related
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'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
I'm trying to extract an icon from imageres.dll. Specifically the "My Computer" or "This PC" icon. The problem is that at between Win7 and Win10, the icon number changes. However, the icon group does not (109). Is there a way to get that icon group, and then let the computer figure out which icon to use of that group, in the same way it figures out which icon to use for my app?
This is the code I'm using to get the specific icon via the index:
public class GetIcon {
public static Icon Extract(string file, int number) {
IntPtr large;
IntPtr small;
ExtractIconEx(file, number, out large, out small, 1);
try {
return Icon.FromHandle(small);
}
catch {
return null;
}
}
[DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);
}
Thanks.
There are a couple of ways to do this. The most reliable, and potentially most time consuming (provided you can't find an existing library), is to parse the PE File (i.e. .exe, .dll) and extract the relevant Icon group data yourself. Here's a good resource for the format: https://msdn.microsoft.com/en-us/library/ms809762.aspx
The second way, can be done easily enough with Windows functions, however there is one caveat. It will only work on PE files that are of the same bit-type as your application. So, for example, if your application is 64-bit, it will only work on 64-bit PE files.
Here's a function I just wrote - based off this: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648051(v=vs.85).aspx#_win32_Sharing_Icon_Resources, that takes a file name, group number, and desired icon size, and returns a System.Drawing.Icon
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
[DllImport("kernel32.dll")]
static extern IntPtr FindResource(IntPtr hModule, int lpName, int lpType);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
[DllImport("kernel32.dll")]
static extern IntPtr LockResource(IntPtr hResData);
[DllImport("user32.dll")]
static extern int LookupIconIdFromDirectoryEx(byte[] presbits, bool fIcon, int cxDesired, int cyDesired, uint Flags);
[DllImport("user32.dll")]
static extern IntPtr CreateIconFromResourceEx(byte[] pbIconBits, uint cbIconBits, bool fIcon, uint dwVersion, int cxDesired, int cyDesired, uint uFlags);
[DllImport("kernel32.dll", SetLastError = true)]
static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);
const int RT_GROUP_ICON = 14;
const int RT_ICON = 0x00000003;
private System.Drawing.Icon GetIconFromGroup(string file, int groupId, int size)
{
IntPtr hExe = LoadLibrary(file);
if(hExe != IntPtr.Zero)
{
IntPtr hResource = FindResource(hExe, groupId, RT_GROUP_ICON);
IntPtr hMem = LoadResource(hExe, hResource);
IntPtr lpResourcePtr = LockResource(hMem);
uint sz = SizeofResource(hExe, hResource);
byte[] lpResource = new byte[sz];
Marshal.Copy(lpResourcePtr, lpResource, 0, (int)sz);
int nID = LookupIconIdFromDirectoryEx(lpResource, true, size, size, 0x0000);
hResource = FindResource(hExe, nID, RT_ICON);
hMem = LoadResource(hExe, hResource);
lpResourcePtr = LockResource(hMem);
sz = SizeofResource(hExe, hResource);
lpResource = new byte[sz];
Marshal.Copy(lpResourcePtr, lpResource, 0, (int)sz);
IntPtr hIcon = CreateIconFromResourceEx(lpResource, sz, true, 0x00030000, size, size, 0);
System.Drawing.Icon testIco = System.Drawing.Icon.FromHandle(hIcon);
return testIco;
}
return null;
}
The process basically works like this:
use LoadLibrary to load up the .exe or .dll file
Get the handle & data of the RT_GROUP_ICON resource
Pass the data, along with the desired size to LookupIconIdFromDirectoryEx, to get the icon index
From there, you can either use ExtractIconEx, or just repeat step 2 with the icon index, and RT_ICON instead, followed by using CreateIconFromResourceEx to get your icon handle.
I trying to marshaling C# code from WinApi functions..
But i understand.. WHYYY WHYY she dont work! Filepath - is correct, handle is taken.
Can anyone help me?
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Linq;
using System.Text;
namespace ChangeFileTime
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetFileTime(IntPtr hFile, ref long lpCreationTime,
ref long lpLastAccessTime,
ref long lpLastWriteTime);
[DllImport("kernel32.dll")]
public static extern IntPtr CreateFile(string lpFilename,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll")]
public static extern bool CloseHandle(IntPtr hObject);
static void Main(string[] args)
{
const uint GENERIC_READ = 0x80000000;
const uint OPEN_EXISTING = 3;
const uint FILE_SHARE_WRITE = 0x00000002;
const uint FILE_ATTRIBUTE_NORMAL = 128;
IntPtr ptr = CreateFile("C:\\file.txt", GENERIC_READ,
FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero);
DateTime creation_time = new DateTime(1990, 12, 14);
long file_time = creation_time.ToFileTime();
DateTime time = DateTime.FromFileTime(file_time);
SetFileTime(ptr, ref file_time, ref file_time, ref file_time);
int a = 20;
}
}
}
I think i got mistake.. i try to write C++ code, and she work fine.. but why in C# dont work?
From MSDN:
The handle must have been created using the CreateFile function with
the FILE_WRITE_ATTRIBUTES
This should work:
const uint FILE_WRITE_ATTRIBUTES = 0x0100;
IntPtr ptr = CreateFile("C:\\file.txt", FILE_WRITE_ATTRIBUTES, //...
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;
}
}
}
}