Can't load .NET dll from ruby

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...

c#
ruby
dll
com
win32ole
asked on Stack Overflow Dec 14, 2016 by Itzik984 • edited Jun 20, 2020 by Community

2 Answers

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.

answered on Stack Overflow Dec 14, 2016 by Joseph Willcoxson • edited Dec 14, 2016 by Joseph Willcoxson
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.

answered on Stack Overflow Dec 15, 2016 by Itzik984

User contributions licensed under CC BY-SA 3.0