我正在从 USB 设备移植一个 C++ SDK 以通过 pinvoke 在 C# 中使用,到目前为止我取得了很好的进展,现在的问题是一个构建图像列表的函数,我可以使用它来附加到其他控件使用像SetImageList这样的函数。
我想做的就是将此列表中的所有图像保存到磁盘并稍后使用它们。
还有其他函数可以返回此列表中特定图像的索引,因此我可以传递此索引,然后将图像保存到磁盘。
使用CImageList
类实例(通过调用现有实例的方法Detach
上的GetImageList
方法CListCtrl
来获得),您可以通过调用Detach 方法HIMAGELIST
来获取句柄。
从那里您可以通过平台调用服务 (P/Invoke) 层调用底层 Windows API 。
以下假设您在HIMAGELIST
中具有此指针IntPtr
:
IntPtr imageList = ...;
首先,您需要在 .NET中声明该ImageList_GetImageCount
函数:
[DllImport("Comctl32.dll", SetLastError = true)]
static extern int ImageList_GetImageCount(IntPtr himl);
当然,将该调用的结果存储在一个变量中:
int imageCount = ImageList_GetImageCount(imageList);
您还需要能够获取有关每个图像的详细信息,因此您需要调用ImageList_GetImageInfo
:
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int left, top, right, bottom;
}
[StructLayout(LayoutKind.Sequential)]
struct IMAGEINFO
{
public IntPtr hbmImage;
public IntPtr hbmMask;
public int Unused1;
public int Unused2;
public RECT rcImage;
}
[DllImport("Comctl32.dll", SetLastError = true)]
static extern bool ImageList_GetImageInfo(IntPtr himl, int i,
ref IMAGEINFO pImageInfo);
有了这些,您可以开始循环以获取有关图像的信息:
for (int i = 0; i < imageCount; ++i)
{
// The image info.
var imageInfo = new IMAGEINFO();
// Get the call to ImageList_GetImageInfo.
if (!ImageList_GetImageInfo(imageList, i, ref imageInfo)
throw new System.ComponentModel.Win32Exception();
请注意,IMAGEINFO
结构中有一个字段,其中包含指向位图的指针(hbmImage
字段)。
这是句柄的句柄,它在 .NET 中的类HBITMAP
中具有等价物。您可以通过调用类上的静态方法在两者之间进行转换(是的,奇怪的是它不在类上):Bitmap
FromHbitmap
Image
Bitmap
using (Bitmap bitmap = Image.FromHbitmap(imageInfo.hbmImage))
{
拥有Bitmap
实例后,您可以在每个实例上调用该Save
方法将它们转储到磁盘:
bitmap.Save("<need to generate a filename>.<and extension>");
}
}
请注意,.NET 中有ImageList
该类,但无法将HIMAGELIST
句柄传递给托管实现(这会使这变得更容易)。
实际上,可以从 HIMAGELIST 句柄创建托管 ImageList。我测试了这个 2 分钟。前:
Public Shared Function ImageList_FromHIMAGELIST(cxcy As Integer, uFlags As UInteger, initSize As Integer, growSize As Integer, _
hicons() As IntPtr) As ImageList
Dim himl = ImageList_Create(cxcy, cxcy, uFlags, initSize, growSize)
If Not IsNothing(hicons) AndAlso hicons.Length > 0 Then
For Each HIcon As IntPtr In hicons
ImageList_ReplaceIcon(himl, -1, HIcon)
Next
End If
Dim NativeILType As Type = _
GetType(Button).Assembly.GetType("System.Windows.Forms.ImageList+NativeImageList", False, True)
If IsNothing(NativeILType) Then
Return Nothing
Else
Dim natObj As Object = _
Activator.CreateInstance( _
NativeILType, BindingFlags.Instance Or BindingFlags.NonPublic, Nothing, {himl}, Nothing)
If Not IsNothing(natObj) Then
Dim iml As New ImageList With {.ImageSize = New Size(cxcy, cxcy)}
iml.GetType.InvokeMember("nativeImageList", _
BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.SetField, _
Nothing, iml, {natObj})
Return iml
End If
End If
Return Nothing
End Function