Envoltorio de C# para importar .dll, "Intento de leer o escribir memoria protegida"

Después de una montaña de investigación y experimentación, todavía no puedo resolver un problema que tengo al acceder a funciones no administradas desde una biblioteca externa.

Breve historia de fondo relevante: Escribí una aplicación en Visual C++ para controlar un medidor externo que se conecta al sistema a través de USB, pero está virtualizando un puerto serie y noté un comportamiento de salida extraño. Para reivindicarse, el fabricante quiere que use su .dll para controlar el medidor desde mi aplicación. Bien, pero....

No pude incluir este .dll directamente como referencia (nombre y ruta eliminados):enter image description here

Entonces, para usarlo, presumiblemente busqué DllImport. En lugar de incluir el código directamente en mi aplicación, decidí hacer mi propio ensamblaje como contenedor para el controlador para poder acceder a la funcionalidad a través de una clase. Después de hacer un dumpbin/exports en el .dll, encontré los puntos de entrada para todas las funciones e hice una biblioteca de clases C# como esta, con solo los ejemplos relevantes incluidos:

namespace Meter
{
    public class PortDrv
    {

        [DllImport("PortDrv.dll", EntryPoint = "SERIALNUMBER",
            CallingConvention = CallingConvention.StdCall,
            CharSet = CharSet.Auto)]
        public static extern long SerialNumber(Byte Index);

        [DllImport("PortDrv.dll", EntryPoint = "OPENPORT",
            CallingConvention = CallingConvention.StdCall,
            CharSet = CharSet.Auto)]
        public static extern int OpenPort();

    };
}

Los prototipos de funciones se extrajeron del .pdf que me enviaron describiendo su biblioteca:

SERIALNUMBER (ByVal Index As Byte) As Long
OPENPORT () As Integer

Y también se usa en su programa VB de muestra:

Private Declare Function SerialNumber Lib "PortDrv" Alias "SERIALNUMBER" (Index As Byte) As Long
Private Declare Function OpenPort Lib "PortDrv" Alias "OPENPORT" () As Integer

¿Aún conmigo? Está bien. Entonces, después de compilar mi propio ensamblaje, agregué la referencia a mi aplicación y accedí al contenedor como tal:

int port_return = PortDrv::OpenPort(); 
Byte bite = 0x31;
__int64 serial = PortDrv::SerialNumber(bite);

Pero falla después de intentar recuperar el número de serie:enter image description here

Y no estoy muy seguro de dónde me estoy equivocando. Algunas de las funciones devuelven información correcta, pero parece que alguna tengo que pasar información para fallar. Probé todas las diferentes combinaciones de CharSets y CallingConventions, configuré ExactSpelling en verdadero, etc. ¿Hay algo evidentemente obvio que estoy haciendo mal, o simplemente no puedo usar esta biblioteca en mi entorno actual?

EDITAR: Olvidé mencionar eso, la razón por la que paso '1' a la función es que, si solo hay un medidor conectado al sistema, el "Índice" sería 1. Si hubiera 2 medidores, podría acceder al la segunda pasando en '2'.

preguntado el 03 de mayo de 12 a las 19:05

Ay. ¿Supongo que el fabricante no puede proporcionarle un contenedor .NET o un código de muestra de trabajo para un entorno .NET? Dadas las aparentes dificultades, esto no parece una solicitud irrazonable. -

Mmm. ¿Estás seguro de que 0x31 es una entrada válida? -

@Cameron: Creo que sí. También he intentado pasar '1' y 1. Quería descartar todas las posibles interpretaciones incorrectas declarando explícitamente el personaje. ¿O estás insinuando que debería pasar en 0x01?

El código que accede a su clase contenedora de C# parece ser un código C++/CLI. ¿Por qué creaste una clase contenedora de C# que accede a un código C/C++? Supongo que la convención de llamadas para C++/CLU NO es StdCall. -

El tipo de datos Integer en VB tiene un tamaño de 16 bits y el tipo de datos Long tiene un tamaño de 32 bits. Entonces, creo que tienes que cambiar tu firma de interoperabilidad. Use short en lugar de int (OpenPort) e int en lugar de long para SerialNumber. -

1 Respuestas

El programa de muestra de VB que diste:

Private Declare Function SerialNumber Lib "PortDrv" Alias "SERIALNUMBER" (Index As Byte) As Long  

no dice ByVal. El valor predeterminado en VB es ByRef. ¿Es esto un error tipográfico de su parte o es ese el problema? Si es así, tienes que decir ref Byte en su firma a SerialNumber.

Moraleja: decir siempre ByRef or ByVal.

contestado el 04 de mayo de 12 a las 13:05

la línea anterior se incluyó en SU ​​programa de muestra de uso del controlador. Parecía como si hubieras pensado que ese era mi código, pero no, lo saqué palabra por palabra para que sea correcto. En su prototipo, el byte se pasa ByVal: SERIALNUMBER (ByVal Index As Byte) As Long. ¿Es eso un contratiempo de su parte? - BL

Cambié la firma a ref Byte y la falla de la memoria disminuyó, pero la función aún no devuelve nada (usando int y long). Quiero marcar su respuesta como correcta ya que ese fue el enfoque del tema, pero como mi problema aún no ha desaparecido, quiero dejarlo abierto por ahora. - BL

Sí, supongo que el prototipo estaba equivocado. Gracias por el buen ojo, Ben. - BL

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.