1

我正在从 USB 设备移植一个 C++ SDK 以通过 pinvoke 在 C# 中使用,到目前为止我取得了很好的进展,现在的问题是一个构建图像列表的函数,我可以使用它来附加到其他控件使用像SetImageList这样的函数。

我想做的就是将此列表中的所有图像保存到磁盘并稍后使用它们。

还有其他函数可以返回此列表中特定图像的索引,因此我可以传递此索引,然后将图像保存到磁盘。

4

2 回答 2

2

使用CImageList实例(通过调用现有实例的方法DetachGetImageList方法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中具有等价物。您可以通过调用类上的静态方法在两者之间进行转换(是的,奇怪的是它不在类上):BitmapFromHbitmapImageBitmap

    using (Bitmap bitmap = Image.FromHbitmap(imageInfo.hbmImage))
    {

拥有Bitmap实例后,您可以在每个实例上调用该Save方法将它们转储到磁盘:

        bitmap.Save("<need to generate a filename>.<and extension>");
    }
}

请注意,.NET 中有ImageList该类,但无法将HIMAGELIST句柄传递给托管实现(这会使这变得更容易)。

于 2012-10-24T19:43:40.593 回答
0

实际上,可以从 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
于 2013-01-02T20:14:17.767 回答