2

I have implemented a COM component in C#:

[ComVisible(true)]
[System.Runtime.InteropServices.Guid("E052BB1C-7ADC-47F4-99E1-9407E2FA0AA2")]
public interface IColorRamps
{
    IColorRamp getColorRamp();
}

[ComVisible(true)]
[Guid("EE47F2F2-0AD9-437C-8815-D570EACF2C07")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("ColorRamps.ColorRamps")]
public class ColorRamps : IColorRamps
{
    public IColorRamp getColorRamp() { ... } 
}

I call this from C++:

IColorRampPtr colorRamp;
{
    ColorRamps::IColorRampsPtr colorRamps(ColorRamps::CLSID_ColorRamps);
    HRESULT hr = colorRamps->getColorRamp(&colorRamp);
    colorRamp.AddRef(); // Should I do this??
 }

At first I did not have the AddRef() call and things seemed to work except I got strange crashes on "R6025 (pure virtual function call) run-time error" after running this code many times.

The signature in the autogenerated .tlh file is:

virtual HRESULT __stdcall getColorRamp(/*[out,retval]*/ struct IColorRamp * * pRetVal ) = 0;

When calling functions like this in C++ I am used to the function doing an AddRef() itself and passing on memory ownership to the caller. Is this not the case in C# COM?

I did NOT call Marshal.AddRef() inside ColorRamps.getColorRamp().

2 Answers 2

3

That is most likely to happen because you Release() the pointer than because .NET forgot to AddRef() before returning (hint: .NET surely did not forget this).

IColorRampPtr is itself a smart pointer, you must be using it because you #imported the .NET generated type library in VC++. As such, you should never call Release() on the smart pointers, as it'll be released when it goes out of scope (or, if used in a class member, when the object is destroyed).

If you want a raw pointer, on which you must later call Release(), use the raw interface pointer (e.g. IColorRamp*) or Detach() the smart pointer. Generally, you need a raw interface pointer when its scope becomes indeterminate. If the scope is well defined and you can use a smart pointer, keep it as a smart pointer.

Sign up to request clarification or add additional context in comments.

1 Comment

I am pretty sure I do not Release() the pointer. Since it is a smart pointer I assumed that it should take care of itself. The crash I encountered may come from some other place in the code, but the fact is that when I called AddRef() I could not reproduce it. I was thinking that the pure virtual function call exception may come from the Runtime Callable Wrapper?
2

From MSDN (https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.addref%28v=vs.80%29.aspx) :

The common language runtime manages the reference count of a COM object for you, making it unnecessary to use this method directly. In rare cases, such as testing a custom marshaler, you might find it necessary to manipulate an object's lifetime manually. After calling AddRef, you must decrement the reference count by using a method such as Marshal.Release. Do not rely on the return value of AddRef, as it can sometimes be unstable.

Worth a look?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.