0

I have followed the steps described in this question:

Can Ruby import a .NET dll?

And so, i have this c# code:

using System;
using System.IO;

namespace ComLib
{
    public class LogWriter
    {
        public void WriteLine(string line)
        {
            using (var log = new StreamWriter(File.OpenWrite(@"c:\log.file")))
            {
                log.WriteLine(line);
            }
        }
    }
}

Under a solution named: RubyToCSharp

I checked the Register for COM interop in VS and created the following ruby code:

require "win32ole"

lib = WIN32OLE.new('RubyToCSharp.ComLib.LogWriter')
lib.WriteLine('calling .net from ruby via COM, hooray!')

And now i tried to run this ruby from powerShell and i keep getting this error:

./exmpl.rb:4:in `initialize': unknown OLE server: `RubyToCSharp.ComLib.LogWriter' (WIN32OLERuntimeError)
    HRESULT error code:0x800401f3
      Invalid class string
        from ./exmpl.rb:4:in `new'
        from ./exmpl.rb:4:in `<main>'

Any thoughts on what i am missing out over here?

EDIT

After checking if my dll was register according to this SO question, It seems that indeed my dll is registered, but still, the same error happens.

Really confused over here...

Community
  • 1
  • 1
Itzik984
  • 15,968
  • 28
  • 69
  • 107

2 Answers2

1

Only classes that are marked ComVisible will be exported to the appropriate keys during registration. It's also a very, very good idea (I'd say mandatory) to have a Guid attribute instead of taking the default which can change during every compilation. You can also have your own ProgId attribute, but often the default of Namespace.ClassName is sufficient (where Namespace is the namespace your class is in and ClassName is the name of your class).

Try this:

using System;
using System.IO;
using System.Runtime.InteropServices;

namespace ComLib
{
    [ComVisible(true)] // needs to be marked ComVisible 
    [Guid("ad4c28c9-4612-4ac3-8ca4-04a343f4f2b9")] // generate your own
    public class LogWriter
    {
        public void WriteLine(string line)
        {
            using (var log = new StreamWriter(File.OpenWrite(@"c:\log.file")))
            {
                log.WriteLine(line);
            }
        }
    }
}

That's what I see from the .NET side. I don't have any experience with trying to consume from Ruby.

It will also help if your Ruby process is 32-bit. VIsual Studio generally only registers the class with the 32-bit runtime system on 64-bit OSes.

For standalone registration outside of the IDE, use something like:

regasm.exe /tlb /codebase YourDll.dll

Make sure you use the regasm.exe for the correct .NET runtime and correct 32/64-bit flavor.

If your DLL is registered correctly with COM, it should be callable via VBScript. Make a simple VBScript called Test.vbs:

Dim obj
set obj = CreateObject("ComLib.LogWriter")
MsgBox TypeName(obj)

If you double click on the filename, in explorer or just type test.vbs from the command line shell it will try to run the VBS program with wscript.exe in c:\windows\system32\wscript.exe.

It will probably fail on a 64-bit OS because by default VS only registers the .NET assembly for COM with the 32-bit subsystem. To try and run it on the 32-bit subsystem, try:

c:\windows\syswow64\wscript.exe test.vbs

If either of those methods fails, then your DLL is not registered correctly.

Joseph Willcoxson
  • 5,853
  • 1
  • 15
  • 29
  • Thanks for the answer joe, Couple of things: 1) [assembly: ComVisible( false )] could be at the AssemblyInfo.cs file and will make all classes com visible (i have this configured) at my project. 2) I need to understand, if it is registered via VS15, does this mean this dll is available through out the entire OS? or is it "alive" only in the VS15 dir? – Itzik984 Dec 14 '16 at 15:18
  • The entries in the registry necessary for COM will be throughout the entire OS assuming that you run VS as an elevated administrator. A quick trick to test if it is working is to write a VBS script: `Dim obj` `set obj = CreateObject("ComLIb.LogWriter")` `MsgBox TypeName(obj)` Having trouble... Run it via c:\windows\system32\wscript.exe and run it via c:\windows\SysWow64\wscript.exe By default it should succeed with the one in the SysWow64 directory. THis will tell you whether it is registered correctly. – Joseph Willcoxson Dec 14 '16 at 15:21
  • Ok, thanks once again... Still have no idea what is going wrong over here. seems like im doing everything as i should. – Itzik984 Dec 14 '16 at 15:24
  • You should still declare a Guid for your class. – Joseph Willcoxson Dec 14 '16 at 15:33
0

Solved it, in what might seem to be a rather weird solution.

Changed this:

lib = WIN32OLE.new('RubyToCSharp.ComLib.LogWriter')

To this:

lib = WIN32OLE.new('ComLib.LogWriter')

And everything worked.

Itzik984
  • 15,968
  • 28
  • 69
  • 107