tags:

views:

93

answers:

2

OK, so I have a C++ project that compiles to a DLL file. I am able to reference this file in C# and see/use all of the objects and functions within the DLL file. What I need to do is to reference those objects and function through VB6.

The C++ code has nothing in it that looks like it's creating a DLL. There are no '__declspec(dllexport)' modifiers, just C++ code.

There are objects like this:

String ^
Array^

I'm not entirely sure what they are. My knowledge of C++ is not very extensive and I've only coded in C++ for Linux systems, although from the usage they sort of look like pointers. Do these objects have anything to do with a DLL in C++?

Anyway, I can add any wrappers that I need or add a definition file (.def), although I do not know what wrappers to use and I don't know how a definition file works or how it needs to be constructed.

Any help and/or suggestions are appreciated. If you can refer me to some good info as well, that would be helpful. All searching I have done has not helped.

Remember, I need to access all functions and objects in this C++ DLL from VB6.

Thanks.

EDIT: Added .h file and AssemblyInfo.cpp spec to the question

I changed some names in these files, but the structure is the same. Note that this references other files, but I assume that if one can be made to work then the others can with the same process. I can see every object, just not the methods:

//myDBObject.h
#pragma once
using namespace System;
namespace myDBNamespace {

#include "ProblemSolution.h"

public ref class MyDataBaseAccessor
{
public:
    MyDataBaseAccessor();

    static  String ^    GetServiceVersion() { return sDLLVersion;};
    int                   GetServiceStatus() { return myiDBStatus;};
    String ^                GetMyVersion();
    String ^                GetDBVersion();
    String ^                GetDLLVersion();
    String ^                GetExpireDate();

    MyOtherObject ^         GetMyOtherObject();

    int             ProcessProblem(ProblemSolution ^ dsps);

private:
    static  MyDataBaseController ^  myDataBase;
    static  MyOtherObject ^         myObjs;
    static  MyDataset ^     myDS;
    static  String ^                myDBPath;

    static  String ^                sDLLVersion = "0.01";
    static  String ^                sReqDBVer = "0.01";
    static  int                     myiDBStatus;
    static  bool                    myBoolean, myOtherBoolean, mybNoChain;

};
}

Here is the AssemblyInfo.cpp file:

#include "stdafx.h"

using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::CompilerServices;
using namespace System::Runtime::InteropServices;
using namespace System::Security::Permissions;

//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly:AssemblyTitleAttribute("My Product Title")];
[assembly:AssemblyDescriptionAttribute("")];
[assembly:AssemblyConfigurationAttribute("")];
[assembly:AssemblyCompanyAttribute("My Company")];
[assembly:AssemblyProductAttribute("My Product Name")];
[assembly:AssemblyCopyrightAttribute("My Copyright")];
[assembly:AssemblyTrademarkAttribute("My Program")];
[assembly:AssemblyCultureAttribute("")];

//
// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the value or you can default the Revision and Build Numbers
// by using the '*' as shown below:

[assembly:AssemblyVersionAttribute("1.0.*")];

[assembly:ComVisible(true)]; //Here is the ComVisible tag. It was false and I set it to true

[assembly:CLSCompliantAttribute(true)];

[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = false)];
+2  A: 

I'm not entirely sure what they are.

You are not looking at C++ code, but at C++/CLI code, a language targeting the managed .NET platform. This is also why you can easily use this DLL in C#.

Honestly, if you want to use managed objects in Visual Basic 6, COM Interop is your best bet. Either create a wrapper or directly expose the objects contained in the DLL via COM Interop.

Edit:

Basically, you expose objects by using attributes, i.e. you annotate your types in source code with attributes. Those are documented here: System.Runtime.InteropServices

Have a look at: Introduction to COM Interop

Also, the COM Interop "bible" is this book by Adam Nathan: .NET and COM: The Complete Interoperability Guide

There is also an article dealing with how to expose a COM object and use it in VB6: http://www.15seconds.com/issue/040721.htm

Jim Brissom
OK, how do I do that? Completely in the dark on this one, as I've never done COM interop programming before, let alone in C++. How do I wrap the objects/functions? how do I expose the DLL with interop?
Mike Webb
+1  A: 

Use regasm to create a COM Type Library (.TLB) file from your C++/CLI assembly.

You should now be able to reference the C++/CLI code by referencing the TLB file in your VB6 code. From the example there:

In its simplest form, you can do:

REGASM MyAssembly.dll

Now, all of the COM-compatible classes are registered as COM objects. You can fire up VB6 and start writing code:

Dim net As Object

Set obj = CreateObject("NETProject.Foo")
obj.Move

Pretty easy. Except that you're late binding because you don't have a COM type library.

No problem! REGASM can generate a type library for you and even register it:

REGASM MyAssembly.dll /tlb:MyAssembly.tlb

Now, in VB6 you can add a reference to the type library and use early binding:

Dim net As Foo

Set obj = New NETProject.Foo
obj.Move

EDIT: Make the class COM visible like this:

[ComVisible(true)]
public ref class MyDataBaseAccessor
Steve Townsend
Tried that. I was able to reference it, but I could not see any of the objects or methods.
Mike Webb
@Mike - You should be able to view the TLB file in OLEVIEW.EXE - do you see the stuff you want to access?
Steve Townsend
@Steve - In oleview the TLB file is empty except for the UUID, version etc. The declaration 'library MyObject{ }' is empty.
Mike Webb
@Mike - the code in the C++/CLI DLL needs to be tagged `ComVisible` for this approach to VB6 integration to work. Can you verify that? http://msdn.microsoft.com/en-us/library/ms182157(v=VS.100).aspx
Steve Townsend
@Steve - Wish I'd known it was that simple. lol Found the line '[assembly:ComVisible(false)];' in AssemblyInfo.cpp file. Changed it to 'true' and I can see everything now. Thanks for the help.
Mike Webb
@Mike - nice, glad it's working now. You don't need this for C# because C++/CLI interoperates as a peer managed language, not via COM.
Steve Townsend
@Steve - Now I have a new issue. The objects are all visible, but the methods of those objects are not. When I try to call one it gives me the error, "Automation error The system cannot find the file specified." Placing the ComVisible tag on individual functions in the .h and .cpp files does nothing. Methods and properties of coClasses are empty in oleview. Suggestions?
Mike Webb
@Mike - can you include the .h file in your question?
Steve Townsend
@Steve - Added the .h file and the AssemblyInfo file where the ComVisible tag is located.
Mike Webb
See EDIT - have you tried that?
Steve Townsend
Yes. Added the attr on the class, individual methods, and the namespace, both with and now without that attr in the AssemblyInfo file. Tried it like this: [assembly: System::Runtime::InteropServices::ComVisible(true)]; with 'assembly:' in the attr. If I do it without 'assembly:' in the attr it gives me a "anonymous usage not allowed" error and won't compile. If I add the attr at multiple levels (i.e. on the class and on one of its methods) it gives me an "attribute cannot be repeated" error and won't compile.
Mike Webb
@Mike - Tagging assembly and class should expose all public methods. have you tried to use this in the VB6 code or just in OLEView?
Steve Townsend
@Steve - Both. Added project->reference to the TLB file in VB6. It gives me a list of the objects, but none of their members.
Mike Webb
@Mike - I am sorry, I can't think of anything else to try at this point...
Steve Townsend
@Steve - No worries. Again, thanks for the help. I'll comment if I find the answer to this new issue.
Mike Webb
Do you know if I need to manually write an interface for each class?
Mike Webb
@Mike - that should not be necessary. If the assembly and class are COM-visible all public members should be available.
Steve Townsend