开发者

Why doesn't Marshal.Release call Release on my COM object?

开发者 https://www.devze.com 2023-02-01 14:04 出处:网络
I\'ve read the documentation for Marshal.GetIUnknownForObject and it says: Always use Marshal.Release 开发者_如何学编程to decrement the reference count once you have finished with the pointer.

I've read the documentation for Marshal.GetIUnknownForObject and it says:

Always use Marshal.Release 开发者_如何学编程to decrement the reference count once you have finished with the pointer.

I wrote a test solution with a COM object which I use via .NET and I see that when working with the wrapper to my COM object neither Marshal.GetIUnknownForObject nor Marshal.Release cause the AddRef or Release methods of my COM object to be called.

What's up with that?


Wait a minute, I think I've got it. You are making a COM object, then you are making a runtime callable wrapper around that COM object, and then you're asking the runtime callable wrapper for its punk, and then you're wondering why calling release on that punk doesn't call your Release? Does that sum up your question?

If so, you might have mentioned all those details in the question rather than making us guess.

Well, why do you suppose it would it call your Release? it's going to call the Release of the runtime callable wrapper. The wrapper wraps your object; that's why its called a wrapper. The runtime callable wrapper doesn't need to addref and release your object every time it is addref'd and released! Why would it? It needs to keep your object alive and it already has a ref on your object; that is sufficient to keep the wrapped object alive. Why do unnecessary work?

When you just have a runtime callable wrapper around a COM object you should reasonably expect to that the ref count on the object is unchanging for the entire lifetime of the object. The runtime takes a ref once, and when the RCW is garbage collected for the last time or released in some other manner, it releases that ref and the object deletes itself.

Think about it like this. Suppose you said:

foo->bar = blah;
blah->AddRef();

blah gets addref'd because foo->bar has a reference to it. Now you say:

abc->def = foo;
foo->AddRef();

That adds a ref to foo. Does it add a ref to blah? Of course not. Why would it? foo has a ref to blah; the fact that foo is being kept alive by abc is irrelevant to blah.

Same thing here. You have:

wrapper = new RCW();
wrapper->wrapped = yourobject;
yourobject->AddRef();

That adds a ref to yourobject. Now if you have

wrapper->QI(IUnknown, &punk)

that doesn't give you the punk to the underlying object, it gives you the punk of the wrapper. If you say

punk->AddRef();

that doesn't addref the underlying object, it addrefs the wrapper.


The Marshal.AddRef and Marshal.Release methods are calling the COM AddRef and Release methods of the COM instance; Marshal.GetIUnknownForObject is likely to be calling QueryInterface, which implies an AddRef on the returned IUnknown pointer.

Maybe your test project is somehow buggy, possibly calling AddRef and Remove on another COM instance than the one you expect?

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号