Com Automation addin and Xll addin Appdomains

Add-in Express™ Support Service
That's what is more important than anything else

Com Automation addin and Xll addin Appdomains
 
Xavier N


Guest


Hello (Andrei),
I got a project with a Com addin, a Com automation addin (functions) and an Xll addin...
Some of my Excel functions (automations and xll) use internal sub functions with an extra parameter (bIsInComFunction) telling if i'm in the xll addin or in the Com Addin... (For returning for example the correct error constants wich is diffents in Xll/Com..)
As Com automation addin are loaded in the default AppDomain, it seems it can't access the Xll addin properties because this one is loaded in its own domains... Is it always true ? I mean, could the xll addin be loaded in the Default appDomain accidentally? And in this case will XllAddin.CurrentInstance be equals to nothing in a com automation function (i want to use this test to remove the extra parameter (bIsInComFunction))...

Thanks for your answer (Hope the question/expression is not to difficult to understand ;)

Regards
Xavier
Posted 10 Mar, 2020 03:23:10 Top
Andrei Smolin


Add-in Express team


Posts: 18821
Joined: 2006-05-11
Hello Xavier,

It is impossible for an Add-in Express XLL add-in to load in the default AppDomain. XllAddin.CurrentInstance being Nothing or null means the xll add-in isn't loaded.

It is possible to load an Automation add-in to the AppDomain where your COM add-in and XLL add-in are loaded. to achieve this you must perform a call to the Automation add-in before Excel invokes it. I don't think it would be possible to perform such a call in *all* scenarios.

If the Automation add-in is loaded in the default AppDomain, you cannot do direct calls to your COM and XLL add-ins. This is because every AppDomain corresponds to a separate assembly instance. To work around this, your Automation add-in can invoke the XLL add-in indirectly via ExcelApp.Evaluate(). To invoke the COM add-in (also indirectly) you use the following code path:

ExcelApp.COMAddins.Item(strMyComAddinProgId).Object.MyPublicPropertyOrMethod.

1. strMyComAddinProgId - see the ProgId attribute of your add-in module.
2. MyPublicPropertyOrMethod is called via late binding (see System.Type.InvokeMember in MSDN or search through our forums)


Andrei Smolin
Add-in Express Team Leader
Posted 10 Mar, 2020 05:20:22 Top
Xavier N


Guest


Thanks a lot for your answer Andrei (and for the App Domains informations) >>> I didn't knew it was possible to load the Automation add-in in the same AppDomain where your COM add-in and XLL add-in...

I wanted to know how to determine if shared part of code was called by the Xll or Com Automation.
In com automation code "XllAddin.CurrentInstance" return Nothing (even if the XllAddin is loaded in Excel). So i will use this test to know which addin is calling the code...
If you have any other idea of test, please tell me...

Thanks again Andrei,
Regards. Xavier
Posted 10 Mar, 2020 05:50:13 Top
Andrei Smolin


Add-in Express team


Posts: 18821
Joined: 2006-05-11
Hello Xavier,

Xavier N writes:
So i will use this test to know which addin is calling the code...


Both add-ins may be loaded at the same moment?

You can introduce two types of adapter methods in the shared part of your code so that the XLL add-in calls one sort of adapters and the Automation add-in calls the other.

Say, if you have MyMethod(), you can introduce MyAdapterMethodForXLL() and MyAdapterMethodForAutomation(); both calling MyMethod() internally.


Andrei Smolin
Add-in Express Team Leader
Posted 10 Mar, 2020 06:36:45 Top
Xavier N


Guest


Both add-ins may be loaded at the same moment?

Yes they are

You can introduce two types of adapter methods in the shared part of your code so that the XLL add-in calls one sort of adapters and the Automation add-in calls the other.


I guess MyAdapterMethodForXLL() is in the Xll Code Module and MyAdapterMethodForAutomation() is in the Automation Code Module in your example...
Thanks for the suggestion. But currently functions are only "defined" in the addins Code Module and then "implemented" in multiple Vb Code modules:

Ex:

'In the automation addin module
Function MY_FUNCTION_COM()
Return fnMY_FUNCTION()
End Function

'In the xll addin module of name XllAddinModule
Function MY_FUNCTION_XLL()
Return fnMY_FUNCTION()
End Function

'In a shared code Module (ie classic Vb Code Module)
Function fnMY_FUNCTION()
'Check if the code is called from Xll or Com (Need to know that to access excel object model (ex: excel caller range,..) or return xll or com error value)
Dim bIsInXllModule = (XllAddinModule.CurrentInstance() IsNot Nothing)
if bIsInXllModule then

else

End if
...
End Function

Is the Check test "Dim bIsInXllModule = (XllAddinModule.CurrentInstance() IsNot Nothing" always valid ?
I mean if the xlladdin is loaded "accidentally" in the Default AppDomain (as the Com automation addin), will XllAddinModule.CurrentInstance() exists if called in code called by com automation...

Regards. Xavier
Posted 10 Mar, 2020 08:44:11 Top
Andrei Smolin


Add-in Express team


