I am attempting to write code to extract the contents of a CAB file, however I am having trouble using the SetupIterateCabinet routine.
Please see doc here http://msdn.microsoft.com/en-us/library/aa377404(v=vs.85).aspx
I can import it properly like this
private const uint SPFILENOTIFY_CABINETINFO = 0x00000010;
private const uint SPFILENOTIFY_FILEINCABINET = 0x00000011;
private const uint SPFILENOTIFY_NEEDNEWCABINET = 0x00000012;
private const uint SPFILENOTIFY_FILEEXTRACTED = 0x00000013;
private const uint SPFILENOTIFY_FILEOPDELAYED = 0x00000014;
private const uint NO_ERROR = 0;
private const uint FILEOP_ABORT = 0;
private const uint FILEOP_DOIT= 1;
private const uint FILEOP_SKIP= 2;
private const uint FILEOP_NEWPATH= 4;
static void Main(string[] args)
{
SetupIterateCabinet("c:\\SomeCab.cab", 0, new PSP_FILE_CALLBACK(CallBack), 0);
Console.ReadKey();
}
[DllImport("SetupApi.dll", CharSet = CharSet.Auto)]
public static extern bool SetupIterateCabinet(string cabinetFile,
uint reserved, PSP_FILE_CALLBACK callBack, uint context);
public delegate uint PSP_FILE_CALLBACK(uint context, uint notification,
IntPtr param1, IntPtr param2);
private static uint CallBack(uint context, uint notification, IntPtr param1,
IntPtr param2)
{
uint rtnValue = NO_ERROR;
switch (notification)
{
case SPFILENOTIFY_FILEINCABINET:
rtnValue = OnFileFound(context, notification, param1, param2);
break;
case SPFILENOTIFY_FILEEXTRACTED:
rtnValue = OnFileExtractComplete(param1);
break;
case SPFILENOTIFY_NEEDNEWCABINET:
rtnValue = NO_ERROR;
break;
}
return rtnValue;
}
private static uint OnFileExtractComplete(IntPtr param1)
{
Console.WriteLine("Complete");
return FILEOP_DOIT;
}
[StructLayout(LayoutKind.Sequential)]
struct _FILE_IN_CABINET_INFO {
IntPtr NameInCabinet;
int FileSize;
int Win32Error;
int DosDate;
int DosTime;
int DosAttribs;
StringBuilder FullTargetName;
};
static private uint OnFileFound(uint context, uint notification, IntPtr param1, IntPtr param2)
{
_FILE_IN_CABINET_INFO fc = new _FILE_IN_CABINET_INFO() ;
Marshal.PtrToStructure(param1, fc);
return 1;
}
However the problem comes when attempting to process the SPFILENOTIFY_FILEINCABINET event in the callback. According to the documentation this is a struct, that I need to put the name of where I want to have the file extracted to in. I am having trouble figuring out what the struct should look like and maybe how to convert the param to a struct.
I think you have a problem with the return values of your callback function. On SPFILENOTIFY_FILECABINET, you should be returning FILEOP_DOIT. Before returning you should be setting up the filename in the FILE_IN_CABINTE_INFO. Please check the codeproject post http://www.codeproject.com/Articles/7165/Iterate-and-Extract-Cabinet-File
I might add some code sample later. GTG now
EDIT:
Code sample below. I haven't tried it, but I believe it should work. I have tried to keep the structure similar to your code. This should show you how to define the FILE_IN_CABINET_INFO class and the correct values to be set and returned in the callback
public delegate uint PSP_FILE_CALLBACK(uint context, uint notification, IntPtr param1, IntPtr param2);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class FILE_IN_CABINET_INFO {
public String NameInCabinet;
public uint FileSize;
public uint Win32Error;
public ushort DosDate;
public ushort DosTime;
public ushort DosAttribs;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public System.String FullTargetName;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class FILEPATHS {
public String Target;
public String Source;
public uint Win32Error;
public uint Flags;
}
public const uint SPFILENOTIFY_FILEINCABINET = 0x00000011; // The file has been extracted from the cabinet.
public const uint SPFILENOTIFY_NEEDNEWCABINET = 0x00000012; // file is encountered in the cabinet.
public const uint SPFILENOTIFY_FILEEXTRACTED = 0x00000013; // The current file is continued in the next cabinet.
public const uint NO_ERROR = 0;
public const uint FILEOP_ABORT = 0; // Abort cabinet processing.
public const uint FILEOP_DOIT = 1; // Extract the current file.
public const uint FILEOP_SKIP = 2; // Skip the current file.
[DllImport("SetupApi.dll", CharSet = CharSet.Auto)]
public static extern bool SetupIterateCabinet(string cabinetFile, uint reserved, PSP_FILE_CALLBACK callBack, uint context);
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern uint GetLastError();
static void Main(string[] args) {
IterateCabinet(#"c:\SomeCab.cab");
}
public static void IterateCabinet(string filePath) {
PSP_FILE_CALLBACK callback = new PSP_FILE_CALLBACK(CallBack);
if (!SetupIterateCabinet(filePath, 0, callback, 0))
throw new Win32Exception((int)GetLastError());
}
static uint CallBack(uint context, uint notification, IntPtr param1, IntPtr param2) {
if (notification == SPFILENOTIFY_FILEINCABINET)
return OnFileFound(context, notification, param1, param2);
else if (notification == SPFILENOTIFY_FILEEXTRACTED)
return OnFileExtractComplete(param1);
else if (notification == SPFILENOTIFY_NEEDNEWCABINET)
return NO_ERROR;
return NO_ERROR;
}
static uint OnFileFound(uint context, uint notification, IntPtr param1, IntPtr param2) {
FILE_IN_CABINET_INFO fileInCabinetInfo = (FILE_IN_CABINET_INFO)Marshal.PtrToStructure(param1, typeof(FILE_IN_CABINET_INFO));
fileInCabinetInfo.FullTargetName = fileInCabinetInfo.NameInCabinet; // extract to current directory
return FILEOP_DOIT;
}
static uint OnFileExtractComplete(IntPtr param1) {
FILEPATHS filePaths = (FILEPATHS)Marshal.PtrToStructure(param1, typeof(FILEPATHS));
if (filePaths.Win32Error == NO_ERROR)
Console.WriteLine("File {0} extracted to {1} " + filePaths.Source, filePaths.Target);
else
Console.WriteLine("Errors occurred while extracting cab File {0} to {1} ", filePaths.Source, filePaths.Target);
return filePaths.Win32Error;
}
Related
I have a listView with a list of documents. To each of them I assigned an icon, using the following method:
private void SetDocumentIcon(ListViewItem item, FileInfo file)
{
Icon iconForFile = Icon.ExtractAssociatedIcon(file.FullName);
if (!documentsIconsImageList.Images.ContainsKey(file.Extension))
{
iconForFile = Icon.ExtractAssociatedIcon(file.FullName);
documentsIconsImageList.Images.Add(file.Extension, iconForFile);
}
item.ImageKey = file.Extension;
}
I tried to use this method for a folder, but it fails. The problem, as far as I understand, is that Icon.ExtractAssociatedIcon is for files and not folders. So how can I extract the icon of a folder?
Thanks.
SHGetStockIconInfo is the correct way to do it, and doesn't require the addition of unnecessary file IO. It's not any more complicated than SHGetFileInfo.
Here is an example class structured in a similar way to Evk's class. Some important things to note:
When you get an icon handle from SHGetStockIconInfo (or even SHGetFileInfo, for that matter), the native icon must be cleaned up by calling DestroyIcon(), otherwise you'll create a resource leak.
When you create an icon using Icon.FromHandle(), the object stores the handle you gave it and will use it for later operations. This means if you immediately call DestroyIcon() and then try to do something with the icon you just created, it will cause exceptions. You can avoid this by using Clone() to get an Icon that doesn't rely on your original native handle.
public static class DefaultIcons
{
private static Icon folderIcon;
public static Icon FolderLarge => folderIcon ?? (folderIcon = GetStockIcon(SHSIID_FOLDER, SHGSI_LARGEICON));
private static Icon GetStockIcon(uint type, uint size)
{
var info = new SHSTOCKICONINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
SHGetStockIconInfo(type, SHGSI_ICON | size, ref info);
var icon = (Icon)Icon.FromHandle(info.hIcon).Clone(); // Get a copy that doesn't use the original handle
DestroyIcon(info.hIcon); // Clean up native icon to prevent resource leak
return icon;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHSTOCKICONINFO
{
public uint cbSize;
public IntPtr hIcon;
public int iSysIconIndex;
public int iIcon;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szPath;
}
[DllImport("shell32.dll")]
public static extern int SHGetStockIconInfo(uint siid, uint uFlags, ref SHSTOCKICONINFO psii);
[DllImport("user32.dll")]
public static extern bool DestroyIcon(IntPtr handle);
private const uint SHSIID_FOLDER = 0x3;
private const uint SHGSI_ICON = 0x100;
private const uint SHGSI_LARGEICON = 0x0;
private const uint SHGSI_SMALLICON = 0x1;
}
I bet there are other ways, but I think easiest to implement is just use SHGetFileInfo win api function over temp folder you create. Example code:
public static class DefaultIcons
{
private static readonly Lazy<Icon> _lazyFolderIcon = new Lazy<Icon>(FetchIcon, true);
public static Icon FolderLarge
{
get { return _lazyFolderIcon.Value; }
}
private static Icon FetchIcon()
{
var tmpDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())).FullName;
var icon = ExtractFromPath(tmpDir);
Directory.Delete(tmpDir);
return icon;
}
private static Icon ExtractFromPath(string path)
{
SHFILEINFO shinfo = new SHFILEINFO();
SHGetFileInfo(
path,
0, ref shinfo, (uint)Marshal.SizeOf(shinfo),
SHGFI_ICON | SHGFI_LARGEICON);
return System.Drawing.Icon.FromHandle(shinfo.hIcon);
}
//Struct used by SHGetFileInfo function
[StructLayout(LayoutKind.Sequential)]
private struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
[DllImport("shell32.dll")]
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
private const uint SHGFI_ICON = 0x100;
private const uint SHGFI_LARGEICON = 0x0;
private const uint SHGFI_SMALLICON = 0x000000001;
}
Usage is just
var icon = DefaultIcons.FolderLarge
It's trivial to add property for small icon too.
public static class DefaultIcons
{
private static readonly Lazy _lazyFolderIcon = new Lazy(FetchIcon, true);
public static Icon FolderLarge
{
get { return _lazyFolderIcon.Value; }
}
private static Icon FetchIcon()
{
var tmpDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())).FullName;
var icon = ExtractFromPath(tmpDir);
Directory.Delete(tmpDir);
return icon;
}
private static Icon ExtractFromPath(string path)
{
SHFILEINFO shinfo = new SHFILEINFO();
SHGetFileInfo(
path,
0, ref shinfo, (uint)Marshal.SizeOf(shinfo),
SHGFI_ICON | SHGFI_LARGEICON);
return System.Drawing.Icon.FromHandle(shinfo.hIcon);
}
//Struct used by SHGetFileInfo function
[StructLayout(LayoutKind.Sequential)]
private struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
[DllImport("shell32.dll")]
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
private const uint SHGFI_ICON = 0x100;
private const uint SHGFI_LARGEICON = 0x0;
private const uint SHGFI_SMALLICON = 0x000000001;
}
I'm working on a WPF app which allows user to drag and drop files from Windows Explorer. For normal files, I'm able to access the path using
string[] fileNames = (string[])e.Data.GetData(DataFormats.FileDrop, false);
But for WPD files, its returning null. Have tried to follow the solution given in http://us.generation-nt.com/answer/drag-drop-pictures-wpd-camera-help-31497882.html#r , but i couldn't make it work. I'm getting AccessVoilationException when trying to get the count of items from the Shell array. I have posted the question in MSDN(http://social.msdn.microsoft.com/Forums/vstudio/en-US/ef7fc152-dd1b-4774-adb7-47b48726daea/drag-drop-from-windows-portable-device-to-wpf-application?forum=wpf), but didn't get any leads.
Is there something that I'm missing here? Could you please help me solve this issue?
Following is the relevant part my code.
public enum SIGDN : uint
{
NORMALDISPLAY = 0,
PARENTRELATIVEPARSING = 0x80018001,
PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
DESKTOPABSOLUTEPARSING = 0x80028000,
PARENTRELATIVEEDITING = 0x80031001,
DESKTOPABSOLUTEEDITING = 0x8004c000,
FILESYSPATH = 0x80058000,
URL = 0x80068000
}
internal class IIDGuid
{
private IIDGuid() { } // Avoid FxCop violation AvoidUninstantiatedInternalClasses
// IID GUID strings for relevant COM interfaces
internal const string IModalWindow = "b4db1657-70d7-485e-8e3e-6fcb5a5c1802";
internal const string IFileDialog = "42f85136-db7e-439c-85f1-e4075d135fc8";
internal const string IFileOpenDialog = "d57c7288-d4ad-4768-be02-9d969532d960";
internal const string IFileSaveDialog = "84bccd23-5fde-4cdb-aea4-af64b83d78ab";
internal const string IFileDialogEvents = "973510DB-7D7F-452B-8975-74A85828D354";
internal const string IShellItem = "43826D1E-E718-42EE-BC55-A1E261C37BFE";
internal const string IShellItemArray = "B63EA76D-1F85-456F-A19C-48159EFA858B";
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
public interface IShellItem
{
void BindToHandler(IntPtr pbc,
[MarshalAs(UnmanagedType.LPStruct)]Guid bhid,
[MarshalAs(UnmanagedType.LPStruct)]Guid riid,
out IntPtr ppv);
void GetParent(out IShellItem ppsi);
void GetDisplayName(SIGDN sigdnName, out IntPtr ppszName);
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
void Compare(IShellItem psi, uint hint, out int piOrder);
};
[ComImport]
[Guid(IIDGuid.IShellItemArray)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItemArray
{
// Not supported: IBindCtx
void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, out IntPtr ppvOut);
void GetPropertyStore([In] int Flags, [In] ref Guid riid, out IntPtr ppv);
void GetCount(out uint pdwNumItems);
void GetItemAt([In] uint dwIndex, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
void EnumItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenumShellItems);
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int SHCreateShellItemArrayFromDataObject(
System.Runtime.InteropServices.ComTypes.IDataObject pdo,
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppv);
[DllImport("kernel32.dll", SetLastError = true)]
static extern Int32 GetLastError();
private void OnFileDrop(object sender, DragEventArgs e)
{
string[] fileNames = (string[])e.Data.GetData(DataFormats.FileDrop, false);// null
System.Runtime.InteropServices.ComTypes.IDataObject mydata = e.Data as System.Runtime.InteropServices.ComTypes.IDataObject;
IShellItemArray nativeShellItemArray;
Guid guid = new Guid(IIDGuid.IShellItemArray);
int retCode = SHCreateShellItemArrayFromDataObject(mydata, ref guid, out nativeShellItemArray);
IShellItem nativeShellItem;
if (retCode == 0)
{
IntPtr displayname;
uint items = 0;
try
{
nativeShellItemArray.GetCount(out items); //Getting AccessVoilationException in this line
}
catch (Exception ex)
{
}
if (items > 0)
{
for (uint item = 0; item < items; item++)
{
nativeShellItemArray.GetItemAt(item, out nativeShellItem);
nativeShellItem.GetDisplayName(SIGDN.DESKTOPABSOLUTEPARSING, out displayname);
//Do something
}
}
}
}
We have a project of managing printing documents. At first I wonder why printing options couldn't be set up in single place. For example printer tray selection for first page and for other pages can be done using MS Word automation:
var doc = _applicationObject.Documents.OpenNoRepairDialog(FileName: ref sourceFile, ReadOnly: ref readOnly,
AddToRecentFiles: ref addToRecentFiles,
Visible: ref visible);
doc.PageSetup.FirstPageTray = (WdPaperTray) firstPageTrayCode;
doc.PageSetup.OtherPagesTray = (WdPaperTray) otherPagesTrayCode;
_applicationObject.ActivePrinter = printerPath;
doc.Activate();
_applicationObject.PrintOut(Background: ref backgroundPrint, FileName: sourceFile);
doc.Close(ref saveChanges, ref _missing, ref _missing);
In the code above printer tray is specified as integer because some printers have not standart values for trays (we had this issue with HP - it's tray codes described here). So we first retrieve what trays printer have, using code:
var setting = new PrinterSettings();
setting.PrinterName = myPrinterName;
foreach (PaperSource tray in setting.PaperSources)
{
Console.WriteLine("\t{0}: #{1}", tray.SourceName, tray.RawKind);
}
And this code works with no problems.
But there is no way to specify duplex and staple options here. Duplex can be done, using driver functions OpenPrinter and SetPrinter, like described here and recommended by Microsoft as well in this forum thread.
Staple is completely unclear and if somebody knows by the way how to implement this, please let me know. Using Stapling enum, like in this MSDN article is useless as it requires custom rendering of the document to print.
I described the situation and how parts were implemented. That works fine on our environment: Windows Server 2008 R2, MS Office 2010 x32, Printers HP LaserJet P2055 and Ricoh Nashuatec DSm635. Tested with native and universal PCL6/PCL5e drivers: duplex and tray selection works as expected.
But after deployment the application to client, printers (HP LaserJet 4250 and Ricoh Aficio MP C7501) do printing always from default tray and without duplex. Tried few different drivers with exactly the same result.
In both environments printers are network printers. So to make them apply duplex setting, using printer driver, we needed to install local driver on server and make a local printer, as recommended my Microsoft on this support forum thread.
Though environments and printers used looks very similar, one works while other do not. Any help will be highly appreciated.
In case someone else needs it, I came up with a workaround, based on storing printer settings memory block in a binary file and then restoring it. The idea was described in this blog post, but it didn't work for me when simply copy-pasted (it worked only for some drivers and for some settings while other printing options were ignored).
So I remade it a bit so that now it can support all settings I've tried on any printer (with compatible driver) I've tested. Of course if you use driver of another printer for example it won't work.
The disadvantage of thi approach is of course that you should first set default printer preferences (in Control Panel) to what you need. That isn't always possible of course, but at least in some cases it can help.
So the full source code of a test util which is capable to store printer settings into a file, load this file again into printer and print a document using the specified settings file:
using System;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Office.Interop.Word;
namespace PrintAdvancedTest
{
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
public int pDatatype;
public int pDevMode;
public int DesiredAccess;
}
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_INFO_2
{
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pServerName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pPrinterName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pShareName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pPortName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pDriverName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pComment;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pLocation;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pSepFile;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pPrintProcessor;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pDatatype;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pParameters;
public IntPtr pSecurityDescriptor;
public readonly Int32 Attributes;
public readonly Int32 Priority;
public readonly Int32 DefaultPriority;
public readonly Int32 StartTime;
public readonly Int32 UntilTime;
public readonly Int32 Status;
public readonly Int32 cJobs;
public readonly Int32 AveragePPM;
}
public class PrintSettings
{
private const short CCDEVICENAME = 32;
private const short CCFORMNAME = 32;
//Constants for DEVMODE
// Constants for DocumentProperties
private const int DM_MODIFY = 8;
private const int DM_COPY = 2;
private const int DM_IN_BUFFER = DM_MODIFY;
private const int DM_OUT_BUFFER = DM_COPY;
// const intants for dmOrientation
private const int DMORIENT_PORTRAIT = 1;
private const int DMORIENT_LANDSCAPE = 2;
// const intants for dmPrintQuality
private const int DMRES_DRAFT = (-1);
private const int DMRES_HIGH = (-4);
private const int DMRES_LOW = (-2);
private const int DMRES_MEDIUM = (-3);
// const intants for dmTTOption
private const int DMTT_BITMAP = 1;
private const int DMTT_DOWNLOAD = 2;
private const int DMTT_DOWNLOAD_OUTLINE = 4;
private const int DMTT_SUBDEV = 3;
// const intants for dmColor
private const int DMCOLOR_COLOR = 2;
private const int DMCOLOR_MONOCHROME = 1;
// const intants for dmCollate
private const int DMCOLLATE_FALSE = 0;
private const int DMCOLLATE_TRUE = 1;
// const intants for dmDuplex
private const int DMDUP_HORIZONTAL = 3;
private const int DMDUP_SIMPLEX = 1;
private const int DMDUP_VERTICAL = 2;
//const for security access
private const int PRINTER_ACCESS_ADMINISTER = 0x4;
private const int PRINTER_ACCESS_USE = 0x8;
private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
private const int PRINTER_ALL_ACCESS =
(STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER
| PRINTER_ACCESS_USE);
/* field selection bits */
private const int DM_ORIENTATION = 0x00000001;
private const int DM_PAPERSIZE = 0x00000002;
private const int DM_PAPERLENGTH = 0x00000004;
private const int DM_PAPERWIDTH = 0x00000008;
private const int DM_SCALE = 0x00000010;
private const int DM_POSITION = 0x00000020;
private const int DM_NUP = 0x00000040;
private const int DM_DISPLAYORIENTATION = 0x00000080;
private const int DM_COPIES = 0x00000100;
private const int DM_DEFAULTSOURCE = 0x00000200;
private const int DM_PRINTQUALITY = 0x00000400;
private const int DM_COLOR = 0x00000800;
private const int DM_DUPLEX = 0x00001000;
private const int DM_YRESOLUTION = 0x00002000;
private const int DM_TTOPTION = 0x00004000;
private const int DM_COLLATE = 0x00008000;
private const int DM_FORMNAME = 0x00010000;
private const int DM_LOGPIXELS = 0x00020000;
private const int DM_BITSPERPEL = 0x00040000;
private const int DM_PELSWIDTH = 0x00080000;
private const int DM_PELSHEIGHT = 0x00100000;
private const int DM_DISPLAYFLAGS = 0x00200000;
private const int DM_DISPLAYFREQUENCY = 0x00400000;
private const int DM_ICMMETHOD = 0x00800000;
private const int DM_ICMINTENT = 0x01000000;
private const int DM_MEDIATYPE = 0x02000000;
private const int DM_DITHERTYPE = 0x04000000;
private const int DM_PANNINGWIDTH = 0x08000000;
private const int DM_PANNINGHEIGHT = 0x10000000;
private const int DM_DISPLAYFIXEDOUTPUT = 0x20000000;
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCDEVICENAME)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCFORMNAME)]
public string dmFormName;
public short dmUnusedPadding;
public short dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
}
static void Main(string[] args)
{
Dictionary<string, Action> commands = new Dictionary<string, Action>
{
{"save", PrinterPreferencesSave},
{"print", PrinterPreferencesPrint},
{"set", PrinterPreferencesSet},
{"info", PrinterInfo}
};
while (true)
{
Console.Write("Command ({0}): ", string.Join(", ", commands.Keys));
string command = Console.ReadLine();
Action action;
if (!commands.TryGetValue(command, out action))
{
Console.WriteLine("Invalid command");
}
else
{
action();
}
}
}
static void PrinterPreferencesSave()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
Console.Write("Settings file path format: ");
string SettingsFileNameFormat = Console.ReadLine();
string testName;
while (true)
{
Console.Write("SAVE: Settings set name: ");
testName = Console.ReadLine();
if (testName == "end")
{
break;
}
getDevMode(printerName, string.Format(SettingsFileNameFormat, testName));
}
}
static void PrinterPreferencesPrint()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
Console.Write("Settings file path format: ");
string SettingsFileNameFormat = Console.ReadLine();
Console.Write("Document to print: ");
string docToPrintPath = Console.ReadLine();
string testName;
while (true)
{
Console.Write("PRINT: Settings set name: ");
testName = Console.ReadLine();
if (testName == "end")
{
break;
}
string filePath = string.Format(SettingsFileNameFormat, testName);
if (!File.Exists(filePath))
{
Console.WriteLine("File {0} not exists", filePath);
return;
}
var success = setDevMode(printerName, filePath);
if (success)
{
PrintWordDocument(docToPrintPath, printerName);
}
}
}
static void PrinterPreferencesSet()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
Console.Write("Settings file path format: ");
string SettingsFileNameFormat = Console.ReadLine();
string testName;
while (true)
{
Console.Write("SET: Settings set name: ");
testName = Console.ReadLine();
if (testName == "end")
{
break;
}
string filePath = string.Format(SettingsFileNameFormat, testName);
if (!File.Exists(filePath))
{
Console.WriteLine("File {0} not exists", filePath);
return;
}
var success = setDevMode(printerName, filePath);
if(!success)
{
Console.WriteLine("Failed");
}
}
}
private static void PrinterInfo()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
IntPtr hDevMode; // handle to the DEVMODE
IntPtr pDevMode; // pointer to the DEVMODE
DEVMODE devMode; // the actual DEVMODE structure
//var printController = new StandardPrintController();
PrinterSettings printerSettings = new PrinterSettings();
printerSettings.PrinterName = printerName;
// Get a handle to a DEVMODE for the default printer settings
hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings);
// Obtain a lock on the handle and get an actual pointer so Windows won't
// move it around while we're futzing with it
pDevMode = GlobalLock(hDevMode);
// Marshal the memory at that pointer into our P/Invoke version of DEVMODE
devMode = (DEVMODE)Marshal.PtrToStructure(pDevMode, typeof(DEVMODE));
Dictionary<string, int> dmConstants = new Dictionary<string, int>
{
{"DM_ORIENTATION", 0x00000001},
{"DM_PAPERSIZE", 0x00000002},
{"DM_PAPERLENGTH", 0x00000004},
{"DM_PAPERWIDTH", 0x00000008},
{"DM_SCALE", 0x00000010},
{"DM_POSITION", 0x00000020},
{"DM_NUP", 0x00000040},
{"DM_DISPLAYORIENTATION", 0x00000080},
{"DM_COPIES", 0x00000100},
{"DM_DEFAULTSOURCE", 0x00000200},
{"DM_PRINTQUALITY", 0x00000400},
{"DM_COLOR", 0x00000800},
{"DM_DUPLEX", 0x00001000},
{"DM_YRESOLUTION", 0x00002000},
{"DM_TTOPTION", 0x00004000},
{"DM_COLLATE", 0x00008000},
{"DM_FORMNAME", 0x00010000},
{"DM_LOGPIXELS", 0x00020000},
{"DM_BITSPERPEL", 0x00040000},
{"DM_PELSWIDTH", 0x00080000},
{"DM_PELSHEIGHT", 0x00100000},
{"DM_DISPLAYFLAGS", 0x00200000},
{"DM_DISPLAYFREQUENCY", 0x00400000},
{"DM_ICMMETHOD", 0x00800000},
{"DM_ICMINTENT", 0x01000000},
{"DM_MEDIATYPE", 0x02000000},
{"DM_DITHERTYPE", 0x04000000},
{"DM_PANNINGWIDTH", 0x08000000},
{"DM_PANNINGHEIGHT", 0x10000000},
{"DM_DISPLAYFIXEDOUTPUT", 0x20000000},
};
Console.WriteLine("Allow set: {0}. Details: {1}", Convert.ToString(devMode.dmFields, 16), string.Join(",", dmConstants.Where(c=>(devMode.dmFields & c.Value)==c.Value).Select(c=>c.Key)));
//private const int DM_POSITION = 0x00000020;
//private const int DM_NUP = 0x00000040;
//private const int DM_DISPLAYORIENTATION = 0x00000080;
//private const int DM_DEFAULTSOURCE = 0x00000200;
//private const int DM_PRINTQUALITY = 0x00000400;
//private const int DM_COLOR = 0x00000800;
//private const int DM_YRESOLUTION = 0x00002000;
//private const int DM_TTOPTION = 0x00004000;
//private const int DM_FORMNAME = 0x00010000;
//private const int DM_LOGPIXELS = 0x00020000;
//private const int DM_BITSPERPEL = 0x00040000;
//private const int DM_PELSWIDTH = 0x00080000;
//private const int DM_PELSHEIGHT = 0x00100000;
//private const int DM_DISPLAYFLAGS = 0x00200000;
//private const int DM_DISPLAYFREQUENCY = 0x00400000;
//private const int DM_ICMMETHOD = 0x00800000;
//private const int DM_ICMINTENT = 0x01000000;
//private const int DM_MEDIATYPE = 0x02000000;
//private const int DM_DITHERTYPE = 0x04000000;
//private const int DM_PANNINGWIDTH = 0x08000000;
//private const int DM_PANNINGHEIGHT = 0x10000000;
//private const int DM_DISPLAYFIXEDOUTPUT = 0x20000000;
WriteDevModePropertyInfo("DeviceName", devMode.dmDeviceName, null);
WriteDevModePropertyInfo("SpecVersion", devMode.dmSpecVersion.ToString(), null);
WriteDevModePropertyInfo("DriverVersion", devMode.dmDriverVersion.ToString(), null);
WriteDevModePropertyInfo("Size", devMode.dmSize.ToString(), null);
WriteDevModePropertyInfo("DriverExtra", devMode.dmDriverExtra.ToString(), null);
WriteDevModePropertyInfo("Orientation", devMode.dmOrientation.ToString(), (devMode.dmFields & DM_ORIENTATION) == DM_ORIENTATION);
WriteDevModePropertyInfo("PaperSize", devMode.dmPaperSize.ToString(), (devMode.dmFields & DM_PAPERSIZE) == DM_PAPERSIZE);
WriteDevModePropertyInfo("PaperLength", devMode.dmPaperLength.ToString(), (devMode.dmFields & DM_PAPERLENGTH) == DM_PAPERLENGTH);
WriteDevModePropertyInfo("PaperWidth", devMode.dmPaperWidth.ToString(), (devMode.dmFields & DM_PAPERWIDTH) == DM_PAPERWIDTH);
WriteDevModePropertyInfo("Scale", devMode.dmScale.ToString(), (devMode.dmFields & DM_SCALE) == DM_SCALE);
WriteDevModePropertyInfo("Copies", devMode.dmCopies.ToString(), (devMode.dmFields & DM_COPIES) == DM_COPIES);
WriteDevModePropertyInfo("Duplex", devMode.dmDuplex.ToString(), (devMode.dmFields & DM_DUPLEX) == DM_DUPLEX);
WriteDevModePropertyInfo("YResolution", devMode.dmYResolution.ToString(), null);
WriteDevModePropertyInfo("TTOption", devMode.dmTTOption.ToString(), null);
WriteDevModePropertyInfo("Collate", devMode.dmCollate.ToString(), (devMode.dmFields & DM_COLLATE) == DM_COLLATE);
WriteDevModePropertyInfo("FormName", devMode.dmFormName.ToString(), null);
WriteDevModePropertyInfo("UnusedPadding", devMode.dmUnusedPadding.ToString(), null);
WriteDevModePropertyInfo("BitsPerPel", devMode.dmBitsPerPel.ToString(), null);
WriteDevModePropertyInfo("PelsWidth", devMode.dmPelsWidth.ToString(), null);
WriteDevModePropertyInfo("PelsHeight", devMode.dmPelsHeight.ToString(), null);
WriteDevModePropertyInfo("DisplayFlags", devMode.dmDisplayFlags.ToString(), null);
WriteDevModePropertyInfo("DisplayFrequency", devMode.dmDisplayFlags.ToString(), null);
}
private static void WriteDevModePropertyInfo(string settingName, string value, bool? allowSet)
{
Console.WriteLine("{0} {1} {2}", allowSet.HasValue ? (allowSet.Value ? "+" : "-") : " ", settingName.PadRight(20, '.'), value);
}
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalFree(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalLock(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalUnlock(IntPtr handle);
[DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern Int32 GetLastError();
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesA", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter,
[MarshalAs(UnmanagedType.LPStr)] string pDeviceNameg,
IntPtr pDevModeOutput, ref IntPtr pDevModeInput, int fMode);
[DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true,
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
private static extern bool GetPrinter(IntPtr hPrinter, Int32 dwLevel,
IntPtr pPrinter, Int32 dwBuf, out Int32 dwNeeded);
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA",
SetLastError = true, CharSet = CharSet.Ansi,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool
OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter,
out IntPtr hPrinter, ref PRINTER_DEFAULTS pd);
[DllImport("winspool.drv", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr
pPrinter, int Command);
[DllImport("kernel32.dll")]
static extern IntPtr GlobalAlloc(uint uFlags, int dwBytes);
public static void getDevMode(string printerName, string filepath)
{
PRINTER_DEFAULTS PrinterValues = new PRINTER_DEFAULTS();
PrinterValues.pDatatype = 0;
PrinterValues.pDevMode = 0;
PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;
IntPtr ptrZero = IntPtr.Zero;
IntPtr hPrinter;
IntPtr pDevMode = new IntPtr();
//get printer handle
OpenPrinter(printerName, out hPrinter, ref PrinterValues);
//allocate memory for ptr to devmode, 0 argument retrieves bytes required
int bytes = DocumentProperties(new IntPtr(0), hPrinter, printerName, ptrZero, ref pDevMode, 0);
pDevMode = GlobalAlloc(0, bytes);
//set the pointer
DocumentProperties(new IntPtr(0), hPrinter, printerName, pDevMode, ref ptrZero, DM_OUT_BUFFER);
//write the devMode to a file
using (FileStream fs = new FileStream(filepath, FileMode.Create))
{
for (int i = 0; i < bytes; i++)
{
fs.WriteByte(Marshal.ReadByte(pDevMode, i));
}
}
//free resources
GlobalFree(pDevMode);
ClosePrinter(hPrinter);
}
public static bool setDevMode(string printerName, string filepath)
{
if(!File.Exists(filepath))
{
return false;
}
IntPtr hPrinter;
int bytes = 0;
IntPtr pPInfo;
IntPtr pDevMode;
PRINTER_INFO_2 pInfo = new PRINTER_INFO_2();
PRINTER_DEFAULTS PrinterValues = new PRINTER_DEFAULTS();
PrinterValues.pDatatype = 0;
PrinterValues.pDevMode = 0;
PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;
//retrieve the devmode from file
using (FileStream fs = new FileStream(filepath, FileMode.Open))
{
int length = Convert.ToInt32(fs.Length);
pDevMode = GlobalAlloc(0, length);
for (int i = 0; i < length; i++)
{
Marshal.WriteByte(pDevMode, i, (byte)fs.ReadByte());
}
}
//get printer handle
OpenPrinter(printerName, out hPrinter, ref PrinterValues);
//get bytes for printer info structure and allocate memory
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out bytes);
if (bytes == 0)
{
throw new Exception("Get Printer Failed");
}
pPInfo = GlobalAlloc(0, bytes);
//set pointer to printer info
GetPrinter(hPrinter, 2, pPInfo, bytes, out bytes);
//place the printer info structure
pInfo = (PRINTER_INFO_2)Marshal.PtrToStructure(pPInfo, typeof(PRINTER_INFO_2));
//insert the new devmode
pInfo.pDevMode = pDevMode;
pInfo.pSecurityDescriptor = IntPtr.Zero;
//set pointer to new printer info
Marshal.StructureToPtr(pInfo, pPInfo, true);
//update
SetPrinter(hPrinter, 2, pPInfo, 0);
//free resources
GlobalFree(pPInfo);
GlobalFree(pDevMode);
ClosePrinter(hPrinter);
return true;
}
private static void PrintWordDocument(string path, string printerName)
{
object readOnly = true;
object addToRecentFiles = false;
object visible = false;
object backgroundPrint = false;
object saveChanges = false;
object sourceFile = path;
var wordApplication = new Application();
var doc = wordApplication.Documents.OpenNoRepairDialog(FileName: ref sourceFile, ReadOnly: ref readOnly,
AddToRecentFiles: ref addToRecentFiles,
Visible: ref visible);
wordApplication.ActivePrinter = printerName;
doc.Activate();
wordApplication.PrintOut(Background: ref backgroundPrint, FileName: sourceFile);
object _missing = Type.Missing;
doc.Close(ref saveChanges, ref _missing, ref _missing);
}
}
}
UPDATE 2018-12-04 (in 5,5 years): There was a nasty rare problem with Marshal.StructureToPtr call in this code and today I finally got an answer to that question (see comment from Hans Passant). I'm not able to verify if that actually works since I no longer work on that project, but it seems you may need to apply that fix if you try using this code.
I've been searching for a c# library that gets the icon of a given path with many sizes, finally when I got exactly the class that I need, It has a problem:
This method gets icon of a given path:
public static BitmapSource GetIcon(string FileName, bool small, bool checkDisk, bool addOverlay)
{
SHFILEINFO shinfo = new SHFILEINFO();
uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
uint SHGFI_LINKOVERLAY = 0x000008000;
uint flags;
if (small)
{
flags = SHGFI_ICON | SHGFI_SMALLICON;
}
else
{
flags = SHGFI_ICON | SHGFI_LARGEICON;
}
if (!checkDisk)
flags |= SHGFI_USEFILEATTRIBUTES;
if (addOverlay)
flags |= SHGFI_LINKOVERLAY;
var res = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), flags);
if (res == 0)
{
throw (new System.IO.FileNotFoundException());
}
var ico = System.Drawing.Icon.FromHandle(shinfo.hIcon); //**Here**
var bs = BitmapFromIcon(ico);
ico.Dispose();
bs.Freeze();
DestroyIcon(shinfo.hIcon);
// CloseHandle(shinfo.hIcon); it always give exception
return bs;
}
public static extern Boolean CloseHandle(IntPtr handle);
The previous code as it is in this question works as it suppose to, however AFTER getting the icons of file paths in a directory successfully, it gives an exception on this line :
var ico = System.Drawing.Icon.FromHandle(shinfo.hIcon);
An exception of type 'System.IO.FileNotFoundException' occurred in WPF_REMOTE.exe but was not handled in user code
Additional information: Unable to find the specified file.
So Why is this happening?
Update: I found out that it happened because there were a path that contains unicode characters and i need to use SHFILEINFOW instead, still can't figure how to change SHFILEINFO to SHFILEINFOW
another question about the line CloseHandle(shinfo.hIcon); always give an exception :
An exception of type 'System.Runtime.InteropServices.SEHException' occurred in WPF_REMOTE.exe but was not handled in user code
Additional information: External component has thrown an exception.
I'm wondering why it's not working! and why should I use it if the method is already working without it.
also if you have any improvement I could use in this class tell me, Thanks in Advance.
After editing some code I get it, you can get the icons easily from this library, in my case i needed the icon as byte[]
public class IconHelper
{
// Constants that we need in the function call
private const int SHGFI_ICON = 0x100;
private const int SHGFI_SMALLICON = 0x1;
private const int SHGFI_LARGEICON = 0x0;
private const int SHIL_JUMBO = 0x4;
private const int SHIL_EXTRALARGE = 0x2;
// This structure will contain information about the file
public struct SHFILEINFO
{
// Handle to the icon representing the file
public IntPtr hIcon;
// Index of the icon within the image list
public int iIcon;
// Various attributes of the file
public uint dwAttributes;
// Path to the file
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szDisplayName;
// File type
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
[System.Runtime.InteropServices.DllImport("Kernel32.dll")]
public static extern Boolean CloseHandle(IntPtr handle);
private struct IMAGELISTDRAWPARAMS
{
public int cbSize;
public IntPtr himl;
public int i;
public IntPtr hdcDst;
public int x;
public int y;
public int cx;
public int cy;
public int xBitmap; // x offest from the upperleft of bitmap
public int yBitmap; // y offset from the upperleft of bitmap
public int rgbBk;
public int rgbFg;
public int fStyle;
public int dwRop;
public int fState;
public int Frame;
public int crEffect;
}
[StructLayout(LayoutKind.Sequential)]
private struct IMAGEINFO
{
public IntPtr hbmImage;
public IntPtr hbmMask;
public int Unused1;
public int Unused2;
public Rect rcImage;
}
[DllImport("shell32.dll", EntryPoint = "#727")]
private extern static int SHGetImageList(
int iImageList,
ref Guid riid,
out IImageList ppv
);
// The signature of SHGetFileInfo (located in Shell32.dll)
[DllImport("Shell32.dll", CharSet = CharSet.Unicode)]
public static extern int SHGetFileInfo(string pszPath, int dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, uint uFlags);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode)]
public static extern int SHGetFileInfo(IntPtr pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, uint uFlags);
[DllImport("shell32.dll", SetLastError = true)]
static extern int SHGetSpecialFolderLocation(IntPtr hwndOwner, Int32 nFolder,
ref IntPtr ppidl);
[DllImport("user32")]
public static extern int DestroyIcon(IntPtr hIcon);
public struct pair
{
public System.Drawing.Icon icon { get; set; }
public IntPtr iconHandleToDestroy { set; get; }
}
private static byte[] ByteFromIcon(System.Drawing.Icon ic)
{
var icon = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(ic.Handle,
System.Windows.Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
icon.Freeze();
byte[] data;
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(icon));
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
data = ms.ToArray();
}
return data;
}
private static byte[] GetSmallIcon(string FileName, IconSize iconSize)
{
SHFILEINFO shinfo = new SHFILEINFO();
uint flags;
if (iconSize == IconSize.Small)
{
flags = SHGFI_ICON | SHGFI_SMALLICON;
}
else
{
flags = SHGFI_ICON | SHGFI_LARGEICON;
}
var res = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), flags);
if (res == 0)
{
throw (new System.IO.FileNotFoundException());
}
var ico = (System.Drawing.Icon)System.Drawing.Icon.FromHandle(shinfo.hIcon);
var bs = ByteFromIcon(ico);
ico.Dispose();
DestroyIcon(shinfo.hIcon);
return bs;
}
private static byte[] GetLargeIcon(string FileName)
{
SHFILEINFO shinfo = new SHFILEINFO();
uint SHGFI_SYSICONINDEX = 0x4000;
int FILE_ATTRIBUTE_NORMAL = 0x80;
uint flags;
flags = SHGFI_SYSICONINDEX;
var res = SHGetFileInfo(FileName, FILE_ATTRIBUTE_NORMAL, ref shinfo, Marshal.SizeOf(shinfo), flags);
if (res == 0)
{
throw (new System.IO.FileNotFoundException());
}
var iconIndex = shinfo.iIcon;
Guid iidImageList = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950");
IImageList iml;
int size = SHIL_EXTRALARGE;
var hres = SHGetImageList(size, ref iidImageList, out iml); // writes iml
IntPtr hIcon = IntPtr.Zero;
int ILD_TRANSPARENT = 1;
hres = iml.GetIcon(iconIndex, ILD_TRANSPARENT, ref hIcon);
var ico = System.Drawing.Icon.FromHandle(hIcon);
var bs = ByteFromIcon(ico);
ico.Dispose();
DestroyIcon(hIcon);
return bs;
}
}
and you can get four different sizes for the icon
I am working on an application that required reading the mifare card serial number, the language I am working with is C#.
I am new to mifare reader programming, so I am sorry for asking dumb question.
At first I would like to know if there is a different between Mifare UID and Mifare Serial number.
I have managed to get UID with the help of WinSCard library, but I cant figure it out how to get the card serial number which should be 10 digit numbers.
I do appreciate if you could point me to the right direction.
Thanks in advance for the help.
Regards
C# signature of SCardTransmit method
[StructLayout(LayoutKind.Sequential)]
public struct SCARD_IO_REQUEST
{
public int dwProtocol;
public int cbPciLength;
}
[DllImport("winscard.dll")]
public static extern int SCardTransmit(int hCard, ref SCARD_IO_REQUEST pioSendRequest, ref byte SendBuff, int SendBuffLen, ref SCARD_IO_REQUEST pioRecvRequest,
ref byte RecvBuff, ref int RecvBuffLen);
Code Example for read UID of mifare card
private SmartcardErrorCode GetUID(ref byte[] UID)
{
byte[] receivedUID = new byte[10];
UnsafeNativeMethods.SCARD_IO_REQUEST request = new UnsafeNativeMethods.SCARD_IO_REQUEST();
request.dwProtocol = 1; //SCARD_PROTOCOL_T1);
request.cbPciLength = System.Runtime.InteropServices.Marshal.SizeOf(typeof(UnsafeNativeMethods.SCARD_IO_REQUEST));
byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x04 }; //get UID command for Mifare cards
int outBytes = receivedUID.Length;
int status = SCardTransmit(_hCard, ref request, ref sendBytes[0], sendBytes.Length, ref request, ref receivedUID[0], ref outBytes);
UID = receivedUID.Take(8).ToArray();
return status;
}
The Selected answer doesn't work on x64 enviroments.
Here is a Full example code, tested and working on Windows 10 x64.
What this does:
Retrieve the List of Available Readers
Selects to use the First available Reader
Check if there is a Card in the reader and Connects to it.
Transmits to the card the Command to retrieve its UID
Converts the UID into a Hexadecimal string.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace DXCutcsa.VO.Common
{
public class SmartCardReader
{
#region Atributos
private bool _disposed = false;
private IntPtr _ReaderContext = IntPtr.Zero;
private string _ReaderName = string.Empty;
private List<string> _AvailableReaders = new List<string>();
#endregion
#region Win32 APIs
[DllImport("WinScard.dll")]
static extern int SCardEstablishContext(uint dwScope,
IntPtr notUsed1,
IntPtr notUsed2,
out IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardReleaseContext(IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardConnect(IntPtr hContext,
string cReaderName,
uint dwShareMode,
uint dwPrefProtocol,
ref IntPtr phCard,
ref IntPtr ActiveProtocol);
[DllImport("WinScard.dll")]
static extern int SCardDisconnect(IntPtr hCard, int Disposition);
[DllImport("WinScard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)]
static extern int SCardListReaders(
IntPtr hContext,
byte[] mszGroups,
byte[] mszReaders,
ref UInt32 pcchReaders);
[DllImport("winscard.dll")]
static extern int SCardStatus(
uint hCard,
IntPtr szReaderName,
ref int pcchReaderLen,
ref int pdwState,
ref uint pdwProtocol,
byte[] pbAtr,
ref int pcbAtrLen);
[DllImport("winscard.dll")]
static extern int SCardTransmit(
IntPtr hCard,
ref SCARD_IO_REQUEST pioSendRequest,
ref byte SendBuff,
uint SendBuffLen,
ref SCARD_IO_REQUEST pioRecvRequest,
byte[] RecvBuff,
ref uint RecvBuffLen);
[DllImport("winscard.dll", SetLastError = true)]
static extern int SCardGetAttrib(
IntPtr hCard, // Valor retornado en funcion ScardConnect
UInt32 dwAttrId, // Identificacion de atributos a obtener
byte[] pbAttr, // Puntero al vector atributos recividos
ref IntPtr pcbAttrLen // TamaƱo del vector
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ReaderState
{
public ReaderState(string sName)
{
this.szReader = sName;
this.pvUserData = IntPtr.Zero;
this.dwCurrentState = 0;
this.dwEventState = 0;
this.cbATR = 0;
this.rgbATR = null;
}
internal string szReader;
internal IntPtr pvUserData;
internal uint dwCurrentState;
internal uint dwEventState;
internal uint cbATR; // count of bytes in rgbATR
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24, ArraySubType = UnmanagedType.U1)]
internal byte[] rgbATR;
}
[StructLayout(LayoutKind.Sequential)]
public struct SCARD_IO_REQUEST
{
public UInt32 dwProtocol;
public UInt32 cbPciLength;
}
/*****************************************************************/
[DllImport("kernel32.dll", SetLastError = true)]
private extern static IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll")]
private extern static void FreeLibrary(IntPtr handle);
[DllImport("kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr handle, string procName);
#endregion
#region Error codes
public const uint S_SUCCESS = 0x00000000;
public const uint F_INTERNAL_ERROR = 0x80100001;
public const uint E_CANCELLED = 0x80100002;
public const uint E_INVALID_HANDLE = 0x80100003;
public const uint E_INVALID_PARAMETER = 0x80100004;
public const uint E_INVALID_TARGET = 0x80100005;
public const uint E_NO_MEMORY = 0x80100006;
public const uint F_WAITED_TOO_LONG = 0x80100007;
public const uint E_INSUFFICIENT_BUFFER = 0x80100008;
public const uint E_UNKNOWN_READER = 0x80100009;
public const uint E_TIMEOUT = 0x8010000A;
public const uint E_SHARING_VIOLATION = 0x8010000B;
public const uint E_NO_SMARTCARD = 0x8010000C;
public const uint E_UNKNOWN_CARD = 0x8010000D;
public const uint E_CANT_DISPOSE = 0x8010000E;
public const uint E_PROTO_MISMATCH = 0x8010000F;
public const uint E_NOT_READY = 0x80100010;
public const uint E_INVALID_VALUE = 0x80100011;
public const uint E_SYSTEM_CANCELLED = 0x80100012;
public const uint F_COMM_ERROR = 0x80100013;
public const uint F_UNKNOWN_ERROR = 0x80100014;
public const uint E_INVALID_ATR = 0x80100015;
public const uint E_NOT_TRANSACTED = 0x80100016;
public const uint E_READER_UNAVAILABLE = 0x80100017;
public const uint P_SHUTDOWN = 0x80100018;
public const uint E_PCI_TOO_SMALL = 0x80100019;
public const uint E_READER_UNSUPPORTED = 0x8010001A;
public const uint E_DUPLICATE_READER = 0x8010001B;
public const uint E_CARD_UNSUPPORTED = 0x8010001C;
public const uint E_NO_SERVICE = 0x8010001D;
public const uint E_SERVICE_STOPPED = 0x8010001E;
public const uint E_UNEXPECTED = 0x8010001F;
public const uint E_ICC_INSTALLATION = 0x80100020;
public const uint E_ICC_CREATEORDER = 0x80100021;
public const uint E_UNSUPPORTED_FEATURE = 0x80100022;
public const uint E_DIR_NOT_FOUND = 0x80100023;
public const uint E_FILE_NOT_FOUND = 0x80100024;
public const uint E_NO_DIR = 0x80100025;
public const uint E_NO_FILE = 0x80100026;
public const uint E_NO_ACCESS = 0x80100027;
public const uint E_WRITE_TOO_MANY = 0x80100028;
public const uint E_BAD_SEEK = 0x80100029;
public const uint E_INVALID_CHV = 0x8010002A;
public const uint E_UNKNOWN_RES_MNG = 0x8010002B;
public const uint E_NO_SUCH_CERTIFICATE = 0x8010002C;
public const uint E_CERTIFICATE_UNAVAILABLE = 0x8010002D;
public const uint E_NO_READERS_AVAILABLE = 0x8010002E;
public const uint E_COMM_DATA_LOST = 0x8010002F;
public const uint E_NO_KEY_CONTAINER = 0x80100030;
public const uint W_UNSUPPORTED_CARD = 0x80100065;
public const uint W_UNRESPONSIVE_CARD = 0x80100066;
public const uint W_UNPOWERED_CARD = 0x80100067;
public const uint W_RESET_CARD = 0x80100068;
public const uint W_REMOVED_CARD = 0x80100069;
public const uint W_SECURITY_VIOLATION = 0x8010006A;
public const uint W_WRONG_CHV = 0x8010006B;
public const uint W_CHV_BLOCKED = 0x8010006C;
public const uint W_EOF = 0x8010006D;
public const uint W_CANCELLED_BY_USER = 0x8010006E;
public const uint W_CARD_NOT_AUTHENTICATED = 0x8010006F;
#endregion
#region Constructor
public SmartCardReader()
{
}
#endregion
#region Metodos
public long GetUID(ref byte[] UID)
{
long _result = 0;
bool cardInserted = false;
IntPtr _CardContext = IntPtr.Zero;
IntPtr ActiveProtocol = IntPtr.Zero;
// Establish Reader context:
if (this._ReaderContext == IntPtr.Zero)
{
_result = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out this._ReaderContext);
#region Get List of Available Readers
uint pcchReaders = 0;
int nullindex = -1;
char nullchar = (char)0;
// First call with 3rd parameter set to null gets readers buffer length.
_result = SCardListReaders(this._ReaderContext, null, null, ref pcchReaders);
byte[] mszReaders = new byte[pcchReaders];
// Fill readers buffer with second call.
_result = SCardListReaders(this._ReaderContext, null, mszReaders, ref pcchReaders);
// Populate List with readers.
string currbuff = new ASCIIEncoding().GetString(mszReaders);
int len = (int)pcchReaders;
if (len > 0)
{
while (currbuff[0] != nullchar)
{
nullindex = currbuff.IndexOf(nullchar); // Get null end character.
string reader = currbuff.Substring(0, nullindex);
this._AvailableReaders.Add(reader);
len = len - (reader.Length + 1);
currbuff = currbuff.Substring(nullindex + 1, len);
}
}
#endregion
// Select the first reader:
this._ReaderName = this._AvailableReaders[0];
}
try
{
//Check if there is a Card in the reader:
//dwShareMode: SCARD_SHARE_SHARED = 0x00000002 - This application will allow others to share the reader
//dwPreferredProtocols: SCARD_PROTOCOL_T0 - Use the T=0 protocol (value = 0x00000001)
if (this._ReaderContext != IntPtr.Zero)
{
_result = SCardConnect(this._ReaderContext, this._ReaderName, 0x00000002, 0x00000001, ref _CardContext, ref ActiveProtocol);
if (_result == 0)
{
cardInserted = true;
SCARD_IO_REQUEST request = new SCARD_IO_REQUEST()
{
dwProtocol = (uint)ActiveProtocol,
cbPciLength = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(SCARD_IO_REQUEST))
};
byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x00 }; //<- get UID command for iClass cards
byte[] ret_Bytes = new byte[33];
uint sendLen = (uint)sendBytes.Length;
uint ret_Len = (uint)ret_Bytes.Length;
_result = SCardTransmit(_CardContext, ref request, ref sendBytes[0], sendLen, ref request, ret_Bytes, ref ret_Len);
if (_result == 0)
{
UID = ret_Bytes.Take(4).ToArray(); //only take the first 8, the last 2 bytes are not part of the UID of the card
string dataOut = byteToHexa(UID, UID.Length, true).Trim(); //Devolver la respuesta en Hexadecimal
}
}
}
}
finally
{
SCardDisconnect(_CardContext, 0);
SCardReleaseContext(this._ReaderContext);
}
return _result;
}
private string byteToHexa(byte[] byReadBuffer, int leng, bool bSpace)
{
string text2 = "";
for (short num1 = 0; num1 < leng; num1 = (short)(num1 + 1))
{
short num2 = byReadBuffer[num1];
text2 = text2 + System.Convert.ToString(num2, 16).PadLeft(2, '0');
if (bSpace)
{
text2 = text2 + " ";
}
}
return text2.ToUpper();
}
//Get the address of Pci from "Winscard.dll".
private IntPtr GetPciT0()
{
IntPtr handle = LoadLibrary("Winscard.dll");
IntPtr pci = GetProcAddress(handle, "g_rgSCardT0Pci");
FreeLibrary(handle);
return pci;
}
#endregion
}// Fin de la Clase
}
PInvoke docs helped a lot: https://www.pinvoke.net/default.aspx/winscard.scardtransmit