I am writing an application using C# and WinForms. I have an ActiveX control provided by a third party. I drag the ActiveX control to a form, and get an instance of the class (call it "Widget") that the control implements.
Now I need to pass an interface pointer, IWidget, from C# into legacy C++ code. I plan to put the C++ code in a dll and call it from C# using P/Invoke. The problem is I don't know how to provide the IWidget definition to the C++ code. The original authors of the C++ code had header files (say widget.h), so they could #include widget.h, and declare an IWidget pointer.
I don't have the .h (and can't get it). I only have the ActiveX. So how can I declare an IWidget pointer in my dll?
My only idea so far is to create an IDL file from the ActiveX dll. Is that a reasonable approach?
Thanks,
Mark
You can try import metadata from ActiveX with tlbimp.exe which create managed assembly and IWidget should be there. If you create class with this managed version of interface and [ClassInterface(ClassInterfaceType.AutoDispatch)], it should pass through to ActiveX.
See howto for tlbimp activex-wrap
Related
I have the COM idl definition file, and i have a VB project that demonstrate how to communicate thru an application thru COM.
unfortunately, i cannot straight up port the VB code to C#.
The COM is written in C++ and is reference by its program id
How can I instantiate the COM from C# and call functions from there?
here is the vb code
Dim DrCephPatient As Object
SampleCom = CreateObject("Sample.SampleCOM")
SampleCom.Attribute1= "Hello"
SampleCom.Method1(1)
Also, since i have the IDL definition, i have the UUID i can use to access.
Any resources I need to read to make this work?
You just need to add a COM reference to your C# project.
The COM tab of the Add Reference dialog window lists all COM components that are available for referencing. If you want to add a reference to a registered COM DLL that contains an internal manifest, unregister the DLL first. Otherwise, Visual Studio adds the assembly reference as an ActiveX control instead of as a native DLL.
If a project type doesn't support COM, the tab doesn't appear in the Reference Manager dialog box. Read more about that in the How to: Add or remove references by using the Reference Manager article.
After adding a COM reference you can use your component as a regular .net classes (using the interop library generated automatically behind the scene).
Using C#, you can quasi get it to perform like VB script code by using Type.GetTypeFromProgID(), the Activator class, and using the dynamic type. I wouldn't necessarily prefer this, though. It's better to add the COM reference to your project. In my example I'm using, Word which runs out of process (is an .exe) so it will work with 32-bit or 64-bit versions of the runtime. However, for an in process server (.dll), the bitness of your code and the server need to match (either both 32- or 64-bit). However, for a quick test, this sometimes will do the job.
using System;
class Test {
public static void Main(string[] args) {
Type t = Type.GetTypeFromProgID("Word.Application");
dynamic word = Activator.CreateInstance(t);
Console.WriteLine("Word title:" + word.Name);
word.Quit(); // otherwise hanging reference ... is Word API specific
}
}
You can use the SerialPort Class
https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport?view=dotnet-plat-ext-5.0
Basically works with Open, Write/Read and Close functions but it's in C#, I guess it's not exactly what you look for
Also there is this list of articles about VB that could help you
https://learn.microsoft.com/en-us/dotnet/visual-basic/developing-apps/programming/computer-resources/accessing-the-computer-s-ports
I have a UI in C# that loads a C++ Dll which contains the code of some process.
So the C# has an interface to communicate with the C++ dll using DllImport.
Now I would like to use the same C# UI but with a different C++ Dll which will have the same function call but totally different process inside.
So basically, in function of some parameters, my UI will load one or the other C++ DLL.
I have tried to create a string variable containing the name of the dll but it doesn't work.
I know I could create a c++ dll which could do the interface between the c++ and the c# code and could load one or the other c++ dll but if it is possible to do it without introducing a new dll, that would be better.
Do you know if there is a way to do that?
Thanks a lot for your help.
I need to create a .lib file from a C# DLL (I think it is C# becuase of this code which calls to the dll https://code.google.com/p/thunder-missile-api/downloads/detail?name=MissileLauncher.cs&can=2&q=) In other word's I need to create a .lib for DreamCheeky Thunder Missile Launcher DLL, which comes with their software .
Now, what I need to do? I need to operate this device using C++. Easiest way is using their own DLL. The above linked code does it in C#.
I tried importing the DLL file into the project C++, but it seems like some methods are missing, specially methods like moveMissileLauncher() which are called in the C# code.
And the best thing is, I might want to move to QT (most probably) so you know, having a .lib is a good idea.
Crating a lib from a managed dll will do no good. You need to use interop
http://msdn.microsoft.com/en-us/library/ms973872.aspx
In your specific case, I would write a C++ lib that exposes the methods you need/want to call and forwards them to the managed C# dll using interop
I would do that in C++/CLI, personally.
A good, more recent article on the options you have is here http://msdn.microsoft.com/en-us/magazine/dd315414.aspx, or look here on SO for COM/.NET interop and you will find plenty of answers.
You want to call managed C# code from your c++ application. Here is tutorial to make someway to call c# code from your c++ application, i have used this method before, and works fine for me.
In an earlier post Passing pointer from managed C++/CLI to ActiveX C++ component I've asked about the correct means to pass an array (whether managed or unmanaged array) to an activeX component created in native C++.
The activeX method has the following signature:
short Component::CopyToBuffer(short FAR* ptr) {}
when the activeX is imported to be used in C++/CLI
the method signature is displayed as
short Component::CopyToBuffer(short% ptr) {}
when imported in C# it is displayed as
short Component::CopyToBuffer(ref short ptr) {}
However, I was not able to pass the array correctly.
whether native array: short* shortsArray = new short[500];
neither a managed array: array<short>^ shortsArray = gcnew array<short>(500);
users ildjarn and Hans Passant suggested that I need to edit the interop assembly file to change the exported method signature to something like Component::(int16[] ptr) which I did and successfully compiled the project but ran into other kind of problems (type mismatch or something).
So now I've made a sample project that reproduces the problemnSolution
The solution contains:
A project for the ActiveX component with one method CopyToBuffer found in SomeCompCtl.h
A test project in C++/CLI. with a single form that has the activeX added to it and a button calls the method with an array of given values.
Another test project in C# that does the same thing
To run the project:
- Simply compile SomeComp to generate Somecomp.ocx which contains the ActiveX.
- regsrv32 the ActiveX control
Please note that I don't access to the ActiveX code (I've had access to one version of code but I cannot presume that the developers will continue to provide me with updated versions of code) so any solutions shouldn't depend on changing the ActiveX interfaces or code. I normally only have the ocx file with its tlb file.
With the signature as CopyToBuffer(short% ptr), how did you call it? If you did CopyToBuffer(myArray[0]) or CopyToBuffer(&myArray[0]), that could fail because the garbage collector could move the array on you. Try this:
pin_ptr<short> pinned = &myArray[0];
component->CopyToBuffer(pinned);
If that doesn't work, try editing the interop assembly file again, change the signature to CopyToBuffer(IntPtr ptr). Since it's more explicit about the fact that the parameter is a simple pointer, perhaps that will work better.
Say we have an existing process (or application) that calls a COM object from an ocx file such as "MyCOMLibrary.ocx".
Is there a way to write a C# library to exactly replicate the ocx file? So that the original application can call your C# code rather than the original COM object?
You would, of course, have to use identical CLSID and ProgIDs as the original ocx. And assuming there is no signing involved, such as a SNK in the .Net world.
Also, are there any tools that exist to automate this? Something that takes in an ocx and spits out a C# file with methods to implement.
EDIT: I want to add that the original application is VB6, and does not use .Net at all. They are most likely loading the ocx as a VB6 app would (ProgId or Guid). Does this cause any issues?
We also have no problem with completely rewriting the ocx--we will most likely just return success error codes for all methods and only use methods/events required by our situation.
EDIT: You would think this would not be too difficult to accomplish. Can we make a VB6 ocx file that could replace the old ocx, and just pass all calls to a .Net assembly?
EDIT: I tried using the following open source library: EasyHook
But it seems like this question should still be viable. VB6 seems to load COM objects in a way that prevents hooking. I don't see a way to hook instance methods on a class/interface or a class's constructor with EasyHook.
You can use ActiveX Import AxImp to import the OCX, create a wrapper class and then call that. The program is described here: http://msdn.microsoft.com/en-us/library/8ccdh774(VS.80).aspx
Basically, what you need to do is execute the following on the commandprompt:
c:/>AxImp MyControl.ocx
result is a MyControl.dll and an AxMyControl.dll. The first you can use as a normal .NET DLL in your projects (i.e., without a graphical user interface), the second can be used to be drawn on a form as you normally would with any other control like a TextBox or a Label.
To use it, go to Visual Studio, rightclick your project and select Add Reference. Browse to the newly created DLL and add it. That's all.
Our Deviare Hook Library can be used for hooking COM objects. You can see an article from our blog related to this topic: Hooking Outlook COM objects with Deviare
Apparently VBMigration Partner can automatically upgrade a VB6 COM component to a VB.Net component that has binary compatibility with the original VB6 component. I don't know whether it supports OCXs. If it does, I'd suggest use that first and then try to go to C# later (if necessary).
Not really a complete answer to the question, but something I think might be useful. If you add a key called 'TreatAs' under the CLSID of the object you want to replace and set the default value to the CLSID of the object you want to create instead, this instructs the COM runtime to create your object instead of the original one. No need then to force your new, replacement object to have the same CLSID and ProgID of the old one.
For example, if your original object had ProgID "MyComLibrary.Object" and CLSID "{ABC}", and your new object has ProgID "MyDotNet.Object" and CLSID "{123}", then under HKLM/CLSID/{ABC} add a key called TreatAs with a default value of {123}. Then any request for "MyComLibrary.Object" or "MyDotNet.Object" will get a copy of the new object (assuming they implement the same interfaces).