Pergunta

Eu estou trabalhando em um invólucro PInvoke para uma biblioteca que não suporta cadeias de caracteres Unicode, mas suporta multi-byte seqüências de caracteres ANSI. Ao investigar FxCop relatórios sobre a biblioteca, eu notei que a seqüência de empacotamento sendo usado teve alguns efeitos colaterais interessantes. O método PInvoke estava usando mapeamento "melhor ajuste" para criar uma cadeia ANSI de byte único. Para ilustração, este é o que um método parecia:

[DllImport("thedll.dll", CharSet=CharSet.Ansi)]
public static extern int CreateNewResource(string resourceName);

O resultado de chamar esta função com uma seqüência que contém caracteres não-ASCII é que o Windows encontra um personagem "fechar", geralmente isso parece que acaba sendo "???". Se fingir que 'a' é um caractere não-ASCII, em seguida, passando "gato" como um parâmetro criaria um recurso chamado "c? T".

Se eu seguir as orientações na regra FxCop, eu acabar com algo parecido com isto:

[DllImport("thedll.dll", CharSet=CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern int CreateNewResource([MarshalAs(UnmanagedType.LPStr)] string resourceName);

Isto introduz uma mudança de comportamento; Agora, quando um personagem não pode ser mapeada uma exceção é lançada. Isso me porque esta é uma alteração de quebra, então eu gostaria de tentar e organizar as cadeias como multi-byte ANSI, mas eu não posso ver uma maneira de fazê-lo preocupações. UnmanagedType.LPStr é especificado para ser uma cadeia ANSI de byte único, LPTStr will be Unicode or ANSI depending on the system, and LPWStr is not what the library expects.

How would I tell PInvoke to marshal the string as a multibyte string? I see there's a WideCharToMultiByte() API function, could I change the signature to expect an IntPtr para uma cadeia de criar na memória não gerenciado? Parece que este ainda tem muitos dos problemas que a implementação atual tem (ainda pode ter que cair ou caracteres substitutos), então eu não tenho certeza se isso é uma melhoria. Existe um outro método de empacotamento que eu estou perdendo?

Foi útil?

Solução

cordas

ANSI é multi-byte, e ANSI são codificados de acordo com a página de código atualmente ativada no sistema. WideCharToMultiByte funciona da mesma maneira como P / Invoke.

Talvez o que você está depois é a conversão para UTF-8. Embora WideCharToMultiByte suporta isso, eu não acho P / Invoke faz, já que não é possível adotar UTF-8 como a página de código ANSI de todo o sistema. Neste ponto, você estaria olhando para passar a string como um IntPtr vez, embora se você estiver fazendo isso, você pode também usar a classe Encoding conseguiu fazer a conversão, em vez de WideCharToMultiByte.

Outras dicas

Aqui é a melhor maneira que eu encontrei para fazer isso. Em vez de mobilizar como uma string, marechal como um byte []. Colocar a responsabilidade sobre o chamador da função pinvoke API para converter em um array de bytes da forma mais apropriada. Muito provavelmente usando uma das classes Text.Encoding.

Se você acabar tendo que chamar WideCharToMultiByte manualmente, gostaria de se livrar da p / invocar e manualmente marechal isso usando WideCharToMultiByte em um ++ / função wrapper CLI C. Managed C ++ é muito melhor nestes cenários de interoperabilidade do que C # é.

No entanto, se esta é a única p / invoke você tem, provavelmente não vale a pena.

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