如何正确P/Invoke Ole32 API中的FmtIdToPropStgName函数
解决Ole32 API中FmtIdToPropStgName函数的P/Invoke声明问题
我无法找到Ole32 API中FmtIdToPropStgName函数可用的P/Invoke声明,尝试了以下C#代码:
internal class Program { [DllImport("ole32.dll", SetLastError = false, ExactSpelling = true)] public static extern int FmtIdToPropStgName(Guid pfmtid, [Out, MarshalAs(UnmanagedType.LPWStr)] System.Text.StringBuilder oszName); static void Main(string[] args) { Guid bstrGuid = new Guid("{7018CEB7-2E6A-4061-B7E6-C9FC9C97F594}"); var stringBuilder = new StringBuilder(100); FmtIdToPropStgName(bstrGuid, stringBuilder); } }
但运行时触发System.AccessViolationException异常:Attempted to read or write protected memory.
以下是可正常运行的C++示例代码:
int main() { LPCOLESTR bstrGuid = L"{7018CEB7-2E6A-4061-B7E6-C9FC9C97F594}"; CLSID clsid; auto res2 = CLSIDFromString(bstrGuid, &clsid); wchar_t buffer[30] = { 0 }; auto res = ::FmtIdToPropStgName(&clsid, buffer); std::wcout << buffer; }
问题原因及解决方案
问题出在P/Invoke的参数声明上:C++中FmtIdToPropStgName的第一个参数是CLSID指针(const CLSID*),但你写的C#代码直接传递了Guid值类型,函数会错误地将值的内存当成指针去解引用,导致内存访问违规。
正确的P/Invoke声明及调用代码
internal class Program { [DllImport("ole32.dll", SetLastError = false, ExactSpelling = true)] public static extern int FmtIdToPropStgName(ref Guid pfmtid, [Out, MarshalAs(UnmanagedType.LPWStr)] System.Text.StringBuilder oszName); static void Main(string[] args) { Guid fmtId = new Guid("7018CEB7-2E6A-4061-B7E6-C9FC9C97F594"); var stringBuilder = new StringBuilder(30); // 函数要求缓冲区至少容纳30个宽字符(含终止符) int result = FmtIdToPropStgName(ref fmtId, stringBuilder); if (result == 0) // 返回0表示调用成功(S_OK) { Console.WriteLine(stringBuilder.ToString()); } } }
关键说明
- 第一个参数必须用
ref Guid修饰,对应C++中的指针类型,确保函数能正确读取Guid的内存地址。 - 缓冲区大小参考C++示例,该函数返回的属性名最长为29个宽字符,加上终止符共需30个字符的空间,无需初始化过大的StringBuilder。
- 必须检查函数返回值,0代表调用成功,非0值对应COM错误码。
内容的提问来源于stack exchange,提问作者blit
相关产品推荐
相关产品推荐

