none
Accessing ActiveX EXE via C # Forms Application RRS feed

  • Question

  • Hello,

    I've been trying to get a handle on how to accomplish accessing an ActiveX EXE's methods from a C# Application but still a little confused.

    I scoured the internet and saw posts regarding using GetActiveObject but then I saw mention of using the GAC so this raised some questions whether my implementation is correct or not.

    Here is what I've done this far ..

    1. Created a Net DLL by calling tlbmip
    2. Added the newly created .dll as a reference in my C# Forms project
    3. Then I use the reflection services to call the exposed methods .. Example ..

                Process p = Process.Start("test.exe");
                 p.WaitForInputIdle();
                Assembly assembly = Assembly.LoadFile("C:\\Test\\bin\\Debug\\test.dll");
                Type type = assembly.GetType("test.DocumentClass");
                var methodInfo = type.GetMethod("RetrieveStatus");
                if (methodInfo == null)
                {
                    // never throw generic Exception - replace this with some other exception type
                    throw new Exception("No such method exists.");
                }

                dynamic instance = Activator.CreateInstance(type);
                var response = instance.RetrieveStatus();
                MessageBox.Show(string.Format("Value returned from RetrieveStatus {0}", response), "ReturnVal", MessageBoxButtons.OK);

    This returns a valid value but not sure if it's the correct way to be doing this?

    Do I need to register the ActiveX EXE?  I see posts regarding using Regasm.

    Is my newly created dll in fact communicating with the ActiveX EXE?

    Do I need my ActiveX EXE invoked or can I exclusively just use the dll now?

    Thanks!

    Saturday, March 21, 2020 2:41 AM

