views:

609

answers:

5

Hi, i am trying to call a method i have written in c# from vbscript.

I have followed just about all of the instructions i can find on the web and am still having problems.

Specifically i am getting the error, ActiveX component can't create object, Code: 800A01AD.

So far i have done the following..

1] Set ComVisible(true)
2] Registered using /codebase
3] Strong named my assembly
4] Confirmed it is in the registry and points to the correct location
5] Made the class public
6] Have no static methods
7] Made the method i want to call public
8] Have a parameterless constructor
9] Explicitly defined a Guid

My vbscript looks like this..

set oObject = CreateObject("TTTTTT.FFFFF.CCCCCCCCC")

My c# code looks like this..

using System;
using System.IO;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace XXXXX.YYYYY
{
    [ComVisible(true)]
    [Guid("3EB62C37-79BC-44f7-AFBD-7B8113D1FD4F")]
    [ProgId("TTTTTT.FFFFF.CCCCCCCCC")]
    public class CCCCCCCCC
    {
        public void MyFunc()
        {
            //
        }
    }
}

Can anyone help?

+1  A: 

Have you read this article: COM Interop Exposed

In the last page (3) of the article, there's a list:

  1. Define a .NET Interface for the methods you want to expose to COM.
  2. Assign a GUID to that interface with the "Guid" attribute.
  3. Have your class implement your interface as the first interface.
  4. Assign a GUID to that class with the "Guid" attribute.
  5. Add the "ClassInterface(ClassInterfaceType.None)" attribute to prevent regasm/tlbexp from creating an empty default interface.
  6. Hard-code a specific version number in your AssemblyVersion attribute.
  7. Create a strong-name key pair for your assembly and point to it via the AssemblyKeyFile attribute.
  8. Add your assembly to the GAC,
  9. Register your assembly for COM by using the REGASM command along with the "/tlb" option to generate a COM type library.

I'm not sure if the GAC and ClassInterfaceType.None are the missing pieces of your puzzle, you might want to give it a try. Good luck!

o.k.w
thanks for your response o.k.w. i have checked all of the items in the article and unfortunely i am still getting the same error.
Grant
Perhaps you can code from scratch a component from those sample codes and see if it works. If it doesn't, maybe the problem lies elsewhere and not your code. Sorry I couldn't offer more assistance.
o.k.w
A: 

Here's a simple project with only a few steps, to get you started.

C# code:

using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[assembly:System.CLSCompliant(true)]
[assembly: ComVisible(true)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("7d9c5cd3-73d4-4ab1-ba98-32515256c0b0")]

namespace Cheeso.ComTests
{
    [Guid("7d9c5cd3-73d4-4ab1-ba98-32515256c0b1")]
    public class TestReply
    {
        public string salutation;
        public string name;
        public string time;
    }

    [Guid("7d9c5cd3-73d4-4ab1-ba98-32515256c0b2")]
    public class TestObj
    {
        // ctor
        public TestObj () {}

        public TestReply SayHello(string addressee)
        {
            return SayHello(addressee, "hello");
        }

        public TestReply SayHello(string addressee, string greeting)
        {
            string x = String.Format("{0}, {1}!", greeting, addressee);
            Console.WriteLine("{0}", x);

            TestReply r = new TestReply
            {
                salutation = greeting,
                name = addressee,
                time = System.DateTime.Now.ToString("u")
            };
            return r;
        }
    }
}

VBScript client code:

Function Main()
    Dim obj
    Dim reply
    set obj = CreateObject("Cheeso.ComTests.TestObj")
    Set reply = obj.SayHello("Evgeny")
    WScript.Echo "Reply at: " & reply.time
    Set reply = obj.SayHello_2("Evgeny", "wassup")
    WScript.Echo "Reply at: " & reply.time
End Function

Main

To build:

(produce your .snk file, once)
csc.exe /t:library /debug+ /keyfile:Foo.snk /out:TestObj.dll TestObj.cs
regasm /codebase TestObj.exe

Then just run the vbscript (through cscript.exe).

Once you get the basic thing working, you can tweak it, add GAC, make the typelib explicit, add an explicit ProgId, and so on.

