c# - programa - SHGetImageList-SHIL_JUMBO para iconos más pequeños(32,32)
poner icono a programa c# (3)
En mi código, obtengo una lista de imágenes a través de la función SHGETImageList con el tamaño SHIL_JUMBO.
IImageList iml;
var hres = SHGetImageList(SHIL_JUMBO, ref iidImageList, out iml);
IntPtr hIcon = IntPtr.Zero;
iml.GetIcon(i, ILD_TRANSPARENT | ILD_IMAGE, ref hIcon);
Icon ico = (Icon)System.Drawing.Icon.FromHandle(hIcon).Clone();
ShellAPI.DestroyIcon(hIcon);
Todo está bien, pero cuando tiene que obtener íconos más pequeños (cuando no tienen un tamaño para 256x256), la función GetIcon me devuelve un ícono con el tamaño de 256x256 pero con el ícono de tamaño 32x32 en la esquina superior izquierda. Quiero cambiar el tamaño de este icono al nuevo tamaño (256 x 256).
No tengo ninguna información sobre cómo hacer que el sistema cambie el tamaño de mi icono a 256 x 256. Todas las funciones en iml (como GetImageInfo, GetImageRect) para este tamaño devuelven una estructura vacía.
Es posible obtener información de que este icono es más pequeño y puedo obtener un icono de otra fuente.
He ejecutado tu ejemplo usando
const string IID_IImageList = "46EB5926-582E-4017-9FDF-E8998DAA0950";
const string IID_IImageList2 = "192B9D83-50FC-457B-90A0-2B82A8B5DAE1";
definido en CommonControls.h Al ejecutarse:
IEnumerable<int> shils = new int[]{
ShellAPI.SHIL_EXTRALARGE,
ShellAPI.SHIL_JUMBO,
ShellAPI.SHIL_SYSSMALL,
ShellAPI.SHIL_LARGE,
ShellAPI.SHIL_SMALL,
ShellAPI.SHIL_LAST
};
ShellAPI.IImageList ppv = null;
Guid guil = new Guid(IID_IImageList2);//or IID_IImageList
foreach (int iil in shils)
{
ShellAPI.SHGetImageList(iil, ref guil, ref ppv);
int noImages = 0;
ppv.GetImageCount(ref noImages);
//...
}
El recuento de imágenes se mantiene constante. Por lo tanto, debo estar en desacuerdo con
cuando no tienen un tamaño de 256x256
Para cada tipo de lista de imágenes hay un número constante de imágenes, por lo que no faltan iconos para la configuración jumbo.
He persistido todos los iconos encontrados con todas las resoluciones (16x16,32x32,48x48,256x256). La relación de aspecto es idéntica entre todos los tamaños diferentes del mismo icono (índice de la misma imagen / resolución diferente). La relación de aspecto significa que la versión de 256x256 no es la versión de 48x48 pegada en una esquina, y el resto de relleno de fondo negro.
Además, todos los
Los íconos con el tamaño de 256x256 pero con el ícono de tamaño 32x32 en la esquina superior izquierda son de hecho imágenes superpuestas, como se puede verificar:
int currentImageListIndex; //loop by noImages above
int idx0Based=0;
ppv.GetOverlayImage(currentImageListIndex+1, ref idx0Based);
La degradación de la calidad se puede encontrar fácilmente utilizando IImageAList :: GetItemFlags y verificando el parámetro dwFlags de salida para ILIF_LOWQUALITY, msdn cita a continuación
Windows Vista y posteriores. Indica que el elemento en la lista de imágenes se generó a través de una función StretchBlt, por lo tanto, la calidad de la imagen puede haberse degradado
Parece que, desde Vista, Microsoft espera que los desarrolladores confíen en las interfaces IShellItem
e IShellItemImageFactory
. A diferencia de la implementación IImageList
de las listas de imágenes del sistema, que está muy dañada (la mayoría de los métodos fallan con E_NOTIMPL
, no se informa el tamaño de los iconos), IShellItemImageFactory
produce imágenes exactamente como se muestran en Explorer. En el caso de los iconos pequeños solicitados en tamaño "jumbo", están centrados y rodeados por un borde (al menos en Windows 7). Si bien es menos eficiente y consume más memoria que IImageList
, es probable que Explorer también lo use, por lo que no es gran cosa.
Consulte el método IShellItemImageFactory :: GetImage en MSDN para obtener más detalles.
Hay una biblioteca para .NET que admite estas interfaces: Windows® API Code Pack para Microsoft® .NET Framework .
Si bien esto no responde exactamente a su pregunta (aún no existe una forma confiable de determinar el tamaño de los íconos), creo que cambiar el tamaño de un pequeño ícono de 32x32 a 256x256 es una mala idea, y el método Explorer (redimensionar solo hasta 48x48, luego centrarlo) debería ser preferido Esto también proporcionará un comportamiento consistente que es una buena idea.
Teniendo en cuenta que preguntas como esta se han publicado en muchos lugares, y ninguna ha sido respondida durante años, me temo que solo se puede obtener más información mediante la ingeniería inversa de Windows Shell, y en particular la implementación estándar / predeterminada de IShellItemImageFactory::GetImage
. Geoff Chappell hizo un poco de ingeniería inversa de shell, así que tal vez valga la pena intentar preguntarle ...
Puede ejecutar algún código para identificar las métricas de la imagen y usar lo siguiente cuando sea necesario:
var hres = SHGetImageList(SHIL_LARGE, ref iidImageList, out iml);
SHIL_LARGE es para 32x32.
El tipo de puntero IImageList, como el que se devuelve en el parámetro ppv, se puede convertir como HIMAGELIST según sea necesario; por ejemplo, para usar en una vista de lista. A la inversa, un HIMAGELIST se puede convertir como un puntero a un IImageList. A partir de Windows Vista, SHIL_SMALL, SHIL_LARGE y SHIL_EXTRALARGE se escalan con puntos por pulgada (ppp) si el proceso está marcado como ppp . Para configurar estos tipos para que sean compatibles con ppp, llame a SetProcessDPIAware. SHIL_JUMBO se fija en 256 píxeles independientemente de la configuración compatible con ppp.
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx