2010-07-01 23 views
9

Trong Delphi, làm cách nào để tìm ra địa chỉ của phương thức COM? Tôi có thể mã hóa sai sốPhương thức COM ở Delphi

//0 is the offset of the QueryInterface method 
p := TPonterArray(pointer(SomeInterface)^)[0]; 

nhưng tôi muốn sử dụng tên biểu tượng. Các folllowing rõ ràng không hoạt động:

var M : TMethod; 
... 
M := TMethod(SomeInterface.QueryInterface); 

Cảm ơn!

+3

Delphi mất đi rất nhiều của tất cả các chi tiết COM đẫm máu, tôi nghĩ rằng bạn muốn làm quá nhiều cho mình. Bạn đang cố gắng đạt được điều gì? Tạo máy chủ COM của riêng bạn hoặc sử dụng máy chủ hiện tại của bạn? –

+0

Bạn có muốn bù số của phương thức trong giao diện (ví dụ, IUnknown.QueryInterface là 0), địa chỉ của phương thức trong lớp thực hiện phương thức giao diện đó (ví dụ: @ TInterfacedObject.QueryInterface) hoặc địa chỉ của mã stub được tạo ra để liên kết một cuộc gọi giao diện đến phương thức đối tượng tương ứng? Cái sau được lưu trữ trong bảng giao diện của lớp. –

+0

@The_Fox: Không: Tôi đang chặn cuộc gọi đến đối tượng COM bên ngoài bằng Win32Hook.pas. @Rob Kennedy: Không có lớp TInterfacedObject - tôi chỉ có giao diện được thực hiện bởi một dll bên ngoài. –

Trả lời

3

Tôi không nghĩ rằng Delphi hỗ trợ điều đó. Hardcoding offsets có lẽ là điều duy nhất sẽ làm việc, vì trình biên dịch không đếm các phương thức giao diện như các biểu tượng có giá trị có thể được gán cho một con trỏ hàm, cách các phương thức đối tượng hoặc các hàm độc lập có thể.

Tại sao bạn đang cố thực hiện việc này, BTW?

+1

Tôi chặn các cuộc gọi đến một đối tượng COM bên ngoài bằng cách sử dụng Win32Hook.pas - chỉ cần một tính năng ghi nhật ký cho OutlookSpy của tôi (http://www.dimastr.com/outspy/) –

+1

BTW, trình biên dịch Delphi rõ ràng là biết bù trừ phương thức, tôi chỉ cố gắng tìm cách để làm tương tự thay vì sử dụng bù đắp mã hóa cứng. –

+0

Vâng, trình biên dịch biết về nó, nhưng theo như tôi có thể nói, không có cách nào để có được nó trực tiếp. –

6

Bạn có thể sử dụng chỉ thị lắp ráp vmtoffset để lấy độ lệch byte của phương thức giao diện tương ứng với bắt đầu của bảng phương thức của giao diện. Hãy xem việc thực hiện _IntfCast trong System.pas, ví dụ:

call dword ptr [eax] + vmtoffset IInterface.QueryInterface 
... 
call dword ptr [eax] + vmtoffset IInterface._Release 

Khái niệm đầu tiên cho biết thêm 0; thứ hai, 8.

Tuy nhiên, bạn không thể tham số hóa các biểu thức đó. Chúng là hằng số biên dịch, vì vậy bạn không thể chọn phương thức nào bạn muốn trong thời gian chạy. Bạn cần phải có tất cả các tên phương thức có thể được biểu diễn trước.

Tất cả các bạn thực sự cần phải móc là QueryInterface. Một khi bạn có điều đó, bạn có thể trả về bất kỳ đối tượng proxy nào bạn muốn có thể chặn cuộc gọi đến tất cả các phương thức khác.

+0

Điều này có vẻ hứa hẹn ... Tôi sẽ thử sau ngày hôm nay và đăng kết quả. Cảm ơn! –

2

Mã của bạn sai vì tham chiếu giao diện không phải là con trỏ đến bảng phương thức giao diện nhưng con trỏ trỏ đến con trỏ tới bảng phương thức giao diện. Đó là cách các giao diện Delphi được thực hiện ở mức nhị phân. Thật khó để nói nhiều hơn và chỉ ra lỗi trong mã của bạn bởi vì bạn chưa đưa ra một ví dụ mã có thể được biên dịch. Sử dụng đoạn mã sau để chuyển đổi tài liệu tham khảo giao diện để con trỏ phương pháp một cách chính xác, ý tưởng được lấy từ Barry Kelly's demonstration of creating a method pointer from a method reference:

procedure IntRefToMethPtr(const IntRef; var MethPtr; MethNo: Integer); 
type 
    TVtable = array[0..999] of Pointer; 
    PVtable = ^TVtable; 
    PPVtable = ^PVtable; 
begin 
    // QI=0, AddRef=1, Release=2, etc 
    TMethod(MethPtr).Code := PPVtable(IntRef)^^[MethNo]; 
    TMethod(MethPtr).Data := Pointer(IntRef); 
end; 

Nếu bạn thích tên mang tính biểu tượng cho MethNo bạn là tốt hơn để khai báo mình là hằng số bù đắp

+0

Không, một biến giao diện trong Delphi là một con trỏ tới một bảng v. –

+0

Không, Dmitry, Serg là đúng. Một biến giao diện không thể chỉ là một con trỏ đến một vtable. Tất cả các cá thể của lớp chia sẻ một vtable đơn, giống như các lớp không giao diện. Hãy xem xét C++, trong đó không có sự khác biệt giữa các giao diện và các lớp thông thường. Một đối tượng con trỏ không chỉ là một con trỏ vtable, do đó, không phải là một con trỏ giao diện. –

+0

@Rob Kennedy: cảm ơn, câu hỏi đã buộc tôi viết một bài đăng trên blog về giao diện Delphi: http://sergworks.wordpress.com/2010/07/06/delphi-interfaces-on-binary-level/ – kludg

1

Hai chỉ thị bổ sung cho phép mã lắp ráp truy cập động và các phương thức ảo: VMTOFFSET và DMTINDEX.

VMTOFFSET truy xuất độ lệch theo byte của con trỏ phương thức ảo mục bảng của đối số phương thức ảo từ đầu bảng phương thức ảo (VMT). Chỉ thị này cần tên được chỉ định đầy đủ với tên phương thức làm tham số (ví dụ: TExample.VirtualMethod) hoặc tên giao diện và phương thức giao diện tên.

DMTINDEX truy lục chỉ mục bảng phương pháp động của phương thức động được truyền.Chỉ thị này cũng cần một tên lớp được chỉ định đầy đủ với tên phương thức làm tham số, ví dụ: TExample.DynamicMethod. Để gọi phương thức động, hãy gọi Hệ thống. @ CallDynaInst với thanh ghi (E) SI có chứa giá trị thu được từ DMTINDEX.

docwiki.embarcadero.com

Đây mã để có được con trỏ phương pháp cần thiết

function GetMethodPointer(const IntRef: IInterface): Pointer; assembler; 
asm 
    mov eax, [IntRef] 
    add eax, vmtoffset ISomeInterface.MemberMethod 
    mov eax, [eax] 
end; 
Các vấn đề liên quan