Answers

  • normally you would add the assembly generated by tlbimp as reference to your project,
    then you don't need to use dynamic.
    Registering a COM out of process server (I guess thats what you mean, I never heard of the term "ActiveX exe") depends on the implementation. When done in C++ with the ATL libraray the default was calling with a command line parameter, but normally this is done by the setup.

    The COM infrastructure should create the exe process autoatically when you do the first call,
    so your call to Process.Start is not needed (unless there is something wrong with the implementation of the exe COM server)
    • Edited by EckiS Saturday, March 21, 2020 10:40 AM
    • Marked as answer by Amernauth Saturday, March 21, 2020 8:17 PM
    Saturday, March 21, 2020 10:39 AM
  • Do I need to register the ActiveX EXE?  I see posts regarding using Regasm.

    If you are already able to use tlbimp.exe to create an interop dll from the out-of-process COM server's type library then the server has already been registered.  So successfully using tlbimp.exe would indicate that the COM server was created using unmanaged code (probably C++).  There is no reason to use Regasm.exe in this situation.  Just to add a little bit more information, the tlbimp.exe utility will complain if you try to use it to import a type library that was created by Regasm.exe. 

    Is my newly created dll in fact communicating with the ActiveX EXE?

    It would seem so.

    This returns a valid value but not sure if it's the correct way to be doing this?

    Actually, if the out-of-process COM server is registered you should be able to just add a reference to the COM server's type library to your project.  This will automatically create an interop dll for you, and separate usage of tlbimp.exe would not be necessary.  After the reference has been added to your project you should be able to instantiate a COM object hosted in the out-of-process-server (EXE) in exactly the same way that you would instantiate a COM object hosted in an in-process server (DLL).

    For example, where TestObject and ITestObject are in the interop dlls namespace

    using SimpleServerLIb; // namespace from COM type library reference

    ITestObject iTest = new TestObject(); string str = iTest.HelloWorld();

    As mentioned by EckiS the COM runtime will automatically start the out-of-process COM server (EXE) and you should be able to see the executable appear in the task manager.  When your Windows Form application is finished using the COM object the COM server process will terminate and disappear from task manager.

    Do I need my ActiveX EXE invoked or can I exclusively just use the dll now?

    Both the out-or-process COM server (EXE) and the interop dll are required.  Don't forget that the actual COM object that you are using is hosted in the EXE.  The interop dll is just an intermediary to enable your Windows Form application to communicate with the COM object.


    • Marked as answer by Amernauth Saturday, March 21, 2020 8:17 PM
    Saturday, March 21, 2020 12:17 PM
  • Thanks for all of the replies!

    I created a couple trial and experiment C# projects and the reason for the question was because I was getting conflicting results.

    Using tlbimp.exe and creating a NET DLL which I then added as a reference in my project seemed to work (value I was getting back when I called the out of process method seemed legitimate).  However, when I added the .tlb reference directly in my project and an interop dll was created I was getting different results.

    The ActiveX EXE unfortunately doesn't have a method I can call which reports back the version number so until I connect the hardware (which communicates with the EXE) I'll have to assume I'm on the right path.

    • Marked as answer by Amernauth Saturday, March 21, 2020 8:17 PM
    Saturday, March 21, 2020 1:06 PM
  • Well, in my simple test with a C++ out-of-process COM server there was no difference between results when 1) adding a reference from the registry, 2) adding a reference from the server's standalone type library file (.tlb) or 3) adding a reference from an interop dll created by tlbimp.exe.

    So what exactly do you mean by "conflicting results" or "different results" depending on how the reference was added to your C# project?

    • Marked as answer by Amernauth Saturday, March 21, 2020 8:16 PM
    Saturday, March 21, 2020 4:32 PM
  • Hi,

    Yes,  when I used tlbimp from the command line to create the NET DLL (ex .. tlbimp test.tlb /out:test.dll) and then added that .dll as a reference inside my C# project, I was able to call the retrieve method ..

                dynamic instance = Activator.CreateInstance(type);
                var response = instance.RetrieveStatus();

    The value returned (response = 3) seemed to make sense.

    When I added the .tlb as a reference inside my C# project (not using tlbimp from the command line) and referenced it this way .. (full code for the below snippet was listed earlier in the chain.)    

               Test app = new Test();
                int v = app.RetrieveStatus();  

    The value returned was 0.  This isn't what I was expecting but it may be correct.  Both implementations invoked the out of process EXE without calling the Process.Start function like you and EckiS mentioned (verified this using the task manager) so I'm trying to understand why the different return values.

    In both cases the variable holding the value, response and v were null before being set to the return value of the method.

    Thanks for all of the help thus far!

    • Marked as answer by Amernauth Saturday, March 21, 2020 8:16 PM
    Saturday, March 21, 2020 5:48 PM
  •           Test app = new Test();

                int v = app.RetrieveStatus(); 

    Ordinarily I would expect you to assign the results of calling new Test() to an interface (e.g., ITest) not to a class variable.
    • Marked as answer by Amernauth Saturday, March 21, 2020 8:16 PM
    Saturday, March 21, 2020 5:53 PM
  • That was it!  

    I was facing an issue when trying to build.  The compiler was complaining regarding interop embedding which forced me to use the class instead of the interface (against my better judgement).  Once I set the Embed Interop property to False I was able to set the interface correctly in the code.  Now the return values match!

    Thanks for all of the help!

    • Marked as answer by Amernauth Saturday, March 21, 2020 8:16 PM
    Saturday, March 21, 2020 7:09 PM
  • If your question has been resolved kindly mark the responses that answered the question to close the thread.
    • Marked as answer by Amernauth Saturday, March 21, 2020 8:17 PM
    Saturday, March 21, 2020 7:59 PM

