开发者

PInvoke - how to represent a field from a COM interface

I am referencing a COM structure that starts as follows:

[scriptable, uuid(ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e)]
interface nsICacheSession : nsISupport开发者_StackOverflows
{
    /**
     * Expired entries will be doomed or evicted if this attribute is set to
     * true.  If false, expired entries will be returned (useful for offline-
     * mode and clients, such as HTTP, that can update the valid lifetime of
     * cached content).  This attribute defaults to true.
     */
    attribute PRBool doomEntriesIfExpired;
...

Source: http://dxr.proximity.on.ca/dxr/mozilla-central/netwerk/cache/public/nsICacheSession.idl.html#58

I found code for importing that interface into my C# app. The code must be wrong though, as the set method doesn't seem to be useful and also throws an error when I try to call it just to see what happens:

[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
    [return: MarshalAs(UnmanagedType.Bool)]
    void set_doomEntriesIfExpired();
    [return: MarshalAs(UnmanagedType.Bool)]
    bool get_doomEntriesIfExpired();
...

What is the correct way to set the value of doomEntriesIfExpired and how do I reference this from my code?

EDIT

I changed my code to the following, which yielded "System.AccessViolationException: Attempt to read or write protected memory yada yada...":

[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
    void set_doomEntriesIfExpired(bool enabled);
    bool get_doomEntriesIfExpired();
...


The answer you inserted is good. In COM Interop bools are marshaled as VARIANT_BOOL by default so your addition of the MarshalAs attribute to tell the marshaler to use a standard 4 byte BOOL type is correct, though the getter part of the equation needs the attribute added as well.

In general, I like to leave properties defined in the interface as properties rather than breaking them out into their getters and setters. It matches the semantics of the interface definition better and is usually easier to read as well. You should be able to re-write your COM import definition as follows to retain the attribute nature of doomEntriesIfExpired:

[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, 
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{

    bool doomEntriesIfExpired 
    { 
        [param:MarshalAs(UnmanagedType.Bool)]set; 
        [return:MarshalAs(UnmanagedType.Bool)]get; 
    }

...


The fact that you state a [return: MarshalAs(UnmanagedType.Bool)] for your void set method is obviously a source of error.

That said, I managed to code a C++ mozilla plugin without the [return ...] tags in the .idl, eg:

[scriptable, uuid(ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e)]
interface nsICacheSession : nsISupports
{
    void set_doomEntriesIfExpired(in bool value);
    bool get_doomEntriesIfExpired();
}

By the way, are you sure you can code a nsi plugin in C# ?


Turns out the answer was the following:

[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
    void set_doomEntriesIfExpired([In, MarshalAs(UnmanagedType.Bool)] ref bool enabled);
    bool get_doomEntriesIfExpired();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