You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8中如何将OleCreatePictureIndirect从DllImport转为LibraryImport

.NET 8中DllImport转LibraryImport的封送问题修复

我在.NET 8里尝试把调用OleCreatePictureIndirect的DllImport代码转换为LibraryImport,原代码如下:

internal static class PictureDispConverter
{
    [DllImport("OleAut32.dll", EntryPoint = "OleCreatePictureIndirect", ExactSpelling = true, PreserveSig = false)]
    private extern static stdole.IPictureDisp OleCreatePictureIndirect(PICTDESC picdesc, ref Guid iid, [MarshalAs(UnmanagedType.Bool)] bool fOwn);

    private static Guid iPictureDispGuid = typeof(stdole.IPictureDisp).GUID;

    [StructLayout(LayoutKind.Sequential)]
    private class PICTDESC
    {
        internal int cbSizeOfStruct = Marshal.SizeOf(typeof(PICTDESC));
        internal int picType;
        internal IntPtr hicon = IntPtr.Zero;
        internal int unused1;
        internal int unused2;

        internal PICTDESC(System.Drawing.Bitmap bitmap)
        {
            picType = 1;
            hicon = bitmap.GetHbitmap();
        }

        internal PICTDESC(System.Drawing.Icon icon)
        {
            picType = 3;
            hicon = icon.ToBitmap().GetHicon();
        }
    }

    public static stdole.IPictureDisp ToIPictureDisp(System.Drawing.Icon icon)
    {
        var pictIcon = new PICTDESC(icon);
        return OleCreatePictureIndirect(pictIcon, ref iPictureDispGuid, true);
    }

    public static stdole.IPictureDisp ToIPictureDisp(System.Drawing.Bitmap bmp)
    {
        var pictIcon = new PICTDESC(bmp);
        return OleCreatePictureIndirect(pictIcon, ref iPictureDispGuid, true);
    }
}

用Visual Studio自动转换后得到的代码:

[LibraryImport("OleAut32.dll", EntryPoint = "OleCreatePictureIndirect")]
private static partial int OleCreatePictureIndirect(PICTDESC picdesc, ref Guid iid, [MarshalAs(UnmanagedType.Bool)] bool fOwn, out stdole.IPictureDisp @return);

但出现两个错误:

  • 类型'WpfApp2.MainWindow.PictureDispConverter.PICTDESC'不被源生成P/Invoke支持,生成的源代码无法处理参数'picdesc'的封送
  • 类型'stdole.IPictureDisp'不被源生成P/Invoke支持,生成的源代码无法处理参数'@return'的封送

问题1:PICTDESC类的封送支持问题

源生成P/Invoke不支持将类作为非托管结构封送,需要把PICTDESC从类改成struct,同时调整cbSizeOfStruct的赋值逻辑(struct不能在字段初始化器中调用Marshal.SizeOf):

[StructLayout(LayoutKind.Sequential)]
private struct PICTDESC
{
    internal int cbSizeOfStruct;
    internal int picType;
    internal IntPtr hicon;
    internal int unused1;
    internal int unused2;

    internal PICTDESC(System.Drawing.Bitmap bitmap)
    {
        cbSizeOfStruct = Marshal.SizeOf(typeof(PICTDESC));
        picType = 1;
        hicon = bitmap.GetHbitmap();
        unused1 = 0;
        unused2 = 0;
    }
}

问题2:IPictureDisp接口的封送支持问题

源生成P/Invoke不直接支持out stdole.IPictureDisp这种COM接口的封送,需要改用IntPtr接收返回的COM对象指针,然后手动封送为IPictureDisp,同时要检查OleCreatePictureIndirect返回的HRESULT是否成功:

修改LibraryImport方法定义:

[LibraryImport("OleAut32.dll", EntryPoint = "OleCreatePictureIndirect", ExactSpelling = true)]
private static partial int OleCreatePictureIndirect(in PICTDESC picdesc, ref Guid iid, [MarshalAs(UnmanagedType.Bool)] bool fOwn, out IntPtr ppvObj);

然后在调用方法里处理封送和错误检查:

public static stdole.IPictureDisp ToIPictureDisp(System.Drawing.Icon icon)
{
    using var tempBmp = icon.ToBitmap();
    var pictDesc = new PICTDESC(tempBmp);
    int hr = OleCreatePictureIndirect(in pictDesc, ref iPictureDispGuid, true, out IntPtr picturePtr);
    
    // 检查HRESULT是否成功
    if (hr < 0)
    {
        Marshal.ThrowExceptionForHR(hr);
    }

    try
    {
        return Marshal.GetObjectForIUnknown(picturePtr) as stdole.IPictureDisp;
    }
    finally
    {
        // 释放IntPtr,避免内存泄漏
        Marshal.Release(picturePtr);
    }
}

public static stdole.IPictureDisp ToIPictureDisp(System.Drawing.Bitmap bmp)
{
    var pictDesc = new PICTDESC(bmp);
    int hr = OleCreatePictureIndirect(in pictDesc, ref iPictureDispGuid, true, out IntPtr picturePtr);
    
    if (hr < 0)
    {
        Marshal.ThrowExceptionForHR(hr);
    }

    try
    {
        return Marshal.GetObjectForIUnknown(picturePtr) as stdole.IPictureDisp;
    }
    finally
    {
        Marshal.Release(picturePtr);
    }
}

完整修改后的代码

internal static class PictureDispConverter
{
    [LibraryImport("OleAut32.dll", EntryPoint = "OleCreatePictureIndirect", ExactSpelling = true)]
    private static partial int OleCreatePictureIndirect(in PICTDESC picdesc, ref Guid iid, [MarshalAs(UnmanagedType.Bool)] bool fOwn, out IntPtr ppvObj);

    private static readonly Guid iPictureDispGuid = typeof(stdole.IPictureDisp).GUID;

    [StructLayout(LayoutKind.Sequential)]
    private struct PICTDESC
    {
        internal int cbSizeOfStruct;
        internal int picType;
        internal IntPtr hicon;
        internal int unused1;
        internal int unused2;

        internal PICTDESC(System.Drawing.Bitmap bitmap)
        {
            cbSizeOfStruct = Marshal.SizeOf(typeof(PICTDESC));
            picType = 1;
            hicon = bitmap.GetHbitmap();
            unused1 = 0;
            unused2 = 0;
        }
    }

    public static stdole.IPictureDisp ToIPictureDisp(System.Drawing.Icon icon)
    {
        using var tempBmp = icon.ToBitmap();
        var pictDesc = new PICTDESC(tempBmp);
        int hr = OleCreatePictureIndirect(in pictDesc, ref iPictureDispGuid, true, out IntPtr picturePtr);
        
        if (hr < 0)
        {
            Marshal.ThrowExceptionForHR(hr);
        }

        try
        {
            return Marshal.GetObjectForIUnknown(picturePtr) as stdole.IPictureDisp;
        }
        finally
        {
            Marshal.Release(picturePtr);
        }
    }

    public static stdole.IPictureDisp ToIPictureDisp(System.Drawing.Bitmap bmp)
    {
        var pictDesc = new PICTDESC(bmp);
        int hr = OleCreatePictureIndirect(in pictDesc, ref iPictureDispGuid, true, out IntPtr picturePtr);
        
        if (hr < 0)
        {
            Marshal.ThrowExceptionForHR(hr);
        }

        try
        {
            return Marshal.GetObjectForIUnknown(picturePtr) as stdole.IPictureDisp;
        }
        finally
        {
            Marshal.Release(picturePtr);
        }
    }
}

内容的提问来源于stack exchange,提问作者Weston Witt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 23:17:12