How to load COM object in smart device project? - c#

I want to create a .NET CF application for Windows Mobile 5. In this application, I want to load a COM object based on the ProgID (or CLSID).
How do I load this COM object in such a way that I can access its methods as if it were just another .NET object?
In addition: how can I configure the projects / solutions in Visual Studio in such a way, that when I debug the application, I am sure that the COM object that is loaded is the one that is installed on the device, not one that may be accessible through the debugger?
I have tried adding the .ocx file as a Reference, but I get an error, and I am not sure about 'question 2'. I have also tried loading the COM object using
Type type = Type.GetTypeFromProgID("my.prog.id")
MyObject myObject = (MyObject)Activator.CreateInstance(type)
...but this results in an InvalidCastException on the second line.
EDIT: For the record: I am working on a 64-bit Windows 7 machine, not sure if this complicates things...

You need a runtime callable wrapper (RCW). See this MSDN article for the basics. For more complex things like ActiveX controls, see this article.

Related

How to configure DCOM access, launch and set run as permission using c#

I'm trying to configure access, launch permissions along with set run as to one of our custom DCOM application.
I have already gone through these links
dcomcnfg functionality programmatically
and http://www.myitforum.com/articles/11/view.asp?id=9323 (downloaded c++ DCOMPerm library)
I tried the code from the first link above as is written by "longofest" but the following line of code
var value = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", "DefaultAccessPermission", null);
always gives me back a null value,however when I looked into the registry entries on my machine the "DefaultAccessPermission" entry for Ole registry key does have a binary value there then why I always receive a null back, no idea.
Secondly I tried the c++ library downloaded from the second link above and tried to do a COM call to one of the methods with DLLImport attribution (for automating the launch permissions for the DCOM object) but some marshalling issue is not letting me pass in the C# types corresponding to C++ types and spitting out an exception that says PInvoke cannot return variants.
I couldn't find anything concrete after googling for several hours, any help on this account will be more than appreciated.
Never worked with C++, got very poor knowledge of this language.
Update:The null value issue is solved but I don't know how to set access permissions and set run as. I have seen in c++ code that for setting access permission the code needs a domain and username but what is the c# equivalent of that, no idea....
I used the tblimp.exe tool from Microsoft and created an interop .dll assembly out of DComPerm.dll (c++ assembly) to reference in C# code and by means of Run Time Callable Wrapper I'm calling various methods on COM objects to write my C# program, so no need of DLLImport or MarshalAs attribution since RCW will take care of all the marshalling and unmarshalling issues.

How can I inform my managed DLL about my managed application types

I have a situation where I have a C# Managed DLL that is handling incoming real time data. The DLL filters and saves up to 200 of the most recent data points in a FIFO. I also have a C# application that on occasion needs to get some of the data from the DLL. I can easily setup methods in the DLL to return single values of the built in data types.
What I need is a way to pass a reference to my user defined type (EX: List ) to the DLL and have it fill it in. I cannot seem to find any way to tell the DLL about my types and the compiler complains that I do not know what I am doing. This is true. I have tried everything I can find on the internet.
Further my application already has a reference to the DLL so that it can start it up and respond to events, therefor I cannot add a reference to my application within the DLL without creating a circular reference.
So how can I inform my managed DLL about my managed application types? The end goal is to be able to pass an ObservableCollection and have the DLL fill in MyObject with data from its local cache of data points.
When searching the internet it seems that the managed to unmanaged scenario outweighs the managed to managed scenario by 98 plus percent.
Any ideas would be greatly appreciated.
To compile my comment as an answer:
You should have (naming is just ilustrative):
DataContract.dll with the definition of your types.
BusinessLogic.dll with the logic.
And Application.exe with your presentation logic.
DataContract.dll can then be referenced by both - BusinessLogic.dll and Application.exe.

How to Determine If .NET EXE was started by another process

Forgive me if my title is not accurate, I did my best to describe my issue.
Here's the details, I can modify accordingly:
I've been upgrading a VB6 application to a .NET (VB.NET and C#) application to be used in Excel. Using my application's ProgID, I can query it in Excel VBA using:
CreateObject("MyExe.MyApp")
Since I believe my app is a single-instance application, when I call CreateObject and it is already running, it just returns me that running instance. All is fine there.
My issue is, when it is NOT running, it will launch a new one right? That's my problem in my .NET application. You see, in VB6, when you use CreateObject, it will change my App.StartMode to VbSModeAutomation = 1
My VB6 application handles this accordingly. However, there doesn't seem to be an equivalent way of doing this for a .NET application. In fact, it says right on this MSDN page:
StartMode - No equivalent. In Visual Basic 6.0, this property was used
to start an application as an ActiveX component. ActiveX component
creation is not supported in Visual Studio .NET.
So ultimately, my question is: how do I determine when my .NET application is started from this call to CreateObject versus starting it manually (or via standealone, like a shortcut or etc.)?
.NET does not as easily let you create an out-of-process COM server, like VB6 does with that VbSModeAutomation property. The supported scenario is COM+ hosting, your [ComVisible] class needs to derive from the ServicedComponent class.
There's a dedicated KB article that summarizes the required steps pretty well. The in-depth MSDN articles start here.
Checking for a parent process is quite tricky but you can find the information in the Win32_Process WMI class - ParentProcessID property. If this is not set then your application was not started by another application.
You might be able to use the CommandLine to determine how it starts. It does not appear that CreateObject allows you to pass command args, but as you noted, -Embedding seems to automatically get sent. Alternatively, maybe you could modify the shortcut method to pass some fake argument and its absence could indicate a CreateObject start method.
NET supports several ways to get the commandline:
Environment.CommandLine and Environment.CommandLineArgs()
I think there is another in the VB Namespace but it returns a collection of objects rather than String or String array of parsed args (space delimited).
You can also modify your Sub Main:
Public Sub Main(args() As String)
NET will fill in the array with the parsed commandline

