Why no intellisense in VB6? - com

I wrote a DLL in C# in VS2012:
namespace COMTest
{
public class MyClass
{
public int Fun()
{
return 3;
}
}
}
And then I set "Make Assembly COM Visible=True" and in the Build page, I set "Register COM for intercrop". Then create a new VB6 project, add a reference to the generated dll file but failed……Later tried tlb file succeeded but without intellisense after saying "a." (No "Fun" tip)
Dim a As MyClass
Set a = New MyClass
MsgBox (a.Fun())
So my questions are:
1) Why must I refer tlb file instead of dll file?
2) Why no intellisense?

Try placing a check mark in:
Tools->Options->Editor->Auto List Members
If that does not help, then to resolve this problem, define a public interface by using methods and properties that you want to expose in the TLB, and then implement the interface in the class. Also, add the ClassInterface (ClassInterfaceType.None) attribute to the class. As you develop the component, you can use this approach to avoid using the ComVisible(False) attribute.
You can have more details here

Related

Calling C# method from VBA using COM Interop

By refering this, I was able to attach Entities.tlb file to VBA. But I couldn't able to create an instance from the classes in C#. This is my code,
C# class
namespace Entities
{
[Guid("1558C766-44DA-4DA5-BF2F-CBD6804E7E21")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface ITools
{
ABC GetABC();
}
[Guid("514719AC-E137-4FCA-82AF-73E4025A8625")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class Tools : ITools
{
public Tools()
{
}
public methods ...
}
}
From VBA,
Dim objElement As New Entities.Tools
This caused Error : Invalid Use Of New Key Word
And also in VBA object browser,for attached Entities.tlb it shows all the classes under Entities namespace. But It's not showing any method inside those classes.
How can I create a instance of Tools class in VBA and access methods in Tools class from VBA ?
Delete the constructor. VBA can't use them and c# will implement the default constructor transparently..
Then try in the class
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(ITools))]
and in the interface
Just
[ComVisible(true)]
Then in VBA
Dim objElement as Tools
set objElement = new Tools
I have a C# class that I access from VBA and this is the only way I've found that gives intellisense in VBA and still allows items such as GetEnumerator to work correctly.
Kvp C# dictionary wrapper for VBA
You should also be aware that if you have an indexer in your class then the .Item[x] syntax will only work in if you choose to not have intellisense. If you have intellisense then then the use of .Item[x]=value will generate a VBA error due toa bug in how the intermediate language is constructed for the indexer.

VB.net load dll

I have been attempting to load a DLL using Reflector
Imports System.Reflection
I have a simple DLL file written in c++ using /CLR (this is the entire file)
using namespace System;
namespace ASSEMBLE{
public class REM{
public:
int VALUE(){
return 100;
}
};
};
And inside my VB.net butten click event i have
Dim dllPath As String = "C:\Users\richard\Documents\Visual Studio 2012\Projects\link\link\bin\Release\dlltest.dll"
' load the assembly
Dim assembly1 As System.Reflection.Assembly = Assembly.LoadFrom(dllPath)
' get the type
Dim t As Type = assembly1.GetType("ASSEMBLE.REM")
' create an instance and add it.
Dim c As Object = Activator.CreateInstance(t)
MsgBox(t.InvokeMember("VAULE", BindingFlags.Default Or BindingFlags.InvokeMethod, Nothing, c, {}))
When event triggered (ie. i load the dll) i get the error:
Method 'ASSEMBLE.REM.VALUE' not found
Using:
<DllImport("DLL.dll")> Public Shared Function VALUE() As Integer
End Function
is not an option. I need to load the DLL after runtime.
Your REM class is an unmanaged class, and therefore reflection cannot see its methods. Using the /CLR compile option does not automatically force all classes to be managed. It just allows you to have managed classes in your project.
To allow the call to InvokeMember, you need to make REM a managed class. This can be done by adding ref to the class declaration like so:
public ref class REM{
...
};

C++/CLI cannot access native member from different assembly

I have a C++/CLI dll where I have the source code but I cannot modify it and I have my own dll where I want to access a member variable:
Assembly 1 (cannot be modified):
public ref class A
{
public:
int m_iInteger;
SomeClass* m_pPointer;
};
Assembly 2 (own):
A^ a;
int i = a->m_iInteger; // no problem
SomeClass* x = a->m_pPointer; // C2248
The Problem is that the compiler shows an error:
error C2248: 'A::m_pPointer' : cannot access private member declared in class 'A'
The "Object Browser" shows:
public SomeClass* m_pPointer Member of A
Is there any way to access an native public member from a different assembly?
I'm using Visual Studio 2012
Edit:
class "SomeClass" is defined in a native dll (which I cannot modify too)
Edit 2:
I have found a Solution. Its not very nice but it works:
System::Reflection::Pointer^ ptr = (System::Reflection::Pointer^)typeof(A)->GetField("m_pPointer")->GetValue(a);
SomeClass* result = static_cast<SomeClass*>(System::Reflection::Pointer::Unbox(ptr));
All native types are private by default (in terms of managed accessibility outside the assembly). So, even though it is listed as public, since the type SomeClass is private, it makes it inaccessible. You can change this by prefixing the the SomeClass definition with public (if you can modify the SomeClass source code). Or, if you can't modify the SomeClass source code, but you can modify code within that dll, you can use the pragma:
#pragma make_public(SomeClass)
That said, based on your description it sounds like you cannot modify Assembly1 at all, in which case you are out of luck.

