2010-11-09 7 views
11

Trong delphi 2009 Tôi có một tham chiếu đến một IInterface mà tôi muốn truyền tới các cơ bản TObjectLàm thế nào để đúc một giao diện cho một đối tượng ở Delphi

Sử dụng TObject(IInterface) rõ ràng không hoạt động trong Delphi 2009 (đó là nghĩa vụ làm việc trong Delphi 2010 mặc dù)

Tìm kiếm của tôi dẫn tôi đến a function that should do the trick, nhưng nó không hoạt động đối với tôi, tôi nhận được AV khi tôi cố gọi các phương thức trên đối tượng được trả về.

tôi có thể không thực sự thay đổi lớp học và tôi biết rằng điều này phá vỡ OOP

Trả lời

18

Thay vì dựa vào bố cục đối tượng nội bộ của Delphi, bạn cũng có thể có đối tượng của bạn thực hiện một giao diện khác. Điều này, tất nhiên, chỉ hoạt động nếu bạn có quyền truy cập vào mã nguồn của các đối tượng để bắt đầu, nhưng bạn có lẽ không nên sử dụng các hacks này nếu bạn không có quyền truy cập vào mã nguồn của các đối tượng.

interface 

type 
    IGetObject = interface 
    function GetObject: TObject; 
    end; 

    TSomeClass = class(TInterfacedObject, IGetObject) 
    public 
    function GetObject: TObject; 
    end; 

implementation 

function TSomeClass.GetObject: TObject; 
begin 
    Result := Self; 
end; 
+1

Tôi thực sự đã kết thúc sử dụng giải pháp này đã có, nhưng đã không nhận được xung quanh để gửi câu trả lời của riêng tôi nêu ra. Đội mũ cho bạn! – Yona

2

Hallvard của hack là rất cụ thể về cách trình biên dịch Delphi tạo mã. Điều đó đã được ổn định đáng kể trong quá khứ, nhưng có vẻ như họ đã thay đổi một cái gì đó đáng kể trong Delphi 2009. Tôi chỉ có 2007 cài đặt ở đây, và trong đó, mã của Hallvard hoạt động tốt.

GetImplementingObject return NIL?

Nếu vậy, sau đó nếu bạn gỡ lỗi và đặt điểm ngắt trên báo cáo trường hợp trong thường trình GetImplementingObject, giá trị của QueryInterfaceThunk.AddInstruction sẽ đánh giá điều gì trong trình gỡ lỗi?

+0

Nó không trả về không, có vẻ như nó trả về địa chỉ bộ nhớ sai, vì tôi có thể thấy một số dữ liệu của đối tượng nhưng dữ liệu khác chỉ là vô nghĩa – Yona

+1

2009 giới thiệu trường con trỏ ẩn mới (để hỗ trợ màn hình). Bạn nên điều chỉnh phương thức để tính toán điều đó. – alex

+0

Cảm ơn alex, nhưng phương pháp đó nằm ngoài chuyên môn của tôi trong Delphi. Bạn có thể xây dựng những gì tôi cần điều chỉnh không? – Yona

3

Tóm lại: bạn không nên hoặc thêm giao diện bằng phương thức trả về con trỏ cho bạn. Bất cứ điều gì khác là hackery.

Lưu ý rằng một giao diện "dụ" có thể được thực hiện bằng ngôn ngữ khác (họ là COM tương thích) và/hoặc có thể là một cái gì đó còn sơ khai cho ra khỏi quá trình vv vv

Tất cả trong tất cả: một thể hiện giao diện duy nhất đồng ý với giao diện và không có gì khác, chắc chắn không được thực hiện như một trường hợp Delphi TObject

+0

Tôi biết đó là một hack và nó có thể phá vỡ mọi thứ. Tôi hỏi làm thế nào không nếu tôi nên. – Yona

-1
var 
    N, F: NativeInt; // NativeInt is Integer(in delphi 32bit) 
    S: TObject; 
begin 
    N := NativeInt(Args[0].AsInterface) - 12; 
    {subtract 12 byte to get object address(in x86 ,1 interface on class) } 
    S := TObject(N);  
    writeln(S.ToString); 

end; 
+0

Điều này có thể làm việc cho một số trình biên dịch tạo ra mã, nhưng không phải người khác. Nó luôn luôn là tốt hơn để có được hằng số $ 0C từ mã được tạo ra. –

15

Bạn đang đúng. Bắt đầu với Delphi 2010, bạn có thể sử dụng toán tử as, ví dụ: qua số aObject := aInterface as TObject hoặc thậm chí aObject := TObject(aInterface).

as Toán tử này sử dụng một giao diện ẩn GUID đặc biệt (ObjCastGUID) để lấy trường hợp đối tượng, gọi một phiên bản nâng cao của TObject.GetInterface, mà không tồn tại trước khi Delphi 2010. Xem mã nguồn của System.pas đơn vị để xem làm thế nào nó hoạt động.

Tôi đã xuất bản một số mã hoạt động cho Delphi 6 lên đến XE2, including Delphi 2009.

Xem http://blog.synopse.info/post/2012/06/13/Retrieve-the-object-instance-from-an-interface

+0

Cám ơn workaround Delphi6 của bạn. Nó hoạt động !!! – geekobi

3

Có một lựa chọn tốt đẹp khi bạn biết đối tượng thực hiện là một hậu duệ TComponent.

Bạn có thể sử dụng giao diện IInterfaceComponentReference, được định nghĩa trong Classes đơn vị:

IInterfaceComponentReference = interface 
    ['{E28B1858-EC86-4559-8FCD-6B4F824151ED}'] 
    function GetComponent: TComponent; 
end; 

Và sau đó nó được khai báo trong TComponent (và thực hiện để trở self):

TComponent = class(TPersistent, IInterface, IInterfaceComponentReference) 

Vì vậy, nếu bạn biết đối tượng thực hiện là một TComponent sau đó bạn có thể làm điều này:

function InterfaceToComponent(const AInterface: IInterface): TComponent; 
var 
    vReference: IInterfaceComponentReference; 
begin 
    if Supports(AInterface, IInterfaceComponentReference, vReference) then 
    result := vReference.GetComponent 
    else 
    result := nil; 
end;