We help IT Professionals succeed at work.

Com programming again.

hulken
hulken asked
on
I have made a ComObject that read things from a database into a IHeader.

What I like to do is to fill a listview with things in the IHeader and have the IHeader at ListView.Items[ix].Data
I get Incompatible types interface and pointer. Is it someway to work around this?
Comment
Watch Question

Commented:
You can always typecast:

var
  Header: IHeader;

ListView.Items[I].Data := Pointer(Header);

but be aware that COM objects are reference counted and automatically destroyed when the reference count reaches zero. This may lead to 'dangling' pointers in your listview items Data (pointing to memory location where the interface pointer is no longer valid because its implementation object has been destroyed) and subsequent access violations.

Delphi, for example, will automatically decrease reference count on any interface reference when it goes out of scope (local variables), or when it's assigned a new value (another interface pointer), or nil.

Always set your Data pointers to nil when you're finished with the interface, and always check for nil before trying to access them.

Sounds like asking for trouble, if you don't do things the right way, IMHO.
Software Engineer, Advisory
CERTIFIED EXPERT
Top Expert 2005
Commented:

Hulken,
if you are going to do it this way, it is important to note that 'pointer:=Pointer(Interface);' will NOT increment the ref count of the interface. (whereas 'Interface:=Interface;' would).

If it was me, I would manually increment the ref count using _AddRef before assigning the interface to the pointer. Then I would not have as many worries about unchecked pointers. Here is a simple example:

-Start of example-
var  punk:       IUnknown; // Your IHeader
     p:          Pointer;  // Data element
     i:          Integer;
begin

// Create instance of object and get IUnknown interface
// Only for example purposes
CoInitialize(nil);
punk:=CreateComObject(ProgIDToClassID('ADODB.Recordset'));

// Increment the ref count, should now show 2
i:=punk._AddRef;
ShowMessage(Format('Interface refcount: %d', [i]));

// Perform the pointer assignment.
// This will NOT increment the refcount,
// thus the reason for the addref.
p:=Pointer(punk);

// Can safely get rid of original interface without
// invalidating the one in the pointer
punk:=nil;

//
// Do code....
//

// You can always hand out the interface,
// which WILL automatically increment the refcount
punk:=IUnknown(p);
// Check the refcount, it will show 2
i:=punk._AddRef-1;
ShowMessage(Format('Interface refcount: %d', [i]));
punk._Release;
punk:=nil;

// Then you have 2 choices when dealing with the
// final destruction of the interface
// But either way you choose, you will still have
// to perform a manual release due to the
// manually addref

// 1. Perform the release on the pointer, and
// set p to nil so you don't mistakenly
// reuse it by accident
IUnknown(p)._Release;
p:=nil;

// 2. Assign the pointer to an interface,
// decrease the refcount, and set the interface
// to nil
punk:=IUnknown(p);
punk._Release;
punk:=nil;

end;

-End of example-


Russell

Explore More ContentExplore courses, solutions, and other research materials related to this topic.