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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 17:59:55