Pergunta

Eu continuo recebendo uma AccessViolationException ao chamar o seguinte a partir de uma DLL externo:

FILES_GetMemoryMapping(MapFile, out size, MapName, out PacketSize, pMapping, out PagePerSector);

Que tem um protótipo que eu configurar como tal:

    [DllImport("Files.DLL", SetLastError = true)]
    public static extern uint FILES_GetMemoryMapping(
        [MarshalAs(UnmanagedType.LPStr)]
        string pPathFile,
        out ushort Size,
        [MarshalAs(UnmanagedType.LPStr)]
        string MapName,
        out ushort PacketSize,
        IntPtr pMapping,
        out byte PagesPerSector);

Agora, o argumento de que está causando isso é mais provável o 5º (um IntPtr pMapping). Eu tenho portado este código ao longo de um aplicativo C ++ em C #. O argumento 5 acima é um ponteiro para uma estrutura que também contém um apontador para outra estrutura. Abaixo está como eu tenho essas sctructs configuração:

    [StructLayout(LayoutKind.Sequential)]
    public struct MappingSector
    {
        [MarshalAs(UnmanagedType.LPStr)]
        public string Name;
        public uint dwStartAddress;
        public uint dwAliasedAddress;
        public uint dwSectorIndex;
        public uint dwSectorSize;
        public byte bSectorType;
        public bool UseForOperation;
        public bool UseForErase;
        public bool UseForUpload;
        public bool UseForWriteProtect;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct Mapping
    {
        public byte nAlternate;
        [MarshalAs(UnmanagedType.LPStr, SizeConst=260)]
        public string Name;
        public uint NbSectors;
        public IntPtr pSectors;
    }

O C ++ equivalente destes são as seguintes:

typedef struct {
    char*       Name;
    DWORD       dwStartAddress;
    DWORD       dwAliasedAddress;
    DWORD       dwSectorIndex;
    DWORD       dwSectorSize;
    BYTE        bSectorType;
    BOOL        UseForOperation;
    BOOL        UseForErase;
    BOOL        UseForUpload;
    BOOL        UseForWriteProtect;
} MAPPINGSECTOR, *PMAPPINGSECTOR;

typedef struct {
    BYTE            nAlternate;
    char            Name[MAX_PATH]; // MAX_PATH = 260
    DWORD           NbSectors;
    PMAPPINGSECTOR  pSectors;   
} MAPPING, *PMAPPING;

Eu tenho um sentimento que eu fiz algo errado com qualquer portabilidade sobre estas estruturas, ou portar sobre o protótipo da função. questão Um Empacotamento de somesort.

A função de todo o caminho no topo deste post é chamado duas vezes no meu código. Uma vez com pMapping definido como nulo (isto coloca um valor em "tamanho"). Memória é então alocado para uma nova struct usando esse parâmetro tamanho e a função é chamada novamente, agora usando um ponteiro para este espaço de memória alocada para pMapping. (PMapping também tem um ponteiro para a outra struct que também recebe algum espaço alocado durante este tempo).

Aqui está o código antigo c ++ que realizou esta:

FILES_GetMemoryMapping((LPSTR)(LPCTSTR)MapFile, &Size, (LPSTR)MapName, &PacketSize, pMapping, &PagePerSector);
// Allocate the mapping structure memory
pMapping = (PMAPPING)malloc(sizeof(MAPPING));
pMapping->NbSectors = 0;
pMapping->pSectors = (PMAPPINGSECTOR) malloc((Size) * sizeof(MAPPINGSECTOR));
printf("mapsectorsize: <%d>\n", football);
printf("pMappingsize: <%d>\n", f2);  
// Get the mapping info
FILES_GetMemoryMapping((LPSTR)(LPCTSTR)MapFile, &Size, (LPSTR)(LPCTSTR)MapName, &PacketSize, pMapping, &PagePerSector);

Inicialmente eu pensei que não foi alocar a quantidade correta de espaço, então eu tentei o código antigo C ++ acima e descobriu que:

sizeof(MAPPING) = 272
and
sizeof(PMAPPINGSECTOR) = 40

Eu fiz a mesma verificação no meu código C # e encontrou o seguinte:

Marshal.SizeOf(new Mapping()) = 16
and
Marshal.SizeOF(new MappingSector()) = 40

Temos um problema aqui. A estrutura de mapeamento deve ser de tamanho 272, mas a sua apenas 16 anos pensando que eu poderia apenas fazer um reparo rápido, eu alocados manualmente 272 em vez de 16 aqui, mas ainda com erros para fora com um AccessViolationException.

Qualquer idéia de como consertar isso? Ou o que poderia ainda estar errado indo?

Foi útil?

Solução

'protótipo' não era a palavra correta, eu como "declaração DLLImport" melhor.

E eu só tenho que trabalhar.

-lo em C ++:

typedef struct {
    BYTE                        nAlternate;
    char                        Name[MAX_PATH]; // MAX_PATH = 260
    DWORD                       NbSectors;
    PMAPPINGSECTOR      pSectors;       
} 

para C #:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct Mapping
{
    public byte nAlternate;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=260)]
    public char[] Name;
    public uint NbSectors;
    public IntPtr pSectors;
}

A matriz de caracteres não é uma string, e deve ser tratado como uma matriz de caracteres .... Quem teria imaginado: P

Outras dicas

De acordo com MSDN , você deve passar um StringBuilder para uma tampão de comprimento fixo. Tente o seguinte, ou alguma variante (não testado):

[StructLayout(LayoutKind.Sequential)]
public struct Mapping
{
    public byte nAlternate;
    [MarshalAs(UnmanagedType.LPStr, SizeConst=260)]
    public StringBuilder Name;
    public uint NbSectors;
    public IntPtr pSectors;

    public Mapping()
    {
        Name = new StringBuilder(259); 
        //This will be a buffer of size 260 (259 chars + '\0')
    }
}

Eu não tenho trabalhado por tudo isso, estou com medo, mas se você tem estruturas com 'char * é em e você está triagem-los como 'string', então você deve ter o cuidado de ser decorando coisas com o apropriado charset = CharSet.Ansi atributos.

Uma coisa que seria útil para adicionar à sua postagem é o protótipo C ++ para a função (eu não iria se referir a sua declaração DLLImport como um 'protótipo', mas que só poderia ser eu.)

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