P/Invocar e Mono:EntryPointNotFoundException
Pergunta
Estou tentando acessar a implementação do Wine de algumas funções do user32 no Kubuntu Linux.Tenho o pacote Wine 1.1.31 instalado.Ao tentar executar este programa de teste simples no MonoDevelop, recebo uma System.EntryPointNotFoundException
.
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace PinvokeTesting
{
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine(GetKeyState((int)Keys.A));
}
[DllImport("user32")]
private static extern short GetKeyState(int vKey);
}
}
Esta é a saída:
Exceção não tratada:System.EntryPointNotFoundException:GetKeyState em (wrapper gerenciado para nativo) pinvoKetesting.mainClass: getKeyState (int) em pinvoketesting.maainclass.main (System.string [] args) [0x00000] em .../main.cs: 11
A função deveria estar lá, mas não a encontra.Alguma ideia?Pesquisei bastante, não encontrei nada útil.A documentação parece ser bastante escassa sobre essas questões (ou isso ou estou procurando as coisas erradas).
Editar: Não estou tentando usar P/Invoke em combinação com Winforms, existem algumas outras funções no Wine que preciso fazer P/Invoke.Estou apenas tentando fazer o Mono P/Invoke to Wine funcionar.
Solução
Os biblioteadores do vinho são completamente incompatíveis com o mono. Se você precisar usar libs de vinho no Linux, precisará obter a versão do Windows do Mono e executá -lo sob o vinho.
Isso não tem nada a ver com WinForms especificamente, é verdade para qualquer biblioteca de vinhos.
Quanto à solução real para o seu problema:
- Não use o truque #IFDEF WIN32API_NT_5 que foi sugerido, use a detecção de tempo de execução e invoca um método ou outro, se você estiver executando no Windows ou sob diferentes sistemas operacionais: ter um único binário vale o tempo de execução de 1 ciclo Penalidade (Moreoer se você armazenar o sinalizador do sistema operacional em um campo estático readnly mono otimizará o check -in para você).
- Você precisa lidar com diferentes modelos de sistema operacional se deseja que seu código seja portátil, porque nem sempre é possível implementar a chamada de formiga de um sistema em outro de uma maneira simples ou totalmente compatível. Por exemplo, no caso getKeyState (), você pode precisar conectar eventos do teclado e gravar o estado de imprensa/liberação.
- Considere maneiras diferentes de fazer a mesma coisa, por exemplo, tem certeza de que a classe de console padrão no MSCORLIB não fornece a functuonalidade necessária em seu programa?
Outras dicas
Se você está tentando fazer isso em combinação com o sistema gerenciado.windows.forms implementação no mono no Linux, então tenho certeza de que o vinho de que o vinho não vai ajudá -lo. O SWF é implementado totalmente diferente/separadamente do vinho, e os dois não "misturam" ou de forma alguma interagem.
Sugiro que você encontre outra maneira de alcançar o que está tentando fazer.
Há uma moral simples para a história aqui, como você descobriu... se houver pinvokes usados, não presuma que o código seja portátil entre plataformas e compatível com vinho!A única coisa que você poderia resolver seria algo assim:
using System; using System.Runtime.InteropServices; using System.Windows.Forms; namespace PinvokeTesting { class MainClass { public static void Main(string[] args) { Console.WriteLine(GetKeyState((int)Keys.A)); } #ifdef WIN32API_NT_5 [DllImport("user32")] private static extern short GetKeyState(int vKey); #else private static extern short GetKeyState(int vKey); #endif } }
E crie algum tipo de wrapper para substituir a assinatura pinvoke do Win32API.Só porque faz referência System.Windows.Forms
não significa que os pinvokes WIN32API funcionarão no Wine, já que as várias interfaces subjacentes em termos de GUI são diferentes e não há garantia de serem portáteis.
Em seguida, defina a opção 'WIN32API_NT_5' ou o que você deseja escolher de sua preferência, se quiser tornar esta plataforma cruzada amigável.
Espero que isso ajude, cumprimentos, Tom.