ps: FYI, this example shows what happens with overloaded .NET methods on a class registered for interop. There's an implicit _2 (_3, _4, etc) appended to the method name.

Cheeso
+1  A: 

There isn't anything really wrong with your code and you followed the correct install procedure, by the sound of it. The error code you get however clearly indicates that the script interpreter has trouble locating or loading the assembly. The best way to troubleshoot this is with SysInternals' ProcMon utility.

I ran your code without trouble, these were the most relevant entries in the ProcMon log:

22  12:04:41.1795038 PM WScript.exe 55280 RegOpenKey HKCR\TTTTTT.FFFFF.CCCCCCCCC SUCCESS Desired Access: Read
26  12:04:41.1795682 PM WScript.exe 55280 RegOpenKey HKCR\TTTTTT.FFFFF.CCCCCCCCC\CLSID SUCCESS Desired Access: Read
29  12:04:41.1796996 PM WScript.exe 55280 RegQueryValue HKCR\TTTTTT.FFFFF.CCCCCCCCC\CLSID\(Default) SUCCESS Type: REG_SZ, Length: 78, Data: {3EB62C37-79BC-44F7-AFBD-7B8113D1FD4F}
34  12:04:41.1797653 PM WScript.exe 55280 RegOpenKey HKCR\CLSID\{3EB62C37-79BC-44F7-AFBD-7B8113D1FD4F} SUCCESS Desired Access: Read
62  12:04:41.1802539 PM WScript.exe 55280 RegOpenKey HKCR\CLSID\{3EB62C37-79BC-44F7-AFBD-7B8113D1FD4F}\InprocServer32 SUCCESS Desired Access: Read
71  12:04:41.1804181 PM WScript.exe 55280 RegQueryValue HKCR\CLSID\{3EB62C37-79BC-44F7-AFBD-7B8113D1FD4F}\InprocServer32\(Default) SUCCESS Type: REG_SZ, Length: 24, Data: mscoree.dll
824 12:04:41.2425662 PM WScript.exe 55280 RegQueryValue HKCR\CLSID\{3EB62C37-79BC-44F7-AFBD-7B8113D1FD4F}\InprocServer32\1.0.0.0\CodeBase SUCCESS Type: REG_SZ, Length: 124, Data: file:///c:/projects/ClassLibrary2/obj/Debug/ClassLibrary2.DLL
... Lots of .NET keys...
1239    12:04:41.2970169 PM WScript.exe 55280 CreateFile C:\projects\ClassLibrary2\obj\Debug\ClassLibrary2.dll SUCCESS Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
Hans Passant
A: 

May be, all of your problems are caused by VS. Try to compile your library from the command line by typing

csc.exe /t:library AClass.cs /keyfile:Foo.snk - produce your key file with VS!
regasm /codebase /tlb AClass.dll

VS are adding some stuff like /warn: /noconfig and so on, and also it adding references to another assemblies like System.Core and so on, and sometimes causes the erros. For me, compiling from csc worked.

VMAtm
A: 

I've been having the exact same issue as the writer, and none of the suggestions above are working.

The interesting thing is that the application that also calls it using IDispatch calls (SAPGUI in this case) does successfully instantiate the component and calls methods on it.

The more interesting thing is that the objects I've been using and the script that I'm using have worked on my Windows XP and Windows 2003 Server systems.

HOWEVER, the system I'm working on now, a Win7 64-bit system with UAC on, is not working.

UPDATE:

I wrote a test MFC application to do a ProgID->CLSID conversion, call CoCreateInstance and then QI to IDispatch like what VBScript CreateObject does, and it worked.

Until I realized that it built a 32-bit process, and the WScript.exe engine is 64-bit.

I rebuilt for 64-bit and tried invoking my object again and this time I got an HRESULT of 0x80040154 (class not registered).

Is it possible that regasm.exe only registers .NET components for the 32-bit hive AND NOT the 64-bit component library?

UPDATE 2: I think I got it. If you want your component to be used by any 64-bit processes (including wscript or cscript), you need to use the 64-bit regasm.exe (under the %SYSTEMROOT%\Microsoft.NET\Framework64\v2.0.50727) assuming the assembly is building under "AnyCPU", not a specific flavor.

Eli