2012-01-12 10 views
5

Ejecutando el siguiente código en la plataforma Delphi XE2 Win32 funciona. Sin embargo, el mismo código compila en la plataforma Win64 hará que el acceso violación en "EnumRCDataProc" si se ejecuta en modo de depuración:Delphi XE2: Invocar WinAPI EnumResourceNames causa violación de acceso en la plataforma Win64

procedure TForm2.Button1Click(Sender: TObject); 
    function EnumRCDataProc(hModule: THandle; lpszType, lpszName: PChar; lParam: 
     NativeInt): Boolean; stdcall; 
    begin 
    TStrings(lParam).Add(lpszName); 
    Result := True; 
    end; 

var k: NativeInt; 
    L: TStringList; 
    H: THandle; 
begin 
    H := LoadPackage('resource.bpl'); 
    L := TStringList.Create; 
    try 
    EnumResourceNames(H, RT_RCDATA, @EnumRCDataProc, NativeInt(L)); 
    ShowMessage(L.Text); 
    finally 
    L.Free; 
    UnloadPackage(H); 
    end; 
end; 

Cuando depurar el código en Delphi XE2 IDE en la plataforma Win64, encontré el valor de hModule en EnumRCDataProc no coincide con la variable H. Sospecho que puede haber algún problema con los parámetros que construí para EnumRCDataProc. Sin embargo, no puedo entender cómo. ¿Algunas ideas?

Respuesta

5

El problema es que ha hecho que EnumRCDataProc sea un procedimiento local. Tienes que moverlo fuera del método.

function EnumRCDataProc(hModule: HMODULE; lpszType, lpszName: PChar; lParam: 
    NativeInt): BOOL; stdcall; 
begin 
    TStrings(lParam).Add(lpszName); 
    Result := True; 
end; 

procedure TForm2.Button1Click(Sender: TObject); 
var k: NativeInt; 
    L: TStringList; 
    H: HMODULE; 
begin 
    H := LoadPackage('resource.bpl'); 
    L := TStringList.Create; 
    try 
    EnumResourceNames(H, RT_RCDATA, @EnumRCDataProc, NativeInt(L)); 
    ShowMessage(L.Text); 
    finally 
    L.Free; 
    UnloadPackage(H); 
    end; 
end; 

La primera inspección que esperaba que el compilador emitiría un error con su código:

E2094 procedimiento/función Local 'Devolución de llamada' asignado a la variable procedimiento

pero lo hace no lo hagas Cavé un poco más profundo y descubrí que el parámetro de devolución de llamada para EnumResourceNames está declarado como tipo Pointer. Si la traducción del encabezado lo hubiera declarado como un parámetro de devolución de llamada tipeado, entonces el mensaje de error anterior habría sido emitido. En mi opinión, la traducción del encabezado es pobre en este sentido. Parece que hay muy poco que ganar al abandonar la seguridad del sistema de tipos.

El hecho de que su código funcione en código de 32 bits es simplemente una feliz coincidencia que se basa en los detalles de implementación. Tu suerte se agota en 64 bits. De nuevo, si el sistema de verificación de tipo se hubiera habilitado, el compilador podría haberle dicho lo que estaba mal inmediatamente.

Algunos otros comentarios:

  1. El EnumRCDataProc tiene un par de tipos incorrectos en su declaración: hModule debe ser de tipo HMODULE y el resultado de la función debe ser BOOL.
  2. LoadPackage es un enfoque bastante pesado para obtener un identificador de módulo. Preferiría ver LoadLibraryEx con las opciones LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE y LOAD_LIBRARY_AS_IMAGE_RESOURCE.
+0

El compilador no debería quejarse de eso. La función enum local no es un problema en absoluto. – OnTheFly

+0

Adivina por qué emite eso: p – OnTheFly

+1

Siempre que la devolución de llamada no acceda a ningún formulario, eso no debería ser un problema. Por otra parte, solo para ese propósito, tomar la devolución de llamada es lo correcto. ¿Qué significa el exceso de ataque? ¿Eso anula la parte de la respuesta anterior? –

Cuestiones relacionadas