PInvoke - lendo o valor de um campo string - “Tentativa de ler ou memória protegida write”

StackOverflow https://stackoverflow.com/questions/1607380

  •  05-07-2019
  •  | 
  •  

Pergunta

Estou tendo problemas para acessar os alguns campos de cordas em uma interface COM. Chamando os campos inteiros não resulta em um erro. Ao tentar chamada clientID(), deviceID() ou key(), fico com a idade "Tentativa de ler ou memória protegida write" erro.

Aqui está o código interface de origem: (código proveniente de aqui )

[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();
};

Aqui está o código C # para acessar a 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();
}

Todas as sugestões a respeito de porque simplesmente tentando ler um campo deve jogar violações de acesso para mim?

Foi útil?

Solução

As cordas nessa interface são variantes em cordas estilo C (char * 's) mas interoperabilidade por padrão trata strings como BSTRs. Você tem a marshaller tentando ler o tipo errado de corda e depois libertá-la com o alocador de memória CoTask, então não é nenhuma surpresa que você começa uma violação de acesso. Se as cordas eram [In] parâmetros você poderia simplesmente enfeitá-las com o atributo MarshalAs adequadas, mas que não vai trabalhar com parâmetros de valor de retorno. Então, você precisa organizar-los como IntPtrs e, em seguida, manualmente marechal e liberar a memória subjacente.

Gostaria de tentar o seguinte:

[Guid("fab51c92-95c3-4468-b317-7de4d7588254"), ComImport, 
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheEntryInfo
{
    IntPtr clientID { get; }
    IntPtr deviceID { get; }
    IntPtr key { get; }
    int fetchCount { get; }
    uint lastFetched { get; }
    uint lastModified { get; }
    uint expirationTime { get; }
    uint dataSize { get; }
    [return: MarshalAs(UnmanagedType.Bool)]
    bool isStreamBased();
}

Como Chris mencionado acima os PRUint32s são na verdade 32 bits não 64 bits inteiros sem sinal para que eu mudei-los. Além disso, eu mudei os métodos para propriedades desde que capta o significado do IDL melhor, pois todos eles são somente leitura que na verdade não afeta o layout.

As cordas para clientID e deviceID podem ser lidos usando Marshal.PtrToStrAnsi assim:

        nsIMemory memoryManagerInstance = /*maybe get this from somewhere*/;
        nsICacheEntryInfo cacheEntryInstance = /*definitely get this from somewhere*/;
        IntPtr pClientID = cacheEntryInstance.clientID;
        string clientID = Marshal.PtrToStringAnsi(pClientID);

        NS_Free(pClientID);

        //or

        memoryManagerInstance.free(pClientID);

Se você usa NS_Free ou a interface de memória para libertar as cordas depende de como você está usando toda a configuração xpcom. O valor da chave é uma seqüência abstrato pelo que a sua representação depende de onde ele vem. Parece no entanto, que geralmente pode ser tratado como um ponteiro para uma cadeia ANSI como os outros.

Eu não tenho a configuração para tentar qualquer do presente para você ea documentação é, para dizer o mínimo, um pouco opaco, assim você pode precisar de fazer um pouco de ajustes sobre este assunto.

Outras dicas

E se você aplicar o [retorno: MarshalAs (UnmanagedType.BStr)]? Statememnt para clientID e deviceID

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top