2012-01-12 29 views
5

Chạy mã sau trong nền tảng Delphi XE2 Win32 hoạt động. Tuy nhiên, cùng mã biên dịch trong nền tảng win64 sẽ gây ra vi phạm truy cập trong "EnumRCDataProc" nếu chạy trong chế độ gỡ lỗi:Delphi XE2: Gọi WinAPI EnumResourceNames khiến vi phạm truy cập trong nền tảng 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; 

Khi gỡ lỗi mã trong Delphi XE2 IDE trên nền tảng Win64, tôi thấy giá trị của hModule trong EnumRCDataProc không phù hợp với biến H. Tôi nghi ngờ rằng có thể là một cái gì đó sai về các thông số tôi xây dựng cho EnumRCDataProc. Tuy nhiên, tôi không thể hiểu được làm thế nào. Ý tưởng nào?

Trả lời

5

Vấn đề là bạn đã thực hiện EnumRCDataProc thủ tục địa phương. Bạn cần phải di chuyển nó ra ngoài phương pháp.

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; 

On kiểm tra đầu tiên tôi mong đợi rằng trình biên dịch sẽ phát ra một lỗi với mã của bạn:

E2094 Local thủ tục/chức năng 'Callback' được gán cho biến thủ tục

Nhưng nó không làm như vậy. Tôi đào sâu hơn một chút và phát hiện ra rằng tham số gọi lại cho EnumResourceNames được khai báo là loại Pointer. Nếu bản dịch tiêu đề đã tuyên bố điều này như là một tham số gọi lại đã gõ thì thông báo lỗi trên thực sự sẽ được phát ra. Theo tôi, bản dịch tiêu đề kém về vấn đề này. Có vẻ như rất ít thu được từ việc từ bỏ sự an toàn của hệ thống kiểu.

Thực tế là mã của bạn hoạt động trong mã 32 bit chỉ là một sự trùng hợp ngẫu nhiên dựa trên chi tiết triển khai. Vận may của bạn hết trên 64 bit. Một lần nữa, nếu hệ thống kiểm tra kiểu đã được kích hoạt, trình biên dịch có thể đã cho bạn biết những gì đã sai ngay lập tức.

Một số ý kiến ​​khác:

  1. Các EnumRCDataProc có một vài loại không chính xác trong việc kê khai của nó: hModule nên loại HMODULE và kết quả chức năng nên được BOOL.
  2. LoadPackage là một cách tiếp cận khá nặng để có được trình xử lý mô-đun. Tôi muốn xem LoadLibraryEx với các tùy chọn LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVELOAD_LIBRARY_AS_IMAGE_RESOURCE.
+0

Trình biên dịch không nên phàn nàn về điều đó. Hàm enum cục bộ không phải là vấn đề gì cả. – OnTheFly

+0

Đoán, tại sao nó phát ra rằng: p – OnTheFly

+1

Miễn là cuộc gọi lại không truy cập bất kỳ điều mẫu nào không phải là vấn đề. Sau đó, một lần nữa, với mục đích đó, việc gọi lại là điều chính xác. Có nghĩa là gì? Điều đó có làm mất hiệu lực một phần của câu trả lời ở trên không? –

Các vấn đề liên quan