【问题标题】:Marshalling char** in a more human way以更人性化的方式编组 char**
【发布时间】:2014-02-19 19:08:56
【问题描述】:

我在 C# 中有以下接口方法声明:

[ComVisible(true), ComImport, SuppressUnmanagedCodeSecurity,
Guid("A668B8F2-BA87-4F63-9D41-768F7DE9C50E"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ILAVAudioStatus
{
    [PreserveSig]
    int GetOutputDetails(out IntPtr pOutputFormat, out int pnChannels, out int pSampleRate, out uint pChannelMask);
}

pOutputformat 在 C++ 中实际上是一个 char**

我需要做一个Marshal.PtrToStringAnsi(pOutputformat) 来获取实际的字符串。

是否有一些编组属性可以将 pOutputformat 直接转换为输出字符串,而不是使用 IntPtr?

这就是 C++ 方法的作用:

HRESULT CLAVAudio::GetOutputDetails(const char **pOutputFormat, int *pnChannels, int *pSampleRate, DWORD *pChannelMask)
{
  if(!m_pOutput || m_pOutput->IsConnected() == FALSE) {
    return E_UNEXPECTED;
  }
  if (m_avBSContext) {
    if (pOutputFormat) {
      *pOutputFormat = get_sample_format_desc(SampleFormat_Bitstream);
    }
    return S_FALSE;
  }
  if (pOutputFormat) {
    *pOutputFormat = get_sample_format_desc(m_OutputQueue.sfFormat);
  }
  if (pnChannels) {
    *pnChannels = m_OutputQueue.wChannels;
  }
  if (pSampleRate) {
    *pSampleRate = m_OutputQueue.dwSamplesPerSec;
  }
  if (pChannelMask) {
    *pChannelMask = m_OutputQueue.dwChannelMask;
  }
  return S_OK;
}

【问题讨论】:

  • 取决于方法使用参数的方式,out StringBuilder 可以工作。
  • out stringBuilder 使应用程序崩溃,而 stringBuilder 只是返回一个用指针而不是值填充的 stringBuilder(4 个字节的垃圾)。
  • 是的,这可能会发生。编组输出参数有点烦人,因为它取决于处理它的方法以及它是分配内存还是调用函数。
  • C++ 中的方法正如您所期望的那样将指向其内部字符串的指针放入 pOutputformat,然后我使用 PtrToStringAnsi 读取它。我只是想知道是否有办法以某种方式将参数声明为输出字符串,因为它显然不适用于“输出字符串”
  • 您不能调用 C++ 实例方法。当它访问 m_Output 和 m_avBSContext 成员时它不会崩溃是盲目的运气。这不会很好地重复。

标签: c# c++ string marshalling


【解决方案1】:
Marshal.PtrToStringAnsi(pOutputformat)

是你能做到的最好的。这是无法避免的。如果您尝试编组为out string OutputFormat,则编组程序将在本机代码返回的指针上调用CoTaskMemFree。最后以泪水告终。

问题在于谁负责释放pOutputformat 指向的内存?只有你自己知道答案。

有人想知道为什么这个 COM 接口的设计者选择使用 C 字符串而不是 COM BSTR

【讨论】:

  • 我知道这完全是因为缺少 BSTR,但我对此无能为力 :( 无论如何,从 c++ 代码来看,我似乎有责任释放任何“*pOutputFormat = get_sample_format_desc()" 放入我的指针中。对吧?
  • @MarinoŠimić 如果您知道它是从哪个堆分配的,或者库为您提供了一个释放器,您只能释放它。有时库返回指向静态分配字符串的指针,在这种情况下不需要释放。我们没有办法知道这些细节。
  • 我找到了 get_sample_format_desc: const char *get_sample_format_desc(LAVAudioSampleFormat sfFormat) { return sample_format_strings[sfFormat];似乎不需要解除分配,因为它只是从 static const char *sample_format_strings[] = { "16bit Integer", "24bit Integer", "32bit Integer", "8bit Integer", "32bit Float", "Bitstreaming" 返回一个字符串};
  • 那你就可以走了。 Marshal.PtrToStringAnsi 对你来说是必不可少的。
  • 我接受你的回答并感谢今天的教学课。学习一些东西总是很好,尤其是因为我不太擅长 c++ 和这种互操作。
猜你喜欢
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
  • 1970-01-01
  • 2018-12-13
相关资源
最近更新 更多