Posts: 18821
Joined: 2006-05-11
Actually, I suggested moving MY_FUNCTION_XLL() and MY_FUNCTION_COM() to the shared code Module (ie classic Vb Code Module).

Xavier N writes:
I mean if the xlladdin is loaded "accidentally" in the Default AppDomain


Let's differentiate "XLL add-in assembly" and "XLL add-in".

It is impossible to load an Add-in Express XLL add-in assembly in the default AppDomain; it can only be loaded in a separate non-default AppDomain.

While a COM add-in requires implementing some COM interface, XLL is a non-COM thing. Creating an XLL requires exporting (in C/C++ style) functions; you have a single entity which is able to export these functions. This is the Add-in Express loader adxloader.dll/adxloader64.dll.

When applied to XLL, using the loader means 1) using a separate AppDomain and 2) being able to export the functions required by the XLL protocol/API/SDK/whatever. To get in the default AppDomain you must use no loader but no loader means no XLL. Whatever occurs, there will be no XLL module loaded in the default AppDomain.

ADXXLLModule.CurrentInstance returns Nothing (null in C#) if the XLL add-in isn't loaded in Excel. The XLL add-in may not be loaded even if the XLL add-in assembly is loaded (in a separate AppDomain).


Andrei Smolin
Add-in Express Team Leader
Posted 10 Mar, 2020 09:11:25 Top
Xavier N


Guest


Whatever occurs, there will be no XLL module loaded in the default AppDomai.

Thanks for the explaination...

ADXXLLModule.CurrentInstance returns Nothing (null in C#) if the XLL add-in isn't loaded in Excel. The XLL add-in may not be loaded even if the XLL add-in assembly is loaded (in a separate AppDomain).

I was mixing the assembly and the addins notions. I thought the xll addin was loaded because it was referenced in the addins dialog box. In reality as com automation is working in another app domain i need to use code to discover the xll addin is not loaded (from the automation code)...

Conclusion: the test is valid if the addins are loaded in two diffent appDomains.

If one day, i decid to load the com automation in the AppDomain used for the xll/com addin, i suppose the test will not be valid anymore. If you have any suggestion ?

And maybe a last question... In my xll addin code, i'm using this code to access Excel caller Range:

Dim xllAddin = AddinXllFunctions.CurrentInstance()
Dim adxCaller = TryCast(xllAddin.CallWorksheetFunction(ADXExcelWorksheetFunction.Caller), ADXExcelRef)
Dim sCallerAddress = adxCaller.ConvertToA1Style()
Dim xlCellCaller As Excel.Range = xllAddin.ExcelApp.Range(sCallerAddress)

It's working well, but i was wondering why CType(xllAddin.ExcelApp.Caller, Excel.Range) was not also returning the caller range (it fails)..

Thanks again Andrei for your previous deep explainations.
(and there's no hurry for these last questions..)

Regards. Xavier
Posted 10 Mar, 2020 09:49:05 Top
Andrei Smolin


Add-in Express team


Posts: 18821
Joined: 2006-05-11
Hello Xavier,

Xavier N writes:
the test is valid if the addins are loaded in two diffent appDomains.


The best test doesn't rely on AppDomains: use the ExcelApp.AddIns collection to check if an add-in is okay. You can also use the information we provide at https://www.add-in-express.com/creating-addins-blog/2011/10/03/invoke-excel-udf-programmatically/.

Xavier N writes:
In my xll addin code, i'm using this code to access Excel caller Range:


Actually, CType(_Module.ExcelApp.Caller, Excel.Range) generates this exception: Unable to cast object of type 'System.Double' to type 'Microsoft.Office.Interop.Excel.Range'. Casting CType(_Module.ExcelApp.Caller, System.Double) returns 1637023755. I suppose this is the #REF value that ExcelApp.Caller returns; see https://docs.microsoft.com/en-us/office/vba/api/excel.application.caller.

You shouldn't call into the Excel object model while in the context of the XLL call. That means, accessing ExcelApp is sort of prohibited: it might work but this depends on how Excel manages COM and XLL calls internally. Once they change something, this may fail. Note that this doesn't mean that XLL or COM may fail. What may fail is the way Excel object model calls are handled while an XLL function is executed.

To avoid this, your XLL function should return the range address, not a Range object. In case this function is called by you, you will be responsible for converting the range address to a Range object *after* this XLL function completes.

We demonstrate the idea of "after an XLL function completes" in sample projects at https://www.add-in-express.com/creating-addins-blog/2011/10/11/invoke-excel-addin-xll/.


Andrei Smolin
Add-in Express Team Leader
Posted 11 Mar, 2020 04:40:08 Top
Xavier N


Guest


Hello Andrei,
Thanks a lot for your answer and the links. I need to investigate a little bit more and test some functions..
(I may contact you later on a few questions..)
Regards. Xavier
Posted 11 Mar, 2020 07:56:17 Top
Andrei Smolin


Add-in Express team


Posts: 18821
Joined: 2006-05-11
You are welcome!


Andrei Smolin
Add-in Express Team Leader
Posted 11 Mar, 2020 12:09:31 Top