Accessing .NET function exposed as COM in Excel

In Convert vba to vb6 and create a .dll - how to - hints, tipps and risks, it was discussed how to convert VBA code into VB.NET code and access the function in VB.NET as COM in Excel.
In Excel, the function has to be accessed this way via VBA:
Public Function getParameterNumberOfMaterial() As Integer
Dim myclass as New ExcelExample.ExcelVB
getParameterNumberOfMaterial = myclass.getParameterNumberOfMaterial()
End Function
This means for every VBA function exposed to the user, I have to write a wrapper as above when converting to VB.NET.
Is there a way to use the function directly without writing the VBA wrapper? That is, in Excel, the user can directly use getParameterNumberOfMaterial(), just like the orignal VBA function, without me writing a VBA wrapper.
You can certainly call .NET functions in a COM-visible .DLL directly from Excel, though you will need to modify them slightly to make then compatible with COM and Excel.
This example will be in C# since that's what I'm familiar with, but the concept should be the same in VB.Net.
Open a new Class project, and add a line to import the InteropServices library:
using System.Runtime.InteropServices;
Declare an interface that will contain the functions you want to call:
public interface ISample
{
object func1(int p1);
object func2(string p1);
}
Only functions listed in the interface will be available in Excel. Note the functions return type is 'object'. This is needed for Excel to properly display the result in the sheet.
Declare the class that will implement the interface, and be exposed via COM.:
[ClassInterface(ClassInterfaceType.None)] // the proper way to declare COM-visible classes
public class Sample : ISample
{
public object func1(int p1)
{
// sample implementation
object[,] retval = new object[1,1]
retval[0,0] = "a";
return retval;
}
public object func2(string p1)
{
// ....
}
Excel expects all return types to be two-dimensional arrays of objects, so you'll need to convert the return values of your functions this way.
You will also need to add a couple functions that will assist with registering and unregistering the DLL:
// helper function to get Registry key of given type
private static string GetSubKeyName(Type type)
{
return "CLSID\\{" + type.GUID.ToString().ToUpper() + "}\\Programmable";
}
// called when class is being registered
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
// register the automation DLL function will be visible to Excel
RegistryKey key = Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type));
if (key != null)
{
key.SetValue(string.Empty, Environment.SystemDirectory + #"\mscoree.dll");
}
}
// called when class is being unregistered
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
try
{
// remove automation DLL from registry
Registry.ClassesRoot.DeleteSubKeyTree(GetSubKeyName(type));
}
catch (Exception ex)
{
Debug.Print(ex.Message + ex.StackTrace);
}
}
In the Properties screen of your project, in "Application" tab, click "Assembly Information", and check "Make assembly COM-Visible". Click OK.
In "Build" tab, click "Register for COM Interop" near the bottom.
Build the project.
In Excel, click the Developer ribbon, click "Add-ins", "Automation" and scroll down to your project. It will be listed in the form [namespace].[classname]
You should now be able to call the functions directly in an Excel worksheet:
=func1(12)
There is also a post on this from an MSDN blogger, but it is quite old
P.S. If there is any part of this you need assitance with converting to VB.Net, please let me know and I can certainly assist.
There used to be a way up to excel 97 but was removed as a security risk. The call function could call functions from COM dlls. http://www.cpearson.com/excel/Call.htm

calling a class constructor present in a dll managed C++

I've a class created in a DLL (which uses /clr runtime, ManagedC++) and a constructor defined in that class. Code as follows:
//Following is defined in something.h//
namespace ABC
{
public ref Class XYZ
{
public: int a;
public: XYZ();
};
//In something.cpp, I've the below code to define the constructor of the class created//
#include something.h
namespace ABC
{
XYZ::XYZ()
{
a = 100;
}
}
Above project is built into a DLL
In another project, I try to use the Class XYZ as follows:
#include something.h
using namespace ABC;
//inside main, I've following code
{
ABC::XYZ^ prq = gcnew ABC:XYZ();
prq->a=200;
......
...
}
In this, I get the an error saying -
unresolved token (06000001) ABC.XYZ::.ctor
Could you please help what's the problem here?
The problem is that the linker can't find the definition of the constructor. It is located in another DLL. In a managed project, you solve that by adding a reference to the assembly. Right-click your project, Properties, Common Properties, Framework and References. Click the Add New Reference button. Use the Project tab if the project is located in the same solution. The Browse tab otherwise.
Also note that you now no longer need the .h file anymore. Declarations are imported from the metadata in the assembly.