如何在windows-rs中初始化无Default trait的IWICBitmapFrameEncode?
使用windows-rs处理IWICBitmapFrameEncode初始化与JPG编码问题
常规初始化场景(无问题)
使用windows-rs时,大部分Windows API对象的初始化都很顺畅:
- 基础结构体默认初始化:
let bitmap = BITMAP::default(); // 初始化BITMAP对象
- 结构体字段填充(剩余字段用默认值):
let prop1 = D2D1_RENDER_TARGET_PROPERTIES { dpiX: Default::default(), dpiY: Default::default(), ..Default::default() };
- COM对象通过函数初始化(比如WIC工厂、编码器、流):
let factory: IWICImagingFactory = CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER)?; let encoder = factory.CreateEncoder(&GUID_ContainerFormatJpeg, &GUID_VendorMicrosoft)?; let stream: IWICStream = factory.CreateStream()?; stream.InitializeFromMemory(&output)?; encoder.Initialize(&stream, WICBitmapEncoderNoCache)?;
IWICBitmapFrameEncode初始化困境
但处理IWICBitmapFrameEncode时遇到了问题:C++里可以直接声明为NULL,后续通过CreateNewFrame接收对象:
IWICBitmapFrameEncode *pFrameEncode = NULL; // C++中这样就完成初始化 hr = pEncoder->CreateNewFrame(&pFrameEncode, NULL); // 用它接收返回值
Rust里无法直接这么做,尝试了多种方法均失败:
let frame = IWICBitmapFrameEncode::default(); // 找不到default实现 let frame: IWICBitmapFrameEncode = Default::default(); // 同样找不到default实现 let frame = IWICBitmapFrameEncode::Initialize(&self, None); // 无法提供&self参数 let frame: IWICBitmapFrameEncode; frame.Initialize(None); // 编译器报错:未初始化绑定`frame`
IWICBitmapFrameEncode的定义如下:
pub struct IWICBitmapFrameEncode(pub ::windows::core::IUnknown); impl IWICBitmapFrameEncode { #[doc = "*Required features: `\"Win32_System_Com_StructuredStorage\"`*"] #[cfg(feature = "Win32_System_Com_StructuredStorage")] pub unsafe fn Initialize<P0>(&self, piencoderoptions: P0) -> ::windows::core::Result<()>
当前代码与内存违规问题
需求是将剪贴板中的位图编码为JPG数据,目前代码能编译,但在frame.SetPixelFormat处触发内存违规异常,代码如下:
fn clipboard_bmp_to_jpg() -> std::result::Result<(), Box<dyn std::error::Error>> { unsafe { if (!OpenClipboard(None)).into() { println!("open error"); } let bitmap = BITMAP::default(); let hdl = GetClipboardData(2)?; let h_bmp = HBITMAP(hdl.0); let mut rst = GetObjectW(h_bmp, std::mem::size_of::<BITMAP>() as _, Some(&bitmap as *const BITMAP as _)); println!("{},{}", rst, bitmap.bmWidth); println!("{},{}", bitmap.bmBitsPixel, bitmap.bmWidthBytes); let num_bytes = (bitmap.bmWidthBytes*bitmap.bmHeight) as usize; let mut pixels: Vec<u8> = Vec::with_capacity(num_bytes); pixels.set_len(num_bytes); let mut output: Vec<u8> = Vec::with_capacity(num_bytes); output.set_len(num_bytes); rst = GetBitmapBits(h_bmp, num_bytes as _, pixels.as_mut_ptr() as _); println!("{},{}", rst, num_bytes); let factory: IWICImagingFactory = CoCreateInstance(&CLSID_WICImagingFactory,None,CLSCTX_INPROC_SERVER)?; let encoder = factory.CreateEncoder(&GUID_ContainerFormatJpeg, &GUID_VendorMicrosoft)?; let stream: IWICStream = factory.CreateStream()?; stream.InitializeFromMemory(&output)?; encoder.Initialize(&stream, WICBitmapEncoderNoCache)?; let mut frame = None; let mut props = None; let rst2 = encoder.CreateNewFrame(&mut frame, &mut props); let frame = frame.ok_or(Error::from(E_FAIL))?; //let props = props.ok_or(Error::from(E_FAIL))?; //let frame: IWICBitmapFrameEncode = None.unwrap(); //let frameopt = Some(frame); //let rst2 = encoder.CreateNewFrame(&frameopt as *const Option<IWICBitmapFrameEncode> as _, &mut None as _); if rst2.is_err() { println!("error CreateNewFrame"); } let rst3 = frame.Initialize(None); if rst3.is_err() { println!("error Initialize"); } frame.SetSize(bitmap.bmWidth as _, bitmap.bmHeight as _)?; frame.SetPixelFormat(&GUID_WICPixelFormatDontCare as *const GUID as _)?; // 此处触发内存违规异常 let source = IWICBitmapSource::from_raw(pixels.as_mut_ptr() as _); let rect = WICRect { X: 0, Y: 0, Width: bitmap.bmWidth, Height: bitmap.bmHeight, }; let rst4 = frame.WriteSource(&source, &rect as _); if rst4.is_err() { println!("error WriteSource"); } frame.Commit()?; let rst5 = encoder.Commit(); if rst5.is_err() { println!("error WriteSource"); } } Ok(()) }
内容的提问来源于stack exchange,提问作者abcjeff
相关产品推荐
相关产品推荐

