دلفي:كيفية تنفيذ الاستعلام واجهة غير معروف?
-
26-09-2020 - |
سؤال
في دلفي, IUnknown
تم الإعلان عنه على أنه:
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
ملاحظة: معلمة الإخراج غير مكتوبة
في بلدي TInterfacedObject
سليل أحتاج إلى التعامل معها QueryInterface
, ، حتى أتمكن من إرجاع كائن يدعم الواجهة المطلوبة:
function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if IsEqualGUID(IID, IFooBar) then
begin
Obj := (TFooBar.Create(Self) as IFooBar);
Result := S_OK;
end
else
Result := inherited QueryInterface(IID, {out}Obj);
end;
المشكلة تأتي على الخط:
Obj := (TFooBar.Create(Self) as IFooBar);
يشكو دلفي:
المشغل لا ينطبق على هذا النوع المعامل
من الواضح أنني لا أعرف كيف أو ماذا أسند إلى غير مكتوب out
المعلمة.يمكنني تجربة الأشياء بشكل عشوائي ، على أمل أن يتوقف المترجم عن الشكوى:
Obj := TFooBar.Create(Self);
Obj := Pointer(TFooBar.Create(Self));
Obj := Pointer(TFooBar.Create(Self) as IFooBar);
تجاهل كل التعليمات البرمجية التي كتبتها (إذا لزم الأمر):كيف يمكنني تنفيذ QueryInterface
في كائن سليل من TInterfacedObject
?
المشكلة الحقيقية لقد كنت تحاول حل يمكن المغلي وصولا الى أريد أن:
أريد تجاوز الأساليب في واجهة
بنفس الطريقة:
TList = class(TObject)
...
function GetItem(Index: Integer): Pointer;
procedure SetItem(Index: Integer; Value: Pointer);
property Items[Index: Integer]: Pointer read GetItem write SetItem;
end;
يمكن تجاوزها في فئة سليل:
TStudentList = class(TList)
...
function GetItem(Index: Integer): TStudent;
procedure SetItem(Index: Integer; Value: TStudent);
property Items[Index: Integer]: TStudent read GetItem write SetItem;
end;
أريد أن نفس الشيء مع واجهات:
IFoo = interface(IUnknown)
...
function GetItem(Index: Variant): Variant;
procedure SetItem(Index: Variant; Value: Variant);
property Items[Index: Variant]: Variant read GetItem write SetItem;
end;
IFooGuidString = interface(IFoo)
...
function GetItem(Index: TGUID): string ;
procedure SetItem(Index: TGUID; Value: string );
property Items[Index: TGUID]: string read GetItem write SetItem;
end;
المشكلة هي كيف يجب أن أبدأ في تحميل كائن التنفيذ الخاص بي مع:
TFoo = class(TInterfacedObject, IFoo, IFooGuidString)
public
function IFoo.GetItem = FooGetItem;
procedure IFoo.SetItem = FooSetItem;
function FooGetItem(Index: Variant): Variant;
procedure FooSetItem(Index: Variant; Value: Variant);
function IFooGuidString.GetItem = FooGuidStringGetItem;
procedure IFooGuidString.SetItem = FooGuidStringSetItem;
function FooGuidStringGetItem(Index: TGUID): string ;
procedure FooGuidStringSetItem(Index: TGUID; Value: string );
end;
وليس هناك فقط طريقتين في IFoo
, ، هناك 6.ثم إذا كنت ترغب في إضافة واجهة أخرى معتمدة:
IFooInt64String = interface(IFoo)
...
function GetItem(Index: Int64): string ;
procedure SetItem(Index: Int64; Value: string );
property Items[Index: Int64]: string read GetItem write SetItem;
end;
TFoo = class(TInterfacedObject, IFoo, IFooGuidString)
public
function IFoo.GetItem = FooGetItem;
procedure IFoo.SetItem = FooSetItem;
function FooGetItem(Index: Variant): Variant;
procedure FooSetItem(Index: Variant; Value: Variant);
function IFooGuidString.GetItem = FooGuidStringGetItem;
procedure IFooGuidString.SetItem = FooGuidStringSetItem;
function FooGuidStringGetItem(Index: TGUID): string ;
procedure FooGuidStringSetItem(Index: TGUID; Value: string );
function IFooInt64String.GetItem = FooInt64StringGetItem;
procedure IFooInt64String.SetItem = FooInt64StringSetItem;
function FooInt64StringGetItem(Index: Int64): string ;
procedure FooInt64StringSetItem(Index: Int64; Value: string );
end;
وتصبح الأمور غير عملية حقا بسرعة كبيرة.
المحلول
تحتاج إلى كتابة-يلقي اليسار جانب بيان المهمة.بهذه الطريقة ، تحتوي المعلمة غير المكتوبة على نوع ، ويعرف المترجم كيفية تعيين قيمة لها:
IFooBar(Obj) := TFooBar.Create(Self) as IFooBar;
يرجى ملاحظة أنك كسر واحدة من متطلبات كوم.إذا قمت بالاستعلام عن واجهة ، يجب أن تكون قادرا على الاستعلام عن النتيجة ل إيوننوون ودائما الحصول على نفس القيمة:
Foo.QueryInterface(IUnknown, I1);
I1.QueryInterface(IFooBar, B);
B.QueryInterface(IUnknown, I2);
Assert(I1 = I2);
إذا كنت ترغب فقط في إنشاء كائنات جديدة من نوع تفوبار ، ثم إعطاء واجهة الخاص بك طريقة التي تولد تلك:
function TFoo.NewFooBar: IFooBar;
begin
Result := TFooBar.Create(Self) as IFooBar;
end;
نصائح أخرى
إلى جانب تصريحات روب بخرق القواعد هنا ، يمكنك حتى النجاح في هذا البناء:
function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if IsEqualGUID(IID, IFooBar) then
Result := TFooBar.Create(Self).QueryInterface(IID, obj)
else
Result := inherited QueryInterface(IID, {out}Obj);
end;
لم أكن التحقيق في هذا ، ولكن قد تحصل على بعض المشاكل مع العد المرجعي...
بناء على تنفيذ توبجيكت.الحصول على واجهة في النظام.با أود أن أقترح هذا:
Pointer(Obj) := TFooBar.Create(Self);