We too had some issues many years ago with regasm and running the COM class as a Local EXE Server.
This is a bit of a hack and I'd welcome any suggestions to make it more elegant. It was implemented for a project back in the .NET 1.0 days and has not been touched since then!
Basically it performs a regasm style of registration each time the application starts (it needs to be run once to make registry entries before the COM object is instantiated in the COM container application).
I've copied the following important bits from our implementation and renamed a few classes to illustrate the example.
The following method is called from the Form Loaded event to register the COM class(renamed to MyCOMClass
for this example)
private void InitialiseCOM()
{
System.Runtime.InteropServices.RegistrationServices services = new System.Runtime.InteropServices.RegistrationServices();
try
{
System.Reflection.Assembly ass = Assembly.GetExecutingAssembly();
services.RegisterAssembly(ass, System.Runtime.InteropServices.AssemblyRegistrationFlags.SetCodeBase);
Type t = typeof(MyCOMClass);
try
{
Registry.ClassesRoot.DeleteSubKeyTree("CLSID\\{" + t.GUID.ToString() + "}\\InprocServer32");
}
catch(Exception E)
{
Log.WriteLine(E.Message);
}
System.Guid GUID = t.GUID;
services.RegisterTypeForComClients(t, ref GUID );
}
catch ( Exception e )
{
throw new Exception( "Failed to initialise COM Server", e );
}
}
For the type in question, MyCOMObject
, will need some special attributes to be COM compatible. One important attribute is to specify a fixed GUID otherwise each time you compile the registry will fill up with orphaned COM GUIDs. You can use the Tools menu in VisualStudio to create you a unique GUID.
[GuidAttribute("D26278EA-A7D0-4580-A48F-353D1E455E50"),
ProgIdAttribute("My PROGID"),
ComVisible(true),
Serializable]
public class MyCOMClass : IAlreadyRegisteredCOMInterface
{
public void MyMethod()
{
}
[ComRegisterFunction]
public static void RegisterFunction(Type t)
{
AttributeCollection attributes = TypeDescriptor.GetAttributes(t);
ProgIdAttribute ProgIdAttr = attributes[typeof(ProgIdAttribute)] as ProgIdAttribute;
string ProgId = ProgIdAttr != null ? ProgIdAttr.Value : t.FullName;
GuidAttribute GUIDAttr = attributes[typeof(GuidAttribute)] as GuidAttribute;
string GUID = "{" + GUIDAttr.Value + "}";
RegistryKey localServer32 = Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\\{0}\\LocalServer32", GUID));
localServer32.SetValue(null, t.Module.FullyQualifiedName);
RegistryKey CLSIDProgID = Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\\{0}\\ProgId", GUID));
CLSIDProgID.SetValue(null, ProgId);
RegistryKey ProgIDCLSID = Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\\{0}", ProgId));
ProgIDCLSID.SetValue(null, GUID);
//Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\\{0}\\Implemented Categories\\{{63D5F432-CFE4-11D1-B2C8-0060083BA1FB}}", GUID));
//Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\\{0}\\Implemented Categories\\{{63D5F430-CFE4-11d1-B2C8-0060083BA1FB}}", GUID));
//Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\\{0}\\Implemented Categories\\{{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}}", GUID));
}
[ComUnregisterFunction]
public static void UnregisterFunction(Type t)
{
AttributeCollection attributes = TypeDescriptor.GetAttributes(t);
ProgIdAttribute ProgIdAttr = attributes[typeof(ProgIdAttribute)] as ProgIdAttribute;
string ProgId = ProgIdAttr != null ? ProgIdAttr.Value : t.FullName;
Registry.ClassesRoot.DeleteSubKeyTree("CLSID\\{" + t.GUID + "}");
Registry.ClassesRoot.DeleteSubKeyTree("CLSID\\" + ProgId);
}
}
The InitialiseCOM
method in the main form uses RegistrationServices
to register the type. The framework then uses reflection to find the method marked with the ComRegisterFunction
attribute and calls that function with the type being registered.
The ComRegisterFunction
marked method, hand creates the registry settings for a Local EXE Server COM object and this can be compared with regasm if you use REGEDIT
and find the keys in question.
I've commented out the three \\Registry.ClassesRoot.CreateSubKey
method calls as this was another reason we needed to register the type ourselves as this was an OPC server and third party OPC clients use these implemented categories to scan for compatible OPC servers. REGASM would not add these in for us unless we did the work ourselves.
You can easily see how this works if you put break points on the functions as it is starting.
Our implementation used an interface that was already registered with COM. For your application you will either need to :-
- Extend the registration methods listed above to register the interface with COM
- Or create a separate DLL with the interface definition and then export that interface definition to a type library and register that as discussed in the StackOverflow link you added in the question.
By no means am I an expert in this, but I stumbled recently on what I think you want: the CoClass attribute class.
[System.Runtime.InteropServices.CoClass(typeof(Test))]
public interface Dummy { }
A coclass supplies concrete
implementation(s) of one or more
interfaces. In COM, such concrete
implementations can be written in any
programming language that supports COM
component development, e.g. Delphi,
C++, Visual Basic, etc.
See my answer to a similar question about the Microsoft Speech API, where you're able to "instantiate" the interface SpVoice
(but really, you're instantiating SPVoiceClass
).
[CoClass(typeof(SpVoiceClass))]
public interface SpVoice : ISpeechVoice, _ISpeechVoiceEvents_Event { }
Best Answer
Place the component registered at COM+, this put an isolation layer at your.
Use : Control Panel->Administrative Tools
or cmd/execute DCOMCNFG
Component Services->Computers->My Computer->COM+ Application, right click, new application, next, Create an empty application, enter app name “COM+ your.dll”, next, select Local Service, next, next, next, finish.
In new item made, expand, at Components, right click, new component, next, select Install new component, select your component.
Click Component properties, tab Identity, select System Account.
For errors in calls see Event after.