I've tried to print content of RichTextBox and there are too many bugs if I print to printer.
But when I'm printing to XPS-file (through XPS-printer in windows) and then printing this file to printer all is ok.
So can I do all these things programmatically?
Here is my printing method:
public int PrintRotate(bool rotate, PrintPageEventArgs e, int charFrom, int charTo)
{
//Calculate the area to render and print
RECT rectToPrint;
rectToPrint.Top = (int)(e.MarginBounds.Top * anInch);
rectToPrint.Bottom = (int)(e.MarginBounds.Bottom * anInch);
rectToPrint.Left = (int)(e.MarginBounds.Left * anInch);
rectToPrint.Right = (int)(e.MarginBounds.Right * anInch);
//Calculate the size of the page
RECT rectPage;
rectPage.Top = (int)(e.PageBounds.Top * anInch);
rectPage.Bottom = (int)(e.PageBounds.Bottom * anInch);
rectPage.Left = (int)(e.PageBounds.Left * anInch);
rectPage.Right = (int)(e.PageBounds.Right * anInch);
IntPtr hdc = e.Graphics.GetHdc();
FORMATRANGE fmtRange;
fmtRange.chrg.cpMax = charTo; //Indicate character from to character to
fmtRange.chrg.cpMin = charFrom;
fmtRange.hdc = hdc; //Use the same DC for measuring and rendering
fmtRange.hdcTarget = hdc; //Point at printer hDC
fmtRange.rc = rectToPrint; //Indicate the area on page to print
fmtRange.rcPage = rectPage; //Indicate size of page
SetGraphicsMode(fmtRange.hdc, GM_ADVANCED);
XFORM par = new XFORM();
par = new XFORM();
par.eM11 = 1;
par.eM12 = 0;
par.eM21 = 0;
par.eM22 = 1;
par.eDx = -e.PageSettings.Margins.Left / 100 * e.PageSettings.PrinterResolution.X;
par.eDy = -e.PageSettings.Margins.Top / 100 * e.PageSettings.PrinterResolution.Y;
ModifyWorldTransform(fmtRange.hdc, ref par, MWT_LEFTMULTIPLY);
IntPtr res = IntPtr.Zero;
IntPtr wparam = IntPtr.Zero;
wparam = new IntPtr(1);
//Get the pointer to the FORMATRANGE structure in memory
IntPtr lparam = IntPtr.Zero;
lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
Marshal.StructureToPtr(fmtRange, lparam, false);
//Send the rendered data for printing
res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam);
//Free the block of memory allocated
Marshal.FreeCoTaskMem(lparam);
//Release the device context handle obtained by a previous call
e.Graphics.ReleaseHdc(hdc);
//Return last + 1 character printer
return res.ToInt32();
}
I've had a problem like this, and ended up making an .XPS file and then sending that to the printer.
From your question, it sounds like you already have the process of "printing" to the xps file down, which is good since I don't know anything about the process of printing the rich text box to the xps file. In my scenaria I needed to print a dokument without using ms office, so I ended up making a XPS file, edit it in code, and then send it to the printer.
This is the code I use to send the xps-file directly to the printer:
LocalPrintServer localPrintServer = new LocalPrintServer();
var queue = localPrintServer.GetPrintQueue("NameOfPrinter");
PrintSystemJobInfo xpsPrintJob = queue.AddJob("name of print job", "my/xps/path.xps",false);
Also remember that for this code to work you need to add references to System.Printing AND "ReachFramework". Took me longer than I care to remember to find out why I couldn't access the printjob.
Most printers should support this in my experience. The common ones and it even works on the odd "barcode-printer" at our storage-department.
Related
My goal :
Saving all Window Icon Handle(HICON) from inside an HIMAGELIST as multiple image files (.png or .tiff).
My issue :
After my saving procedure some images have poor quality but some don't.
I only noticed this problem on the images of folders with subfolders / subfiles.
My attempt :
Code background:
I'm using Vanara to help me with PInvoke calls and a lot more.
The HIMAGELISTcome from a ListView using the ListViewMessage:LVM_GETIMAGELIST.
This method is part of a Shell Extension (I know, I shouldn't do that).
private void Saving()
{
var hWnd = GetListViewHWnd(); // This is the Desktop SysListView32 HWND
IntPtr lParam = IntPtr.Zero;
IntPtr pHil = SendMessage(hWnd, ListViewMessage.LVM_GETIMAGELIST, 0, ref lParam);
var sHil = new SafeHIMAGELIST(pHil); // This is the IMAGELIST of the ListView
var imageCount = sHil.Interface.GetImageCount(); // sHil.Interface == IImageList Interface
for (int i = 0; i < imageCount; i++)
{
using (var fs = File.OpenWrite(#"C:\Users\Julien\Desktop\Icons\" + i + ".tiff"))
{
using (SafeHICON sHIcon = sHil.Interface.GetIcon(i, IMAGELISTDRAWFLAGS.ILD_NORMAL))
{
var bmpS = Imaging.CreateBitmapSourceFromHIcon(
sHIcon.DangerousGetHandle(),
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
BitmapEncoder enc = new TiffBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bmpS));
enc.Save(fs);
}
}
}
sHil.Dispose();
}
Also :
var bmp = Bitmap.FromHicon(sHIcon.DangerousGetHandle());
bmp.Save(fs);
FAQ :
Why I am using the listview imagelist and not SHGetFileInfo ?
Because SHGetFileInfo will give me an HICON like that :
for a folder that in reality look like this :
What about passing SHGFI_SYSICONINDEX in your SHGetFileInfo ?
Same thing, the icons of non-empty folders is not stored in the System Image List.
Since I can wrote my extension in C++ I am open to any solution written in C++ too.
Edit :
I tried to draw those glitched images using IImageList.Draw() and it seem to work. So clearly the problem come from how I create an image from an HICON.
var hdc = GetDC(notepadHWnd);
var dp = new IMAGELISTDRAWPARAMS(
hdc,
new RECT(73, 73, 73, 73), 12,
COLORREF.None,
IMAGELISTDRAWFLAGS.ILD_NORMAL);
sHil.Interface.Draw(dp);
As I am stubborn I insisted with the IMAGELIST of the desktop listview.
I managed to get the icons / thumbnails from it. By drawing them in a in-memory device context.
No more glitched images.
private void Saving()
{
var hWnd = GetListViewHWnd(); // Desktop SysListView32 HWND
IntPtr lParam = IntPtr.Zero;
IntPtr pHil = SendMessage(hWnd, ListViewMessage.LVM_GETIMAGELIST, 0, ref lParam);
var sHil = new SafeHIMAGELIST(pHil); // IMAGELIST of the ListView
sHil.Interface.GetIconSize(out var cx, out var cy);
var imageCount = sHil.Interface.GetImageCount(); // IImageList Interface
var desktopHdc = new SafeHDC(GetDC(GetListViewHWnd()).DangerousGetHandle());
var inMemoryHdc = CreateCompatibleDC(desktopHdc);
for (int i = 0; i < imageCount; i++)
{
var inMemoryBmp = CreateCompatibleBitmap(desktopHdc, cx, cy);
SelectObject(inMemoryHdc, inMemoryBmp);
var ilDp = new IMAGELISTDRAWPARAMS(
inMemoryHdc,
new RECT(0, 0, 0, 0),
i,
COLORREF.None,
IMAGELISTDRAWFLAGS.ILD_NORMAL);
sHil.Interface.Draw(ilDp);
var bmpS = Imaging.CreateBitmapSourceFromHBitmap(
inMemoryBmp.DangerousGetHandle(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
using (var fs = File.OpenWrite(#"C:\Users\Julien\Desktop\Icons\" + i + ".png"))
{
BitmapEncoder enc = new PngBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bmpS));
enc.Save(fs);
}
inMemoryBmp.Dispose();
}
sHil.Dispose();
desktopHdc.Dispose();
inMemoryHdc.Dispose();
}
But as Jonathan Potter said it is not a good idea :
A combination of IShellItemImageFactory and SHCreateItemFromIDList for example seem better.
I need to change my screen capture code to get a pixel array instead of a Bitmap.
I change the code to this:
BitBlt > Image.FromHbitmap(pointer) > LockBits > pixel array
But, I'm checking if it's possible to cut some middle man, and have something like this:
BitBlt > Marshal.Copy > pixel array
Or even:
WinApi method that gets the screen region as a pixel array
So far, I tried to use this code, without success:
public static byte[] CaptureAsArray(Size size, int positionX, int positionY)
{
var hDesk = GetDesktopWindow();
var hSrce = GetWindowDC(hDesk);
var hDest = CreateCompatibleDC(hSrce);
var hBmp = CreateCompatibleBitmap(hSrce, (int)size.Width, (int)size.Height);
var hOldBmp = SelectObject(hDest, hBmp);
try
{
new System.Security.Permissions.UIPermission(System.Security.Permissions.UIPermissionWindow.AllWindows).Demand();
var b = BitBlt(hDest, 0, 0, (int)size.Width, (int)size.Height, hSrce, positionX, positionY, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
var length = 4 * (int)size.Width * (int)size.Height;
var bytes = new byte[length];
Marshal.Copy(hBmp, bytes, 0, length);
//return b ? Image.FromHbitmap(hBmp) : null;
return bytes;
}
finally
{
SelectObject(hDest, hOldBmp);
DeleteObject(hBmp);
DeleteDC(hDest);
ReleaseDC(hDesk, hSrce);
}
return null;
}
This code gives me an System.AccessViolationException while stepping on Marshal.Copy.
Is there any more efficient way of getting screen pixels as a byte array while using BitBlt or similar screen capture methods?
EDIT:
As found in here and as suggested by CodyGray, I should use
var b = Native.BitBlt(_compatibleDeviceContext, 0, 0, Width, Height, _windowDeviceContext, Left, Top, Native.CopyPixelOperation.SourceCopy | Native.CopyPixelOperation.CaptureBlt);
var bi = new Native.BITMAPINFOHEADER();
bi.biSize = (uint)Marshal.SizeOf(bi);
bi.biBitCount = 32;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
bi.biCompression = 0;
bi.biHeight = Height;
bi.biWidth = Width;
bi.biPlanes = 1;
var data = new byte[4 * Width * Height];
Native.GetDIBits(_windowDeviceContext, _compatibleBitmap, 0, (uint)Height, data, ref bi, Native.DIB_Color_Mode.DIB_RGB_COLORS);
My data array has all the pixels of the screenshot.
Now, I'm going to test if there's any performance improvements or not.
Yeah, you can't just start accessing the raw bits of a BITMAP object through an HBITMAP (as returned by CreateCompatibleBitmap). HBITMAP is just a handle, as the name suggests. It's not a pointer in the classic "C" sense that it points to the beginning of the array. Handles are like indirect pointers.
GetDIBits is the appropriate solution to get the raw, device-independent pixel array from a bitmap that you can iterate through. But you'll still need to use the code you have to get the screen bitmap in the first place. Essentially, you want something like this. Of course, you'll need to translate it into C#, but that shouldn't be difficult, since you already know how to call WinAPI functions.
Note that you do not need to call GetDesktopWindow or GetWindowDC. Just pass NULL as the handle to GetDC; it has the same effect of returning a screen DC, which you can then use to create a compatible bitmap. In general, you should almost never call GetDesktopWindow.
I'm using DWM API for displaying thumbnail of other window in my WPF app. On most computers it works fine, but on some computers my thumbnail in app is mispositioned and smaller (it's moved a few pixels left+up and it is about 30% smaller).
For creating a thumbnail relationship I'm using this code(and dwmapi.dll):
if (DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb) != 0) return;
PSIZE size;
DwmQueryThumbnailSourceSize(m_hThumbnail, out size);
DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES
{
fVisible = true,
dwFlags = DwmApiConstants.DWM_TNP_VISIBLE | DwmApiConstants.DWM_TNP_RECTDESTINATION | DwmApiConstants.DWM_TNP_OPACITY,
opacity = 0xFF,
rcDestination = destinationRect
};
DwmUpdateThumbnailProperties(m_hThumbnail, ref props);
For positioning in my app I'm using a canvas whose position I'm obtaining using:
var generalTransform = PreviewCanvas.TransformToAncestor(App.Current.MainWindow);
var leftTopPoint = generalTransform.Transform(new Point(0, 0));
return new System.Drawing.Rectangle((int)leftTopPoint.X, (int)leftTopPoint.Y, (int)PreviewCanvas.ActualWidth, (int)PreviewCanvas.ActualHeight);
Thanks to Hans, it was problem with dip -> px conversion (I thought that WPF dimensions are represented by pixels).
So, I changed
return new System.Drawing.Rectangle(
(int)leftTopPoint.X,
(int)leftTopPoint.Y,
(int)PreviewCanvas.ActualWidth,
(int)PreviewCanvas.ActualHeight
);
to:
using (var graphics = System.Drawing.Graphics.FromHwnd(IntPtr.Zero))
{
return new System.Drawing.Rectangle(
(int)(leftTopPoint.X * graphics.DpiX / 96.0),
(int)(leftTopPoint.Y * graphics.DpiY / 96.0),
(int)(PreviewCanvas.ActualWidth * graphics.DpiX / 96.0),
(int)(PreviewCanvas.ActualHeight * graphics.DpiY / 96.0)
);
}
and now positions and sizes of thumbnails are correct on all devices.
I am writing a printing application in c#. In my application i done following steps
Created Device context (hdc)
Created and started Document StartDoc
Created and Started Page StartPage
Assigned images to context
called BitBlt and assigned conext to right hdc
EndPage(hdc)
EndDoc(hdc)
After all these steps, printing is not trigered. I want to ask that printing should be trigered itself
after all these steps or i need to trigger it by some other method?
Following is source code where CardPrinterLib is class in which i imported gdi32.dll and mapped its function
IntPtr hdc = IntPtr.Zero;
hdc = CardPrinterLib.CreateDC(null, ps.PrinterName, null, IntPtr.Zero);
CardPrinterLib.DOCINFO docinfo = new CardPrinterLib.DOCINFO();
docinfo.cbSize = Marshal.SizeOf(docinfo);
docinfo.pDocName = "PrinterTest";
docinfo.pOutputFile = null;
docinfo.pDataType = null;
docinfo.fwType = 0;
if (CardPrinterLib.StartDoc(hdc, ref docinfo) > 0)
{
if (CardPrinterLib.StartPage(hdc) > 0)
{
Bitmap bmpFrontCard = (Bitmap)imgFrontCard;
Graphics grFrontCard = this.CreateGraphics();
IntPtr dcFrontCard = grFrontCard.GetHdc();
IntPtr chdcFrontCard = CardPrinterLib.CreateCompatibleDC(dcFrontCard);
CardPrinterLib.SelectObject(chdcFrontCard, bmpFrontCard.GetHbitmap());
Graphics ghdcFrontCard = Graphics.FromHdc(chdcFrontCard);
grFrontCard.ReleaseHdc(dcFrontCard);
IntPtr hhdcFrontCard = ghdcFrontCard.GetHdc();
bool resultFrontCard = CardPrinterLib.BitBlt(hdc, 0, 0, 994, 624, hhdcFrontCard, 0, 0, 13369376);
CardPrinterLib.EndPage(hdc);
}
CardPrinterLib.EndDoc(hdc);
CardPrinterLib.DeleteDC(hdc);
I have an application which I have made a 256 x 256 Windows Vista icon for.
I was wondering how I would be able to use a 256x256 PNG file in the ico file used as the application icon and show it in a picture box on a form.
I am using VB.NET, but answers in C# are fine. I'm thinking I may have to use reflection.
I am not sure if this is even possible in Windows XP and may need Windows Vista APIs
Today, I made a very nice function for extracting the 256x256 Bitmaps from Vista icons.
Like you, Nathan W, I use it to display the large icon as a Bitmap in "About" box. For example, this code gets Vista icon as PNG image, and displays it in a 256x256 PictureBox:
picboxAppLogo.Image = ExtractVistaIcon(myIcon);
This function takes Icon object as a parameter. So, you can use it with any icons - from resources, from files, from streams, and so on. (Read below about extracting EXE icon).
It runs on any OS, because it does not use any Win32 API, it is 100% managed code :-)
// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx
// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx
Bitmap ExtractVistaIcon(Icon icoIcon)
{
Bitmap bmpPngExtracted = null;
try
{
byte[] srcBuf = null;
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{ icoIcon.Save(stream); srcBuf = stream.ToArray(); }
const int SizeICONDIR = 6;
const int SizeICONDIRENTRY = 16;
int iCount = BitConverter.ToInt16(srcBuf, 4);
for (int iIndex=0; iIndex<iCount; iIndex++)
{
int iWidth = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex];
int iHeight = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex + 1];
int iBitCount = BitConverter.ToInt16(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 6);
if (iWidth == 0 && iHeight == 0 && iBitCount == 32)
{
int iImageSize = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 8);
int iImageOffset = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 12);
System.IO.MemoryStream destStream = new System.IO.MemoryStream();
System.IO.BinaryWriter writer = new System.IO.BinaryWriter(destStream);
writer.Write(srcBuf, iImageOffset, iImageSize);
destStream.Seek(0, System.IO.SeekOrigin.Begin);
bmpPngExtracted = new Bitmap(destStream); // This is PNG! :)
break;
}
}
}
catch { return null; }
return bmpPngExtracted;
}
IMPORTANT! If you want to load this icon directly from EXE file, then you CAN'T use Icon.ExtractAssociatedIcon(Application.ExecutablePath) as a parameter, because .NET function ExtractAssociatedIcon() is so stupid, it extracts ONLY 32x32 icon!
Instead, you better use the whole IconExtractor class, created by Tsuda Kageyu (http://www.codeproject.com/KB/cs/IconExtractor.aspx). You can slightly simplify this class, to make it smaller. Use IconExtractor this way:
// Getting FILL icon set from EXE, and extracting 256x256 version for logo...
using (TKageyu.Utils.IconExtractor IconEx = new TKageyu.Utils.IconExtractor(Application.ExecutablePath))
{
Icon icoAppIcon = IconEx.GetIcon(0); // Because standard System.Drawing.Icon.ExtractAssociatedIcon() returns ONLY 32x32.
picboxAppLogo.Image = ExtractVistaIcon(icoAppIcon);
}
Note: I'm still using my ExtractVistaIcon() function here, because I don't like how IconExtractor handles this job - first, it extracts all icon formats by using IconExtractor.SplitIcon(icoAppIcon), and then you have to know the exact 256x256 icon index to get the desired vista-icon. So, using my ExtractVistaIcon() here is much faster and simplier way :)
Found info here. To get the large Vista icon, you need to use Shell32's SHGetFileInfo method. I've copied the relevant text below, of course you'll want to replace the filename variable with "Assembly.GetExecutingAssembly().Location".
using System.Runtime.InteropServices;
A bunch of constants we will use in the call to SHGetFileInfo() to specify the size of the icon we wish to retrieve:
// 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;
The SHFILEINFO structure is very important as it will be our handle to various file information, among which is the graphic icon.
// 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;
};
The final preparation for the unmanaged code is to define the signature of SHGetFileInfo, which is located inside the popular Shell32.dll:
// The signature of SHGetFileInfo (located in Shell32.dll)
[DllImport("Shell32.dll")]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, uint uFlags);
Now that we have everything prepared, it's time to make the call to the function and display the icon that we retrieved. The object that will be retrieved is an Icon type (System.Drawing.Icon) but we want to display it in a PictureBox so we'll convert the Icon to a Bitmap using the ToBitmap() method.
But first of all there are 3 controls you need to add to the form, a Button btnExtract that has "Extract Icon" for its Text property, picIconSmall which is a PictureBox and a picIconLarge which is also a PictureBox. That's because we will get two icons sizes. Now double click btnExtract in Visual Studio's Design view and you'll get to its Click event. Inside it is the rest of the code:
private void btnExtract_Click(object sender, EventArgs e)
{
// Will store a handle to the small icon
IntPtr hImgSmall;
// Will store a handle to the large icon
IntPtr hImgLarge;
SHFILEINFO shinfo = new SHFILEINFO();
// Open the file that we wish to extract the icon from
if(openFile.ShowDialog() == DialogResult.OK)
{
// Store the file name
string FileName = openFile.FileName;
// Sore the icon in this myIcon object
System.Drawing.Icon myIcon;
// Get a handle to the small icon
hImgSmall = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_SMALLICON);
// Get the small icon from the handle
myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
// Display the small icon
picIconSmall.Image = myIcon.ToBitmap();
// Get a handle to the large icon
hImgLarge = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON);
// Get the large icon from the handle
myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
// Display the large icon
picIconLarge.Image = myIcon.ToBitmap();
}
}
UPDATE: found even more info here.
None of the above answers handle Vista Icons - only small (32x32) and large (48x48)
There is a library that handles Vista Icons here
...it looks quite complicated due to the dual-png alpha channel format.
I will try to make a concise answer in vb .net but it may take some time.
Having the same problem of displaying the 256*256*32 image from an ICO file in a picture box, I found the solution from SAL80 the most efficient one (and almost working). However, the original code doesn't support images stored as BMP (the large icon is usually PNG, but not always...).
Here is my version for future references. The code to create the bitmap is also slightly simpler :
/// <summary>
/// Extracts the large Vista icon from a ICO file
/// </summary>
/// <param name="srcBuf">Bytes of the ICO file</param>
/// <returns>The large icon or null if not found</returns>
private static Bitmap ExtractVistaIcon(byte[] srcBuf)
{
const int SizeIcondir = 6;
const int SizeIcondirentry = 16;
// Read image count from ICO header
int iCount = BitConverter.ToInt16(srcBuf, 4);
// Search for a large icon
for (int iIndex = 0; iIndex < iCount; iIndex++)
{
// Read image information from image directory entry
int iWidth = srcBuf[SizeIcondir + SizeIcondirentry * iIndex];
int iHeight = srcBuf[SizeIcondir + SizeIcondirentry * iIndex + 1];
int iBitCount = BitConverter.ToInt16(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 6);
// If Vista icon
if (iWidth == 0 && iHeight == 0 && iBitCount == 32)
{
// Get image data position and length from directory
int iImageSize = BitConverter.ToInt32(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 8);
int iImageOffset = BitConverter.ToInt32(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 12);
// Check if the image has a PNG signature
if (srcBuf[iImageOffset] == 0x89 && srcBuf[iImageOffset+1] == 0x50 && srcBuf[iImageOffset+2] == 0x4E && srcBuf[iImageOffset+3] == 0x47)
{
// the PNG data is stored directly in the file
var x = new MemoryStream(srcBuf, iImageOffset, iImageSize, false, false);
return new Bitmap(x);
}
// Else it's bitmap data with a partial bitmap header
// Read size from partial header
int w = BitConverter.ToInt32(srcBuf, iImageOffset + 4);
// Create a full header
var b = new Bitmap(w, w, PixelFormat.Format32bppArgb);
// Copy bits into bitmap
BitmapData bmpData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.WriteOnly, b.PixelFormat);
Marshal.Copy(srcBuf, iImageOffset + Marshal.SizeOf(typeof(Bitmapinfoheader)), bmpData.Scan0, b.Width*b.Height*4);
b.UnlockBits(bmpData);
return b;
}
}
return null;
}
Have a look at the Windows icon functions that are available. There's also an overview that mentions querying for different icon sizes. There's a Dream.In.Code forum thread for using the APIs in C# as well as a Pinvoke.net reference.