COM Object Registration--Multiple allowed?

I have two COM objects with different GUID values, but the same name. One is a newer version of the other. What happens when I register both using Name.exe /regserver? I've looked in the registry, and they both show up with the same ProgID, but their respective GUID values are different. They point to their separate locations on the hard drive. Is this a problem?
I'm trying to get the old version of a project to work alongside the new version of a project (but not running at the same time), and I think these two things are fighting.
The COM objects were created in VB6. The code that uses them is C#. They are added to their individual C# projects as references. When one is registered, I can't compile the other (nor run successfully).
What other information would be helpful while investigating this issue?
Converting my comment into an answer:
You have created a new version of a component which is not backward compatible with the old version.
You really should change the ProgID to indicate that this is effectively a new component. Client apps will have to explicitly target either the new component or the old one. People often just append a version number (e.g. 2) to the ProgId.
You are violating hard COM rules. Either your replacement must be an exact match with the component you replace. Or you must generate a new version that:
Uses a different [Guid] for the coclass, you did that correctly.
Uses a different ProgId, you didn't do that. Boilerplate is to include a version number in the ProgId itself. So a Foo.Bar becomes Foo.Bar.2
Uses different [Guids] for the interfaces implemented by the class. This is easy to overlook since they are hidden so well in a VB6 component. Crucial however whenever the class is used from another apartment. COM needs to find the type library for the component so it knows how to marshal the interface method call. Be sure to declare your interfaces explicitly in your C# code.
The best way to double-check all this is by running OleView.exe, File + View Typelib command. That decompiles the type library content back to IDL, you will see the guids and interfaces. If you want to create an exact substitute for the old component then everything must match exactly. Exact same guids, exact same interfaces with the exact same order of methods and exact same arguments.
I haven't ever accessed VB6 ActiveX exes from .NET (just dlls), so this is a shot in the dark (and is weak enough to be just a comment except it is too long).
Perhaps you can create / export a .tlb each for the two VB6 components to compile your C# against. You shouldn't need the exes to compile.
Next manually add the registry entries as if they had separate Programmatic IDs (say MyComponent.ServerClass.1 and MyComponent.ServerClass.2) and then load them by name in your C#.

HRESULT:0x80040154 COM object with CLSID {} is either not valid or not registered

I am using COM Object in my C# .NET 1.1 application. When the COM object is not registered on client machine, I get the exception:
"COM object with CLSID {} is either
not valid or not registered."
(HRESULT:0x80040154)
I know how to register the COM object using regsvr32. Our requirement is to identify the COM object which is not registered. We don't want to hardcode the name of the COM Object, rather identify it dynamically using the COM Exception/HResult. Any ideas?
Given the situation mentioned in the comment to Benjamin Podszun's answer, your approach could be:
Look up the CLSID in the registry (HKEY_CLASSES_ROOT\CLSID\{...})
If not found, just throw so that the generic error message is displayed
Look at the appropriate subkey depending on the type of object (e.g. InProcServer32 for an in-proc native COM DLL/OCX). The default value will be the path to the DLL/OCX.
Check for the existence of this path and fabricate a suitable message with the name of the file.
This enables you to display a different message if the OCX/DLL has been moved, but of course won't help if it is not registered.
You also might want to spend some time trying to understand why (or even five whys!) the components are being moved / unregistered on some client machines, which may suggest a way to prevent it . For example, one possible scenario is that the user installs version 1, then installs version 2, then uninstalls version 1. Depending on how your installer is implemented, uninstalling version 1 may deregister or remove the components needed for version 2.
Another approach might be to see how the installer behaves as a normal user vs an administrator.
Identifying the exact sequence of events on failing client machines may be a bit of a challenge, but it's worth trying.
The only way to solve the problem you describe is to have a global list of CLSIDs for all objects you want to check.
If you only care about a few libraries, you can install them, check their GUIDs, and build this database yourself.
If you want to identify any possible library worldwide that might ever exist, I would give up now and have some coffee.
If I understand you correctly you get the message "I don't know how to find the COM object for this GUID" and want to do it better..?
In other words: Usually you'd register the COM object and it is referenced by its class id or ProgId. For now windows doesn't know about your target object.
I'm not sure how to do that. If your COM objects are .Net assemblies you might be able to use Reflection to iterate over a list of files in your program directory and lookup the relevant attribute, comparing it with the error message.
If they are native libraries there are probably P/Invoke ways to do the same, but I wouldn't know how and Google doesn't help so far.
I would love to understand the requirement though: Since you're distributing that app and know the dependencies, why do you want to add this extra layer of complexity?

Categories