I can load up the control fine (pseudo code):
Set o = CreateObject("DevsoftCustom.CommControl")
Now, I need to find the file and directory for that ocx (so I can read the version stamp on the ocx, and read from a config file in that directory).
How is this done in C# and vb.net? (This project is in vb.net)
Now, I need to find the file and directory for that ocx
Assuming you are not using private COM registration, such information is in the registry.
HKCR\CLSID\<SOME-GUID>\LocalServer="<path>"
...or:
HKCR\<PROG-ID>\CLSID=<GUID> // use this GUID in the example above
Or if you don't want to use the registry you can make use of the native function CLSIDFromProgID(). Tell me more...
Here's an easy representation of Microsoft Outlook Date Control in OLE/COM Object Viewer.
You can use the OLE/COM Object Viewer to view a control's interfaces.
So in your case, look up the class ID in the registry based on the prog ID "DevsoftCustom.CommControl"
i.e.
Under HKCR, look for the key DevsoftCustom.CommControl
There will be a child key called CLSID, take note of the default value
Open HKCR\CLSID\ < your-key-from-step-2 >
The path will be in a subkey called LocalServer32
Using the Office example:
Once you know how COM works, its easy to implement the above in c#.
Isn't there a more direct way to ask the OS based on the object/control name?
Not that I'm aware of and as Damien mentioned, the point of COM (including OCX) is that you don't care where something is, you just want an instance.
The closest parallel is having a .NET assembly in the GAC where you want to create an instance of an object but don't want to have to worry about deploying the same assembly over and over on the same computer. Of course, the GAC serves far more purposes than that so that's where the comparison ends.
Related
I have written two addins , 1 for excel and 1 for word. However these addins have a lot of duplicates: Database handling, file handling,array handling which I would like to update 1 place instead of two.
We do have access to sharepoint, and could get access to visual studio. The thing is that people like to use file explorer and find the correct word or excel file, then open it then press a button inside the application which then should do things with the active document.
This is why we haven't written it as a .Net application yet, because that requires that people browse for the file inside the .NET application uless I am mistaken.
Is it possible to make an Addin which works both excel and word, or a dll? AnAnother important thing is that it should be easy to roll out a new version to the user, like stored on a network drive or similar.
Yes it is possible
The Hard Way
You can create a .Net DLL and call it from VBA. In visual studio a lot of people use Unmannaged Exports by Robert Giesecke to create DLLs that don't need to be registered (that way the DLL can be shipped with your document, and as long as it can be found you can use it).
Alternatively you might be able to do it manually as shown here by Hans Passant.
The Easy Way
Once the DLL is created you can declare it in a VBA module the same way you declare any other DLL for Late Binding and then call it from your code.
OR if you're happy to create the DLL and add it as a reference (possibly less portable) you can make it COM visible and register it for COM Interop in Visual Studio; this is probably the easiest way to go because you can then use Early Binding.
This is a walk through that might help: http://www.geeksengine.com/article/create-dll.html
But if you want to store the DLL on a network drive, well it might be that you really want to look at doing it the 'hard way', in which case look here: https://stackoverflow.com/a/5934745/3451115 and here: https://msdn.microsoft.com/en-us/library/bb687915.aspx
I need a list of the methods and properties exposed by a COM object. I am able to late bind the object and use some basic methods that I found in an example code snippet but I need to find out the full list of methods and properties on the object.
More info:
I am trying to pull data from a fairly old system and am unable to early bind any of the dlls.
I do have some snippets of example code from the company that creates these dlls (it was packaged with the software), however it does not have code for all of the advanced functionality I am seeing from their example application (which I do not have source code to).
I have already tried using reflection without much success.
Assuming that you don't need to programatically access the information, the easiest way is to the OLE-COM object viewer. The tool is part of the Windows SDK.
Once running, look in the Type Library node and locate the type library of the component that you are using. The Type Library viewer will show you all of the dispatch interfaces defined by the component.
If you can't add the DLL to VB6 in the References dialogue, then there is no Type Library resource embedded in the DLL. If you can load the DLL, you should be able to use F2 to bring up Object Browser, and see all of the properties and methods of the component.
It seems unlikely that you hadn't tried this. So there are three possibilities:
There is an external type library for the component.
You got an error when adding the DLL as a reference, which essentially said the VB IDE couldn't find a type library in the component.
You got an error when adding the DLL as a reference, saying something like "Could not load DLL".
Just in case of 1. - check if there is a TLB or OLB file for this component.
If you got the error in 2. - then you are out of luck. You will require access to documentation and/source code.
If you got the error in 3. - then there is probably a dependent library which has not been registered. Try to find the dependent TLB or DLL, and register it.
I am working on an application that imports an unmanaged dll into C#. It has a wrapper class that loads the methods so it can be called. The methods work fine in the program from the dll. I want to add saving the version of the dll that is being used. I found that I need to use FileVersionInfo.GetVersionInfo("my.dll") thanks to C# getting version of unmanaged dll. However, when running this function it exceptions saying it can't find "my.dll". The dll is in a folder off the root of the c:. This folder is in the PATH and according to http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx#search_order_for_desktop_applications it should find it.
Knowing that the my.dll file is loaded and working why can't I also call GetVersionInfo() inside the same wrapper class and find my.dll so I can get the same file's version number? Thanks for the help as I have been looking for a couple of days.
It requires the full path, it won't search for the DLL. That's too risky, the Windows search rules for a DLL are intricate and subject to configuration. If you need to do this before pinvoking any function then the best way is by pinvoking SearchPath(). Which uses the same algorithm as LoadLibrary uses if you set the first argument to null.
If you need to do this after pinvoking a function then the best way is by using the loaded DLL. Iterate Process.GetCurrentProcess().Modules to retrieve the ProcessModule.FileName.
From MSDN, the parameter for GetVersionInfo is:
The fully qualified path and name of the file to retrieve the version
information for.
So it's pretty clear. You need to pass the full path, as it seems this function relies on it. Otherwise it will most likely look for the file in the current directory (so your app's dir).
As a side note, keeping the native DLL in C:\ is bad practice.
You should store it in your application's folder. Then this function would work and your app would be more self contained. No files spread around the disk.
Of course, this is true unless you have a good reason for storing it in the root of your C drive.
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).
does somebody know how can I embedd an exe file into a dll ?
I have a tool which is an exe file that I call from c# code.
The thing is that I want to have 1 dll containing this tool (exe file) and the dll containg my c# code.
Is it possible to embedd this exe file within the resources?
Thx in advance
Sure it is. You can add any file as RC_DATA in application as resource. But I believe you will need to extract it to disk first before calling it!
Which IDE/Language you are using?
[EDIT]
Sorry! you did mention that you are using C#.
Add a resource file to you application (right click application in IDE and select "Add new item".
Use the toolbar in resource editor to add an existing file.
Then extract the exe whenever required by calling code something like:
System.IO.File.WriteAllBytes (#"C:\MyEXE\", Resource1.MyEXE);
It's worth baring in mind that your uses may not be too happy about you doing this. Embedding an executable that they've got no control over into a DLL that you'll extract and run will probably make people worry about the running a Trojan on their machine.
It's better to leave the .EXE in the filesystem and be transparent about what your application is doing.
You can load an Assembly from a byte[]. This can be obtained via the ManifestResourceStream of an embedded resource.
An alternative may be to not embed the .exe itself, but rather include its functionality in the dll, and use rundll32[1] to execute it.
On a side note, remember that when you pull a file from your resources to disk and then execute code on it, you may trigger Windows Data Execution Prevention - basically, Windows tries to automatically detect if something is supposed to be code or data, and if it looks like data (which a resource would), then it will prevent that data from being executed as code.
This becomes a particularly sticky issue if your .NET assembly is going to be used over a network instead of from a local drive - there are all sorts of .NET security configurations that might prevent this from working correctly.
Another option, and not knowing the details of your project, take this with a grain of salt: add a .exe.readme file to your install that describes to any curious users or IT people why there is an executable they weren't expecting in the installation directory :)