PInvoke - 读取字符串字段的值 - “尝试读取或写入受保护的内存”
我在访问 COM 接口中的某些字符串字段时遇到问题。调用整数字段不会导致错误。当尝试调用 clientID()
、deviceID()
或 key()
时,我收到旧的“Attempted to read or write protected”内存”错误。
这里是源接口代码:(代码来源于这里)
[scriptable, uuid(fab51c92-95c3-4468-b317-7de4d7588254)]
interface nsICacheEntryInfo : nsISupports
{
readonly attribute string clientID;
readonly attribute string deviceID;
readonly attribute ACString key;
readonly attribute long fetchCount;
readonly attribute PRUint32 lastFetched;
readonly attribute PRUint32 lastModified;
readonly attribute PRUint32 expirationTime;
readonly attribute unsigned long dataSize;
boolean isStreamBased();
};
这里是访问接口的 C# 代码:
[Guid("fab51c92-95c3-4468-b317-7de4d7588254"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheEntryInfo
{
string clientID();
string deviceID();
nsACString key();
int fetchCount();
Int64 lastFetched();
Int64 lastModified();
Int64 expirationTime();
uint dataSize();
[return: MarshalAs(UnmanagedType.Bool)]
bool isStreamBased();
}
关于为什么仅仅尝试读取字段就会向我抛出访问冲突,有什么建议吗?
I'm having trouble accessing the some string fields in a COM interface. Calling the integer fields does not result in an error. When attempting call clientID()
, deviceID()
or key()
, I get the old "Attempted to read or write protected memory" error.
Here is the source interface code: (code sourced from here)
[scriptable, uuid(fab51c92-95c3-4468-b317-7de4d7588254)]
interface nsICacheEntryInfo : nsISupports
{
readonly attribute string clientID;
readonly attribute string deviceID;
readonly attribute ACString key;
readonly attribute long fetchCount;
readonly attribute PRUint32 lastFetched;
readonly attribute PRUint32 lastModified;
readonly attribute PRUint32 expirationTime;
readonly attribute unsigned long dataSize;
boolean isStreamBased();
};
Here is the C# code for accessing the interface:
[Guid("fab51c92-95c3-4468-b317-7de4d7588254"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheEntryInfo
{
string clientID();
string deviceID();
nsACString key();
int fetchCount();
Int64 lastFetched();
Int64 lastModified();
Int64 expirationTime();
uint dataSize();
[return: MarshalAs(UnmanagedType.Bool)]
bool isStreamBased();
}
Any suggestions as to why simply trying to read a field should throw access violations at me?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
此接口中的字符串是 C 样式字符串 (char*) 的变体,但 COM Interop 默认情况下将字符串视为 BSTR。您让编组器尝试读取错误类型的字符串,然后使用 CoTask 内存分配器释放它,因此出现访问冲突也就不足为奇了。如果您的字符串是 [In] 参数,您可以使用适当的 MarshalAs 属性来装饰它们,但这不适用于返回值参数。因此,您需要将它们编组为 IntPtr,然后手动编组并释放底层内存。
我会尝试以下操作:
正如 Chris 上面提到的,PRUint32 实际上是 32 位而不是 64 位无符号整数,所以我已经更改了它们。另外,我已经将方法更改为属性,因为这样可以更好地捕获 idl 的含义,因为它们都是只读的,所以实际上不会影响布局。
clientID 和 deviceID 的字符串可以使用 Marshal.PtrToStrAnsi 读取,如下所示:
是否使用 NS_Free 或内存接口来释放字符串取决于您如何使用整个 xpcom 设置。键值是一个抽象字符串,因此其表示形式取决于它的来源。看起来它通常可以像其他字符串一样被视为指向 ANSI 字符串的指针。
我没有为您尝试任何这些的设置,并且至少可以说,文档有些不透明,因此您可能需要对此进行一些调整。
The strings in this interface are variants on C style strings (char*'s) but COM Interop by default treats strings as BSTRs. You have the marshaller trying to read the wrong kind of string and then free it with the CoTask memory allocator, so it's no surprise you get an access violation. If your strings were [In] parameters you could just adorn them with the appropriate MarshalAs attribute but that won't work with return value parameters. So you need to marshal them as IntPtrs and then manually marshal and free the underlying memory.
I would try the following:
As Chris mentioned above the PRUint32s are actually 32 bit not 64 bit unsigned integers so I've changed them. Also, I've changed the methods to properties since that captures the meaning of the idl better, since they are all readonly it doesn't actually affect the layout.
The strings for clientID and deviceID can be read using Marshal.PtrToStrAnsi as so:
Whether you use NS_Free or the memory interface to free the strings depends on how you are using the whole xpcom setup. The key value is an abstract string so its representation depends on where it comes from. It appears though that it can usually be treated as a pointer to an ANSI string like the others.
I don't have the setup to try any of this for you and the documentation is, to say the least, somewhat opaque so you may need to do a little tweaking on this.
如果将 [return: MarshalAs(UnmanagedType.BStr)] 语句应用于 clientID 和 deviceID 会怎样?
What if you apply the [return: MarshalAs(UnmanagedType.BStr)] statememnt to clientID and deviceID ?