public virtual long CopyTo(UnsafeNativeMethods.IStream pstm, long cb, long[] pcbRead) { int bufsize = 4096; // one page IntPtr buffer = Marshal.AllocHGlobal(bufsize); if (buffer == IntPtr.Zero) throw new OutOfMemoryException(); long written = 0; try { while (written < cb) { int toRead = bufsize; if (written + toRead > cb) toRead = (int) (cb - written); int read = Read(buffer, toRead); if (read == 0) break; if (pstm.Write(buffer, read) != read) { throw EFail("Wrote an incorrect number of bytes"); } written += read; } } finally { Marshal.FreeHGlobal(buffer); } if (pcbRead != null && pcbRead.Length > 0) { pcbRead[0] = written; } return written; }
public void Dispose() { UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, _handle)); }
internal static extern int GdipSaveImageToStream(HandleRef image, UnsafeNativeMethods.IStream stream, ref Guid classId, HandleRef encoderParams);
/// <include file='doc\Icon.uex' path='docs/doc[@for="Icon.Initialize"]/*' /> /// <devdoc> /// Initializes this Image object. This is identical to calling the image's /// constructor with picture, but this allows non-constructor initialization, /// which may be necessary in some instances. /// </devdoc> private unsafe void Initialize(int width, int height) { if (iconData == null || handle != IntPtr.Zero) { throw new InvalidOperationException(SR.GetString(SR.IllegalState, GetType().Name)); } if (iconData.Length < Marshal.SizeOf(typeof(SafeNativeMethods.ICONDIR))) { throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "Icon")); } // Get the correct width / height // if (width == 0) { width = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CXICON); } if (height == 0) { height = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CYICON); } if (bitDepth == 0) { IntPtr dc = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef); bitDepth = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), SafeNativeMethods.BITSPIXEL); bitDepth *= UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), SafeNativeMethods.PLANES); UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, dc)); // If the bitdepth is 8, make it 4. Why? Because windows does not // choose a 256 color icon if the display is running in 256 color mode // because of palette flicker. // if (bitDepth == 8) { bitDepth = 4; } } fixed(byte *pbIconData = iconData) { SafeNativeMethods.ICONDIR *pIconDir = (SafeNativeMethods.ICONDIR *)pbIconData; if (pIconDir->idReserved != 0 || pIconDir->idType != 1 || pIconDir->idCount == 0) { throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "Icon")); } SafeNativeMethods.ICONDIRENTRY *pIconDirEntry = &pIconDir->idEntries; SafeNativeMethods.ICONDIRENTRY *pBestFit = null; int bestBitDepth = 0; int icondirEntrySize = Marshal.SizeOf(typeof(SafeNativeMethods.ICONDIRENTRY)); Debug.Assert((icondirEntrySize * pIconDir->idCount) < iconData.Length, "Illegal number of ICONDIRENTRIES"); if ((icondirEntrySize * pIconDir->idCount) >= iconData.Length) { throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "Icon")); } for (int i = 0; i < pIconDir->idCount; i++) { int iconBitDepth = pIconDirEntry->wPlanes * pIconDirEntry->wBitCount; if (iconBitDepth == 0) { if (pIconDirEntry->bColorCount == 0) { iconBitDepth = 16; } else { iconBitDepth = 8; if (pIconDirEntry->bColorCount < 0xFF) { iconBitDepth = 4; } if (pIconDirEntry->bColorCount < 0x10) { iconBitDepth = 2; } } } // Windows rules for specifing an icon: // // 1. The icon with the closest size match. // 2. For matching sizes, the image with the closest bit depth. // 3. If there is no color depth match, the icon with the closest color depth that does not exceed the display. // 4. If all icon color depth > display, lowest color depth is chosen. // 5. color depth of > 8bpp are all equal. // 6. Never choose an 8bpp icon on an 8bpp system. // if (pBestFit == null) { pBestFit = pIconDirEntry; bestBitDepth = iconBitDepth; } else { int bestDelta = Math.Abs(pBestFit->bWidth - width) + Math.Abs(pBestFit->bHeight - height); int thisDelta = Math.Abs(pIconDirEntry->bWidth - width) + Math.Abs(pIconDirEntry->bHeight - height); if (thisDelta < bestDelta) { pBestFit = pIconDirEntry; bestBitDepth = iconBitDepth; } else if (thisDelta == bestDelta && (iconBitDepth <= bitDepth && iconBitDepth > bestBitDepth || bestBitDepth > bitDepth && iconBitDepth < bestBitDepth)) { pBestFit = pIconDirEntry; bestBitDepth = iconBitDepth; } } pIconDirEntry++; } Debug.Assert(pBestFit->dwImageOffset >= 0 && (pBestFit->dwImageOffset + pBestFit->dwBytesInRes) <= iconData.Length, "Illegal offset/length for the Icon data"); if (pBestFit->dwImageOffset < 0 || (pBestFit->dwImageOffset + pBestFit->dwBytesInRes) > iconData.Length) { throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "Icon")); } handle = SafeNativeMethods.CreateIconFromResourceEx(pbIconData + pBestFit->dwImageOffset, pBestFit->dwBytesInRes, true, 0x00030000, 0, 0, 0); if (handle == IntPtr.Zero) { throw new Win32Exception(); } } }
internal static extern int GdipLoadImageFromStreamICM(UnsafeNativeMethods.IStream stream, out IntPtr image);
internal static extern int GdipRecordMetafileStreamI(UnsafeNativeMethods.IStream stream, HandleRef referenceHdc, int emfType, ref GPRECT frameRect, int frameUnit, string description, out IntPtr metafile);
internal static extern int GdipGetMetafileHeaderFromStream(UnsafeNativeMethods.IStream stream, IntPtr header);
internal static extern int GdipCreateMetafileFromStream(UnsafeNativeMethods.IStream stream, out IntPtr metafile);
internal static extern int GdipCreateBitmapFromStreamICM(UnsafeNativeMethods.IStream stream, out IntPtr bitmap);
// Initializes this Image object. This is identical to calling the image's // constructor with picture, but this allows non-constructor initialization, // which may be necessary in some instances. private unsafe void Initialize(int width, int height) { if (_iconData == null || _handle != IntPtr.Zero) { throw new InvalidOperationException(SR.Format(SR.IllegalState, GetType().Name)); } if (_iconData.Length < sizeof(SafeNativeMethods.ICONDIR)) { throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon))); } // Get the correct width and height. if (width == 0) { width = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CXICON); } if (height == 0) { height = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CYICON); } if (s_bitDepth == 0) { IntPtr dc = Interop.User32.GetDC(IntPtr.Zero); s_bitDepth = Interop.Gdi32.GetDeviceCaps(dc, Interop.Gdi32.DeviceCapability.BITSPIXEL); s_bitDepth *= Interop.Gdi32.GetDeviceCaps(dc, Interop.Gdi32.DeviceCapability.PLANES); Interop.User32.ReleaseDC(IntPtr.Zero, dc); // If the bitdepth is 8, make it 4 because windows does not // choose a 256 color icon if the display is running in 256 color mode // due to palette flicker. if (s_bitDepth == 8) { s_bitDepth = 4; } } fixed(byte *b = _iconData) { SafeNativeMethods.ICONDIR *dir = (SafeNativeMethods.ICONDIR *)b; if (dir->idReserved != 0 || dir->idType != 1 || dir->idCount == 0) { throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon))); } byte bestWidth = 0; byte bestHeight = 0; if (sizeof(SafeNativeMethods.ICONDIRENTRY) * (dir->idCount - 1) + sizeof(SafeNativeMethods.ICONDIR) > _iconData.Length) { throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon))); } var entries = new ReadOnlySpan <SafeNativeMethods.ICONDIRENTRY>(&dir->idEntries, dir->idCount); foreach (SafeNativeMethods.ICONDIRENTRY entry in entries) { bool fUpdateBestFit = false; uint iconBitDepth; if (entry.bColorCount != 0) { iconBitDepth = 4; if (entry.bColorCount < 0x10) { iconBitDepth = 1; } } else { iconBitDepth = entry.wBitCount; } // If it looks like if nothing is specified at this point then set the bits per pixel to 8. if (iconBitDepth == 0) { iconBitDepth = 8; } // Windows rules for specifing an icon: // // 1. The icon with the closest size match. // 2. For matching sizes, the image with the closest bit depth. // 3. If there is no color depth match, the icon with the closest color depth that does not exceed the display. // 4. If all icon color depth > display, lowest color depth is chosen. // 5. color depth of > 8bpp are all equal. // 6. Never choose an 8bpp icon on an 8bpp system. if (_bestBytesInRes == 0) { fUpdateBestFit = true; } else { int bestDelta = Math.Abs(bestWidth - width) + Math.Abs(bestHeight - height); int thisDelta = Math.Abs(entry.bWidth - width) + Math.Abs(entry.bHeight - height); if ((thisDelta < bestDelta) || (thisDelta == bestDelta && (iconBitDepth <= s_bitDepth && iconBitDepth > _bestBitDepth || _bestBitDepth > s_bitDepth && iconBitDepth < _bestBitDepth))) { fUpdateBestFit = true; } } if (fUpdateBestFit) { bestWidth = entry.bWidth; bestHeight = entry.bHeight; _bestImageOffset = entry.dwImageOffset; _bestBytesInRes = entry.dwBytesInRes; _bestBitDepth = iconBitDepth; } } if (_bestImageOffset > int.MaxValue) { throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon))); } if (_bestBytesInRes > int.MaxValue) { throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER); } uint endOffset; try { endOffset = checked (_bestImageOffset + _bestBytesInRes); } catch (OverflowException) { throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER); } if (endOffset > _iconData.Length) { throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon))); } // Copy the bytes into an aligned buffer if needed. if ((_bestImageOffset % IntPtr.Size) != 0) { // Beginning of icon's content is misaligned. byte[] alignedBuffer = ArrayPool <byte> .Shared.Rent((int)_bestBytesInRes); Array.Copy(_iconData, _bestImageOffset, alignedBuffer, 0, _bestBytesInRes); fixed(byte *pbAlignedBuffer = alignedBuffer) { _handle = SafeNativeMethods.CreateIconFromResourceEx(pbAlignedBuffer, _bestBytesInRes, true, 0x00030000, 0, 0, 0); } ArrayPool <byte> .Shared.Return(alignedBuffer); } else { try { _handle = SafeNativeMethods.CreateIconFromResourceEx(checked (b + _bestImageOffset), _bestBytesInRes, true, 0x00030000, 0, 0, 0); } catch (OverflowException) { throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER); } } if (_handle == IntPtr.Zero) { throw new Win32Exception(); } } }
/// <include file='doc\Icon.uex' path='docs/doc[@for="Icon.Initialize"]/*' /> /// <devdoc> /// Initializes this Image object. This is identical to calling the image's /// constructor with picture, but this allows non-constructor initialization, /// which may be necessary in some instances. /// </devdoc> private unsafe void Initialize(int width, int height) { if (_iconData == null || _handle != IntPtr.Zero) { throw new InvalidOperationException(SR.Format(SR.IllegalState, GetType().Name)); } int icondirSize = Marshal.SizeOf(typeof(SafeNativeMethods.ICONDIR)); if (_iconData.Length < icondirSize) { throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", "Icon")); } // Get the correct width / height // if (width == 0) { width = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CXICON); } if (height == 0) { height = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CYICON); } if (s_bitDepth == 0) { IntPtr dc = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef); s_bitDepth = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), SafeNativeMethods.BITSPIXEL); s_bitDepth *= UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), SafeNativeMethods.PLANES); UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, dc)); // If the bitdepth is 8, make it 4. Why? Because windows does not // choose a 256 color icon if the display is running in 256 color mode // because of palette flicker. // if (s_bitDepth == 8) { s_bitDepth = 4; } } fixed(byte *pbIconData = _iconData) { short idReserved = GetShort(pbIconData); short idType = GetShort(pbIconData + 2); short idCount = GetShort(pbIconData + 4); if (idReserved != 0 || idType != 1 || idCount == 0) { throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", "Icon")); } SafeNativeMethods.ICONDIRENTRY EntryTemp; byte bestWidth = 0; byte bestHeight = 0; //int bestBitDepth = 0; byte *pbIconDirEntry = unchecked (pbIconData + 6); int icondirEntrySize = Marshal.SizeOf(typeof(SafeNativeMethods.ICONDIRENTRY)); if ((icondirEntrySize * (idCount - 1) + icondirSize) > _iconData.Length) { throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", "Icon")); } for (int i = 0; i < idCount; i++) { // // Fill in EntryTemp // EntryTemp.bWidth = pbIconDirEntry[0]; EntryTemp.bHeight = pbIconDirEntry[1]; EntryTemp.bColorCount = pbIconDirEntry[2]; EntryTemp.bReserved = pbIconDirEntry[3]; EntryTemp.wPlanes = GetShort(pbIconDirEntry + 4); EntryTemp.wBitCount = GetShort(pbIconDirEntry + 6); EntryTemp.dwBytesInRes = GetInt(pbIconDirEntry + 8); EntryTemp.dwImageOffset = GetInt(pbIconDirEntry + 12); // // // bool fUpdateBestFit = false; int iconBitDepth = 0; if (EntryTemp.bColorCount != 0) { iconBitDepth = 4; if (EntryTemp.bColorCount < 0x10) { iconBitDepth = 1; } } else { iconBitDepth = EntryTemp.wBitCount; } // it looks like if nothing is specified at this point, bpp is 8... if (iconBitDepth == 0) { iconBitDepth = 8; } // Windows rules for specifing an icon: // // 1. The icon with the closest size match. // 2. For matching sizes, the image with the closest bit depth. // 3. If there is no color depth match, the icon with the closest color depth that does not exceed the display. // 4. If all icon color depth > display, lowest color depth is chosen. // 5. color depth of > 8bpp are all equal. // 6. Never choose an 8bpp icon on an 8bpp system. // if (0 == _bestBytesInRes) { fUpdateBestFit = true; } else { int bestDelta = Math.Abs(bestWidth - width) + Math.Abs(bestHeight - height); int thisDelta = Math.Abs(EntryTemp.bWidth - width) + Math.Abs(EntryTemp.bHeight - height); if ((thisDelta < bestDelta) || (thisDelta == bestDelta && (iconBitDepth <= s_bitDepth && iconBitDepth > _bestBitDepth || _bestBitDepth > s_bitDepth && iconBitDepth < _bestBitDepth))) { fUpdateBestFit = true; } } if (fUpdateBestFit) { bestWidth = EntryTemp.bWidth; bestHeight = EntryTemp.bHeight; _bestImageOffset = EntryTemp.dwImageOffset; _bestBytesInRes = EntryTemp.dwBytesInRes; _bestBitDepth = iconBitDepth; } pbIconDirEntry += icondirEntrySize; } if (_bestImageOffset < 0) { throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", "Icon")); } if (_bestBytesInRes < 0) { throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER); } int endOffset; try { endOffset = checked (_bestImageOffset + _bestBytesInRes); } catch (OverflowException) { throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER); } if (endOffset > _iconData.Length) { throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", "Icon")); } // See DevDivBugs 17509. Copying bytes into an aligned buffer if needed if ((_bestImageOffset % IntPtr.Size) != 0) { // Beginning of icon's content is misaligned byte[] alignedBuffer = new byte[_bestBytesInRes]; Array.Copy(_iconData, _bestImageOffset, alignedBuffer, 0, _bestBytesInRes); fixed(byte *pbAlignedBuffer = alignedBuffer) { _handle = SafeNativeMethods.CreateIconFromResourceEx(pbAlignedBuffer, _bestBytesInRes, true, 0x00030000, 0, 0, 0); } } else { try { _handle = SafeNativeMethods.CreateIconFromResourceEx(checked (pbIconData + _bestImageOffset), _bestBytesInRes, true, 0x00030000, 0, 0, 0); } catch (OverflowException) { throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER); } } if (_handle == IntPtr.Zero) { throw new Win32Exception(); } } }