2010-09-20 21 views
11

Por alguna razón, cada vez que mi aplicación C# .NET 2.0 realiza una llamada a GetProcAddress siempre devuelve cero.C# GetProcAddress Devuelve cero

public class MyClass 
{ 
    internal static class UnsafeNativeMethods 
    { 
     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     internal static extern IntPtr LoadLibrary(string lpFileName); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     internal static extern bool SetDllDirectory(string lpPathName); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName); 
    } 

    private void MyFunc() 
    { 
     IntPtr _dllHandle; 
     IntPtr _fptr; 
     string _fullPath = ".\\mydll.dll"; 
     string _procName = "MyDllFunc"; 

     _dllHandle = UnsafeNativeMethods.LoadLibrary(_fullPath); 
     _fptr = UnsafeNativeMethods.GetProcAddress(_dllHandle, _procName); // <-- Always returns zero. 
    } 
} 

Estoy seguro que el nombre de la función está escrito correctamente, y _fullPath es presumiblemente correcta porque _dllHandle siempre se le asigna un valor distinto de cero. Cualquier información que pueda proporcionar es apreciada. Gracias.

Respuesta

13

GetProcAddress solo tiene un sabor ANSI, por lo tanto, ayudamos al tiempo de ejecución al decirle que siempre use ANSI al coordinar el parámetro de cadena. También evitamos que el tiempo de ejecución busque GetProcAddressA inexistente, ya que el valor predeterminado para C# es establecer ExactSpelling en falso.

http://www.pinvoke.net/default.aspx/kernel32.getprocaddress

+0

+1, lo tienes antes de que lo viera. –

+0

¡Eso hizo el truco! ¡Gracias! –

+0

+1 ¡He estado insinuando mi cabeza contra la pared durante horas hasta que google me envió aquí!Después de todo, solo era cuestión de agregar ** CharSet = CharSet.Ansi ** a los parámetros nombrados del atributo ** DllImport ** para que funcionase. –

1

No ha mostrado cómo exporta la función de la DLL, pero sospecho que el problema es que el nombre exportado no es lo que cree que es. Puede ejecutar dumpbin /exports mydll.dll para ver las exportaciones de la dll para verificar el nombre.

Si muestra un fragmento de código de la exportación, podría proporcionarle más consejos. Puede intentar decorar la función exportada con extern "C" para eliminar el cambio de nombre como una prueba.

2

Realmente necesita agregar alguna comprobación de errores. Al menos verificar si _dllHandle! = IntPtr.Zero. Además, dependiendo del directorio de trabajo actual es peligroso, use Assembly.GetEntryAssembly(). Location para obtener un nombre de ruta completo.

El nombre de la función probablemente sea incorrecto. Las exportaciones tienden a decorarse, como _MyDllFunc o _MyDllFunc @ 4. Más salvajemente si fue compilado por un compilador de C++. Use Dumpbin.exe/exports en su archivo DLL para ver los nombres reales.

Volver al tratamiento de errores, use SetLastWin32Error en el atributo [DllImport]. Tire Win32Exception si la función devuelve false o IntPtr.Zero.


Editar: Veo el problema real. Usar CharSet.Auto para GetProcAddress() es incorrecto. Muy desafortunado, solo se trata de la única función de la API de Windows que solo tiene una versión ANSI. Tienes que usar CharSet.Ansi. Un buen lugar para obtener declaraciones [DllImport] correctas es pinvoke.net

+0

Vote por nombre equivocado. los nombres de las funciones exportadas generalmente se ven muy raras. –

+0

Eliminé el código del controlador de errores para simplificar el fragmento de código. –

+0

@Jim: ¿realmente eliminó SetLastWin32Error antes de publicar? Lo sé, comentario inteligente :) –

0

¿Su exportación en el archivo .DEF para la DLL coincide con la entrada aquí? Puede usar dumpbin para averiguar qué se exporta, según otras respuestas aquí.

¿Cuál es el error de Win32 subyacente en GetProcAddress(), por GetLastError()?

Puede probar esto en el código nativo para calcular primero las entradas correctas sin el equipaje adicional de P/Invoke.

+2

BTW puede obtener el último error lanzando una Win32Exception: 'throw new Win32Exception();' El constructor sin parámetros llama a 'Marshal.GetLastWin32Error()' y proporciona un mensaje de error detallado. – dtb