C# IBuffer.AsStream导致无法强制转换COM对象异常
在我的Windows Phone 8应用程序中,我试图将后台代理程序(用c++/cx编写)中获取的数据发送到前台应用程序(用c#编写)。我可以成功地登记回调用,并调用C++中从C层编写的函数(在单独的后台进程中运行)。p> 我的C#函数是C# IBuffer.AsStream导致无法强制转换COM对象异常,c#,windows-phone-8,com,windows-runtime,c++-cx,C#,Windows Phone 8,Com,Windows Runtime,C++ Cx,在我的Windows Phone 8应用程序中,我试图将后台代理程序(用c++/cx编写)中获取的数据发送到前台应用程序(用c#编写)。我可以成功地登记回调用,并调用C++中从C层编写的函数(在单独的后台进程中运行)。p> 我的C#函数是 public virtual void OnNewAudioData(IBuffer buffer) { byte[] data = new byte[buffer.Length]; var reader = buffer.AsStream()
public virtual void OnNewAudioData(IBuffer buffer)
{
byte[] data = new byte[buffer.Length];
var reader = buffer.AsStream();
reader.Read(data, 0, (int)buffer.Length);
}
但函数在第二行中断(当我使用buffer.AsStream方法时),出现以下异常
发生System.InvalidCastException异常
_HResult=-2147467262
_消息=无法将类型为“System.\u ComObject”的COM对象强制转换为接口类型“System.Runtime.InteropServices.WindowsRuntime.IBufferByteAccess”。此操作失败,因为对IID为“{905A0FEF-BC53-11DF-8C49-001E4FC686DA}”的接口的COM组件的QueryInterface调用由于以下错误而失败:不支持此类接口(HRESULT的异常:0x80004002(E_NOINTERFACE))
[编辑:添加更多代码]
我调用C#回调的C++/CX函数是
void BackEndTransport::Write(BYTE* bytes, int byteCount)
{
ComPtr<NativeBuffer> spNativeBuffer = NULL;
MakeAndInitialize<NativeBuffer>(&spNativeBuffer, bytes, byteCount, FALSE);
//Invoking the call back to C# layer
Globals::Instance->CallController->OnNewAudioData(NativeBuffer::GetIBufferFromNativeBuffer(spNativeBuffer));
}
void BackEndTransport::Write(字节*字节,整数字节计数)
{
ComPtr spNativeBuffer=NULL;
MakeAndInitialize(&spNativeBuffer,bytes,byteCount,FALSE);
//调用对C#layer的回调
Globals::Instance->CallController->OnNewAudioData(NativeBuffer::GetIBufferFromNativeBuffer(spNativeBuffer));
}
NativeBuffer类的实现如下(取自示例)
#pragma一次
#包括“windows.h”
#包括
#包括
#包括
#包括
#包括
名称空间PhoneVoIPApp
{
命名空间后端
{
///
///此类的目的是将字节缓冲区转换为IBuffer
///
类NativeBuffer:公共Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags,
ABI::Windows::Storage::Streams::IBuffer,
Windows::Storage::Streams::iBufferByte访问,
Microsoft::WRL::FtmBase>
{
公众:
虚拟~NativeBuffer()
{
if(m_pBuffer和m_bIsOwner)
{
删除[]m_pBuffer;
m_pBuffer=NULL;
}
}
STDMETHODIMP运行时分类初始化(UINT totalSize)
{
m_长度=总尺寸;
m_uFullSize=总尺寸;
m_pBuffer=新字节[总大小];
m_bIsOwner=真;
返回S_OK;
}
STDMETHODIMP RuntimeClassInitialize(字节*pBuffer,UINT totalSize,BOOL ftakeOwnershipFPassedinBuffer)
{
m_长度=总尺寸;
m_uFullSize=总尺寸;
m_pBuffer=pBuffer;
m_bIsOwner=FTAKeownershipFPassedinbuffer;
返回S_OK;
}
STDMETHODIMP缓冲区(字节**值)
{
*值=m_pBuffer;
返回S_OK;
}
STDMETHODIMP获取容量(UINT32*值)
{
*值=m_fullsize;
返回S_OK;
}
STDMETHODIMP get_长度(UINT32*值)
{
*值=m_长度;
返回S_OK;
}
标准方法输入长度(UINT32值)
{
如果(值>m_fullSize)
{
返回E_INVALIDARG;
}
m_长度=数值;
返回S_OK;
}
静态Windows::Storage::Streams::IBuffer^GetIBufferFromNativeBuffer(Microsoft::WRL::ComPtr spNativeBuffer)
{
auto iinspectable=重新解释强制转换(spNativeBuffer.Get());
返回重新解释(不可检测);
}
静态字节*GetBytesFromIBuffer(Windows::Storage::Streams::IBuffer^buffer)
{
自动iinspectable=(iinspectable*)重新解释强制转换(缓冲区);
微软::WRL::ComPtr spBuffAccess;
HRESULT hr=iinspectable->QueryInterface(u uuidof(Windows::Storage::Streams::IBufferByteAccess),(void**)和SPBufferByteAccess);
UCHAR*前置缓冲器;
spBuffAccess->Buffer(&pReadBuffer);
返回预缓冲;
}
私人:
UINT32米长;
UINT32米整尺寸;
字节*m_pBuffer;
布尔·穆比索恩;
};
}
}
[编辑2:]
根据Hans Passant的建议,我尝试修改函数GetIBufferFromNativeBuffer以使用QueryInterface而不是重新解释cast。但我还是被卡住了(我的怀疑与代码一致)
static Windows::Storage::Streams::IBuffer^GetIBufferFromNativeBuffer(Microsoft::WRL::ComPtr spNativeBuffer)
{
auto myBuffer=spNativeBuffer.Get();
IUnknown*iinspectable=重新解释强制转换(myBuffer);
微软::WRL::ComPtr spBuffer;
HRESULT hr=iinspectable->QueryInterface(u uuidof(ABI::Windows::Storage::Streams::IBuffer),(void**)和spBuffer);
//如何将ABI::Windows::Storage::Streams::IBuffer转换为Windows::Storage::Streams::IBuffer?
返回。。。。;
}
这可能是实现此缓冲区的任何代码中的错误。它违反了实现IBuffer还需要实现IBufferByteAccess的要求。我们当然看不到。@HansPassant解决方案是什么?当然要修复您的C++/CX代码。我们仍然看不到它。我用更多的代码更新了这个问题。你不能用reinterpret_cast获得接口指针。您知道如何正确执行此操作,我看到您正在使用QueryInterface()。
#pragma once
#include "windows.h"
#include <robuffer.h>
#include <wrl.h>
#include <wrl/implements.h>
#include <wrl\client.h>
#include <windows.storage.streams.h>
namespace PhoneVoIPApp
{
namespace BackEnd
{
/// <summary>
/// The purpose of this class is to transform byte buffers into an IBuffer
/// </summary>
class NativeBuffer : public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >,
ABI::Windows::Storage::Streams::IBuffer,
Windows::Storage::Streams::IBufferByteAccess,
Microsoft::WRL::FtmBase>
{
public:
virtual ~NativeBuffer()
{
if (m_pBuffer && m_bIsOwner)
{
delete[] m_pBuffer;
m_pBuffer = NULL;
}
}
STDMETHODIMP RuntimeClassInitialize(UINT totalSize)
{
m_uLength = totalSize;
m_uFullSize = totalSize;
m_pBuffer = new BYTE[totalSize];
m_bIsOwner = TRUE;
return S_OK;
}
STDMETHODIMP RuntimeClassInitialize(BYTE* pBuffer, UINT totalSize, BOOL fTakeOwnershipOfPassedInBuffer)
{
m_uLength = totalSize;
m_uFullSize = totalSize;
m_pBuffer = pBuffer;
m_bIsOwner = fTakeOwnershipOfPassedInBuffer;
return S_OK;
}
STDMETHODIMP Buffer( BYTE **value)
{
*value = m_pBuffer;
return S_OK;
}
STDMETHODIMP get_Capacity(UINT32 *value)
{
*value = m_uFullSize;
return S_OK;
}
STDMETHODIMP get_Length(UINT32 *value)
{
*value = m_uLength;
return S_OK;
}
STDMETHODIMP put_Length(UINT32 value)
{
if(value > m_uFullSize)
{
return E_INVALIDARG;
}
m_uLength = value;
return S_OK;
}
static Windows::Storage::Streams::IBuffer^ GetIBufferFromNativeBuffer(Microsoft::WRL::ComPtr<NativeBuffer> spNativeBuffer)
{
auto iinspectable = reinterpret_cast<IInspectable*>(spNativeBuffer.Get());
return reinterpret_cast<Windows::Storage::Streams::IBuffer^>(iinspectable);
}
static BYTE* GetBytesFromIBuffer(Windows::Storage::Streams::IBuffer^ buffer)
{
auto iinspectable = (IInspectable*)reinterpret_cast<IInspectable*>(buffer);
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> spBuffAccess;
HRESULT hr = iinspectable->QueryInterface(__uuidof(Windows::Storage::Streams::IBufferByteAccess), (void **)&spBuffAccess);
UCHAR * pReadBuffer;
spBuffAccess->Buffer(&pReadBuffer);
return pReadBuffer;
}
private:
UINT32 m_uLength;
UINT32 m_uFullSize;
BYTE* m_pBuffer;
BOOL m_bIsOwner;
};
}
}
static Windows::Storage::Streams::IBuffer^ GetIBufferFromNativeBuffer(Microsoft::WRL::ComPtr<NativeBuffer> spNativeBuffer)
{
auto myBuffer = spNativeBuffer.Get();
IUnknown* iinspectable = reinterpret_cast<IUnknown*>(myBuffer);
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> spBuffer;
HRESULT hr = iinspectable->QueryInterface(__uuidof(ABI::Windows::Storage::Streams::IBuffer), (void **) &spBuffer);
//How can I convert ABI::Windows::Storage::Streams::IBuffer to Windows::Storage::Streams::IBuffer?
return ....;
}