Search code examples
c#wcfcomcom-interopmoniker

How to fix compile error 'System.ServiceModel.ComIntegration.IParseDisplayName' is inaccessible due to its protection level'


I'm trying to implement a COM component in C# that will be invokable using GetObject and supplying a custom string. Two components already do this WMI with GetObject("winmgmts:\.\root\cimv2") and LDAP with GetObject("LDAP://example.com/OU=Users,DC=asp,DC=rippe,DC=com"). I'm attracted to this custom activation syntax and would like to replicate it.

It seems I have to implement the Class Com Interface IParseDisplayName.

So I'm trying to do this in C#, I have simple COM object that does simple calculations. I am stuck trying to implement IParseDisplayName, I get the following error

`'System.ServiceModel.ComIntegration.IParseDisplayName' is inaccessible due to its protection level`

Now I've seen other C# questions with these errors and they are access modifier issues that are solved by upgrading access to public. But I do not control this interface as it is a system interface.

How do I solve please? Here the code as it currently stands.

using Microsoft.Win32;
using System;
using System.ServiceModel;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Xml;

namespace MonikerParseDisplayName
{
    // In Project Properties->Build->Check 'Interop for COM'
    // In AssemblyInfo.cs [assembly: ComVisible(true)]
    // compile with /unsafe In Project Properties->Build->Check 'Allow unsafe code'


    public interface ICalculator
    {
        double add( double a, double b);
        double mult(double a, double b);
    }
    [ClassInterface(ClassInterfaceType.None)]
    [ComDefaultInterface(typeof(ICalculator))]
    //[System.Security.SuppressUnmanagedCodeSecurity]
    public class Calculator : ICalculator, System.ServiceModel.ComIntegration.IParseDisplayName  //, System.Runtime.InteropServices.ComTypes.IMoniker
    {
        public double add( double a, double b) 
        {
            return a+b;
        }
        public double mult(double a, double b)
        {
            return a*b;
        }

        //void IParseDisplayName.ParseDisplayName(IBindCtx pbc, IMoniker pmkToLeft, 
        //    string pszDisplayName, out int pchEaten, out IMoniker ppmkOut)
        void IParseDisplayName.ParseDisplayName(IBindCtx pbc, IMoniker pmkToLeft,
            string pszDisplayName, IntPtr pchEaten, IntPtr ppmkOut)
        {
            return new Exception("Not yet implemented");
        }
    }
}

EDIT: Also, I think Windows Communication Foundation (WCF) also uses same mechanism here is a link and here a code snippet. If true then this proves that it can be done in C#!

Set typedServiceMoniker = GetObject(  
"service4:address=http://localhost/ServiceModelSamples/service.svc,      binding=wsHttpBinding,   
contractType={9213C6D2-5A6F-3D26-839B-3BA9B82228D3}")  

Solution

  • You should just be able to re-declare that interface yourself. The interesting thing about COM interfaces in .NET is that you can define them in multiple places and they won't conflict. Just stick this in your code somewhere and use this definition instead of the one in System.ServiceModel.ComIntegration.

    [ComImport]
    [SuppressUnmanagedCodeSecurity]
    [Guid("0000011a-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IParseDisplayName
    {
        void ParseDisplayName(IBindCtx pbc, [MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, IntPtr pchEaten, IntPtr ppmkOut);
    }