Jump to content

Archive: Write SwyxIt! Plug-ins in C#


Tom Wellige
 Share


Recommended Posts

The following blog post is restored from the Swyx Forum Archive (2007-2014) and was posted originally at 24.11.2008 in "Martin's Blog".

 

There’s a software development kit for SwyxIt with a lot of useful examples. However,  SwyxIt’s roots are native, unmanaged C++, and most of the examples are in native code, too. Recently somebody asked in the forum if it’s possible to write a client plug-in in C#.

 

Unfortunately the interfaces a plug-in has to provide and which are called by SwyxIt are custom COM interfaces, not standard automation interfaces. In the latter case, the automatically created COM-callable wrapper for .NET types would work and you could just write a c# interface with a matching signature.

 

But it’s still possible. The .NET COM interoperability is is able to do a lot more than the automatic wrapper creation suggests. The first interface a SwyxIt line manager (ClMgr) plug-in has to implement is IClientAddInLoader. It’s purpose is not to provide a loader for the plug-in as the name suggests, but to provide an interface for ClMgr plugin loader to initialize and get information about the plugin. It looks like this:

 

  1: [
  2:     object,
  3:     uuid(f8e55372-4c00-11d3-80bc-00105a653379),
  4:     helpstring("IClientAddInLoader Interface"),
  5:     pointer_default(unique)
  6: ]
  7: interface IClientAddInLoader : IUnknown
  8: {
  9:     HRESULT Initialize([in] DWORD dwReserved);
 10:     HRESULT GetName([out] BSTR *pName);
 11:     HRESULT GetVersion([out] BSTR *pVersion);
 12:     HRESULT UnInitialize([in] DWORD dwReserved);
 13: };

 

Look at line 7. It’s derived from IUnknown. An automation interface would derive from IDispatch and would have the “oleautomation” attribute set. To instruct the .NET Framework to generate such an interface for a C# class you have to define it like this:

 

 1: [ComVisible(true)]
 2: [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
 3: [Guid("f8e55372-4c00-11d3-80bc-00105a653379"]
 4: [AutomationProxy(false)]
 5: public interface IClientAddInLoader
 6: {
 7:    [PreserveSig()]
 8:    [return: MarshalAs(UnmanagedType.Error)]
 9:           int Initialize([MarshalAs(UnmanagedType.U4), In()]int reserved);
10: 
11:    [PreserveSig()]
12:    [return: MarshalAs(UnmanagedType.Error)]
13:           int GetName([MarshalAs(UnmanagedType.BStr), Out()]out string name);
14: 
15:    [PreserveSig()]
16:    [return: MarshalAs(UnmanagedType.Error)]
17:           int GetVersion([MarshalAs(UnmanagedType.BStr), Out()]out string version);
18: 
19:    [PreserveSig()]
20:    [return: MarshalAs(UnmanagedType.Error)]
21:        int UnInitialize([MarshalAs(UnmanagedType.U4), In()]int reserved);
22: }

 

Line 1 defines with the COMVisibleAttribute that this interface is visible from COM. The InterfaceTypeAttribute on line 2 defines that it’s an IUnknown-based interface. The interface ID (IID) has to be defined with the GuidAttribute (line 3). This has to be the same IID as in the original interface definition. The AutomationProxyAttribute Line 4 completes the interface attributes by defining that the standard automation proxy will not be used.

The interface method definitions are mostly straight-forward. The MarshalAsAttribute, InAttribute and OutAttribute declarations for the method parameter are probably not necessary, because the framework can derive that from the method signature itself. But better safe than sorry. Essential is the PreserveSigAttribute. Without it the .NET framework would expose a method like an automation method. Example. For a native COM application without that attribute the IClientAddInLoader.Initialize method would look this:

 

HRESULT Initialize([in] DWORD dwReserved, [out,retval]long* pReturnValue);

 

If your implementation returns a value the caller which uses COM would get that value in *pReturnValue and the HRESULT would be S_OK. If you would throw an exception, the framework would return an error HRESULT to the caller. But we need to provide exactly the interface methods SwyxIt expects and PreserveSignatureAttribute allows us to do that.

 

To implement the interface just create a C# class inheriting from the interface above. That class needs some attributes, too:

 

  1: [ComVisible(true)]
  2: [Guid("373767E9-2953-42f9-98CA-63A232BC5B6F")]
  3: [ClassInterface(ClassInterfaceType.None)]
  4: public class SampleAddIn 
  5:    : IClientAddInLoader, IClientResolverAddIn
  6: {

 

First (line 1) we declare that this managed type should be visible from COM. Next on line 2 we define the COM object class ID (CLSID). Last, but not least (line 3) we declare that this class has no COM class interface. If you would use ClassInterfaceType.AutoDispatch or AutoDual the framework would expose all public non-static methods of that class to COM. With ClassInterfaceType.None no methods will be exposed. This does not effect the inherited interface, but it ensures that no other methods of your class are accidentally exposed to COM. When you’re done with your implementation register your assembly with

 

regasm.exe /codebase SampleAddIn.dll

 

Last, but not least you have to create a registry key for SwyxIt to find your plugin (as described in the Client SDK dokumentation). Create a new registry key at location

HKLM:\software\swyx\client line manager\currentversion\options\plugins.

Key name is the CLSID of your object, i.e. the GUID you declared with the GuidAttribute of your managed type.

 

Here’s an example which implements IClientAddInLoader and IClientResolverAddIn:

 

CSharpAddIn.zip

 

 

Have fun and start writing SwyxIt! plug-ins in any .NET language you like.

 

[Edit: Added missing information about assembly registration]

 

Link to comment
Share on other sites


Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share


×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and have taken note of our Privacy Policy.
We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.