.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
相关产品推荐
相关产品推荐