All replies

  • normally you would add the assembly generated by tlbimp as reference to your project,
    then you don't need to use dynamic.
    Registering a COM out of process server (I guess thats what you mean, I never heard of the term "ActiveX exe") depends on the implementation. When done in C++ with the ATL libraray the default was calling with a command line parameter, but normally this is done by the setup.

    The COM infrastructure should create the exe process autoatically when you do the first call,
    so your call to Process.Start is not needed (unless there is something wrong with the implementation of the exe COM server)
    • Edited by EckiS Saturday, March 21, 2020 10:40 AM
    • Marked as answer by Amernauth Saturday, March 21, 2020 8:17 PM
    Saturday, March 21, 2020 10:39 AM
  • Do I need to register the ActiveX EXE?  I see posts regarding using Regasm.

    If you are already able to use tlbimp.exe to create an interop dll from the out-of-process COM server's type library then the server has already been registered.  So successfully using tlbimp.exe would indicate that the COM server was created using unmanaged code (probably C++).  There is no reason to use Regasm.exe in this situation.  Just to add a little bit more information, the tlbimp.exe utility will complain if you try to use it to import a type library that was created by Regasm.exe. 

    Is my newly created dll in fact communicating with the ActiveX EXE?

    It would seem so.

    This returns a valid value but not sure if it's the correct way to be doing this?

    Actually, if the out-of-process COM server is registered you should be able to just add a reference to the COM server's type library to your project.  This will automatically create an interop dll for you, and separate usage of tlbimp.exe would not be necessary.  After the reference has been added to your project you should be able to instantiate a COM object hosted in the out-of-process-server (EXE) in exactly the same way that you would instantiate a COM object hosted in an in-process server (DLL).

    For example, where TestObject and ITestObject are in the interop dlls namespace

    using SimpleServerLIb; // namespace from COM type library reference

    ITestObject iTest = new TestObject(); string str = iTest.HelloWorld();

    As mentioned by EckiS the COM runtime will automatically start the out-of-process COM server (EXE) and you should be able to see the executable appear in the task manager.  When your Windows Form application is finished using the COM object the COM server process will terminate and disappear from task manager.

    Do I need my ActiveX EXE invoked or can I exclusively just use the dll now?

    Both the out-or-process COM server (EXE) and the interop dll are required.  Don't forget that the actual COM object that you are using is hosted in the EXE.  The interop dll is just an intermediary to enable your Windows Form application to communicate with the COM object.


    • Marked as answer by Amernauth Saturday, March 21, 2020 8:17 PM
    Saturday, March 21, 2020 12:17 PM
  • Thanks for all of the replies!

    I created a couple trial and experiment C# projects and the reason for the question was because I was getting conflicting results.

    Using tlbimp.exe and creating a NET DLL which I then added as a reference in my project seemed to work (value I was getting back when I called the out of process method seemed legitimate).  However, when I added the .tlb reference directly in my project and an interop dll was created I was getting different results.

    The ActiveX EXE unfortunately doesn't have a method I can call which reports back the version number so until I connect the hardware (which communicates with the EXE) I'll have to assume I'm on the right path.

    • Marked as answer by Amernauth Saturday, March 21, 2020 8:17 PM
    Saturday, March 21, 2020 1:06 PM
  • Well, in my simple test with a C++ out-of-process COM server there was no difference between results when 1) adding a reference from the registry, 2) adding a reference from the server's standalone type library file (.tlb) or 3) adding a reference from an interop dll created by tlbimp.exe.

    So what exactly do you mean by "conflicting results" or "different results" depending on how the reference was added to your C# project?

    • Marked as answer by Amernauth Saturday, March 21, 2020 8:16 PM
    Saturday, March 21, 2020 4:32 PM
  • Hi,

    Yes,  when I used tlbimp from the command line to create the NET DLL (ex .. tlbimp test.tlb /out:test.dll) and then added that .dll as a reference inside my C# project, I was able to call the retrieve method ..

                dynamic instance = Activator.CreateInstance(type);
                var response = instance.RetrieveStatus();

    The value returned (response = 3) seemed to make sense.

    When I added the .tlb as a reference inside my C# project (not using tlbimp from the command line) and referenced it this way .. (full code for the below snippet was listed earlier in the chain.)    

               Test app = new Test();
                int v = app.RetrieveStatus();  

    The value returned was 0.  This isn't what I was expecting but it may be correct.  Both implementations invoked the out of process EXE without calling the Process.Start function like you and EckiS mentioned (verified this using the task manager) so I'm trying to understand why the different return values.

    In both cases the variable holding the value, response and v were null before being set to the return value of the method.

    Thanks for all of the help thus far!

    • Marked as answer by Amernauth Saturday, March 21, 2020 8:16 PM
    Saturday, March 21, 2020 5:48 PM
  •           Test app = new Test();

                int v = app.RetrieveStatus(); 

    Ordinarily I would expect you to assign the results of calling new Test() to an interface (e.g., ITest) not to a class variable.
    • Marked as answer by Amernauth Saturday, March 21, 2020 8:16 PM
    Saturday, March 21, 2020 5:53 PM
  • That was it!  

    I was facing an issue when trying to build.  The compiler was complaining regarding interop embedding which forced me to use the class instead of the interface (against my better judgement).  Once I set the Embed Interop property to False I was able to set the interface correctly in the code.  Now the return values match!

    Thanks for all of the help!

    • Marked as answer by Amernauth Saturday, March 21, 2020 8:16 PM
    Saturday, March 21, 2020 7:09 PM
  • If your question has been resolved kindly mark the responses that answered the question to close the thread.
    • Marked as answer by Amernauth Saturday, March 21, 2020 8:17 PM
    Saturday, March 21, 2020 7:59 PM