Edit: The real solution to what I wanted to do can be found on this post here. I just wanted to expose some compiled functions to excel. This proved to be very easy using the Excel DNA nuget package. You just add a class library, add the nuget package, and copy paste the code found in the readme. Click F5 and it launches excel with the add-in already loaded. If you want your functions to be persisted you just need to manually add the add-in to the excel file through the "developer" ribbon section.
Original Post:
I was following the instructions from this microsoft post on how to create an automation add-in. Code compiles fine and I can access the functions from within Excel. However the functions do not work. I almost always get a #value or a #ref error when I try to assign to a cell the result of a function call. To be more specific:
The following function that is provided by Microsoft does not work. It shows me a #value error in the cell where I try to use it. I select using the mouse a random cell range as a parameter for the function.
Public Function NumberOfCells(ByVal range As Object) As Double
Dim r As Excel.Range = TryCast(range, Excel.Range)
Return CDbl(r.get_Cells.get_Count)
End Function
The following function that I created does not work. I get a #ref error. I called it by passing either directly integers ( Add1(1,2) ) or cells that contain numbers.
Public Function Add1(ByVal i1 As Integer, ByVal i2 As Integer) As Integer
return i1+i2
End Function
The following function that I created works(?!?):
Public Function Add1(ByVal i1 As Integer, ByVal i2 As Integer) As Integer
return 222
End Function
I am quite experienced in c# but not at all in vb.net, however for this add-in I need to use vb.net. I suspect that there is something simple that I am missing here but I have no idea what it is. It is also strange that the code provided by Microsoft doesn't work.
Edit: I also copy pasted the function presented here and I get the same #Value error inside excel. I did not follow the tutorial from this post from the beginning but I will during the day.
Edit 2: I figured out that the code from Microsoft doesn't work for some reason whenever you add a number in the function name. If I renamed Add1 on the sample code above to Addqweqew it would work!
MSDN Ref: http://blogs.msdn.com/b/andreww/archive/2008/01/23/managed-automation-add-ins.aspx
It has to do with a locale ID (LCID) issue. This is a known issue when
developing Excel solutions in a mixed culture environment. For more
information, see here: http://support.microsoft.com/kb/246501/.
VSTO solves this problem via its LCID Proxy. Although you can only use
this with VSTO solutions, its worth reading the documentation so you
can understand the problem:
http://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.excellocale1033proxy.aspx
and
http://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.excellocale1033attribute.aspx.
I got the same problem #Value results, I mucked around a bit and got this working (obviously it could be cleared up - but this code definitely works for me while keeping my PC set to my Australian locale ID. I'm not sure which part of the world you live but I am guessing not the United States as that's the locale where it works by default)
Public Function AddNumbers1(ByVal num1 As Double, _
ByVal num2 As Double) As Double
Dim oldCI As CultureInfo = Thread.CurrentThread.CurrentCulture
Dim english As System.Globalization.CultureInfo = System.Globalization.CultureInfo.GetCultureInfo("en-US")
System.Threading.Thread.CurrentThread.CurrentCulture = english
System.Threading.Thread.CurrentThread.CurrentUICulture = english
Dim valresult As Double = num1 + num2
Thread.CurrentThread.CurrentCulture = oldCI
Return valresult
End Function
Related question: https://social.msdn.microsoft.com/Forums/en-US/dafe71c5-d390-44bc-b4d3-b133444a02fe/excel-automation-addin-udf-returns-error-on-different-regional-settings?forum=vsto
Related
Compile Error:
Compile Error: Only user-defined types defined in public object
modules can be coerced to or from a variant or passed to a late-bound
functions.
I'm new to VBA and I was tasked with debugging some code for a custom screen in Dynamics SL. The first thing I did was to see if it compiled and I got the above message.
When I read the built-in help reference I found the following for the above error:
You attempted to use a public user defined type as a parameter or
return type for a public procedure of a class module, or as a field of
a public user defined type. Only public user defined types that are
defined in a public object module can be used in this manner.
I also went through these similar questions:
How to put user defined datatype into a Dictionary
Only user-defined type defined in public object modules can be coerced when trying to call an external VBA function
They have the same error but I don't see a collection object that the above two questions focused on.
If you may have any idea what may be causing this error please don't hesitate to suggest it.
Code:
Private Sub cpjt_entity_Chk(ChkStrg As String, retval As Integer)
Dim ldDate As Sdate
Dim xStrDailyPost As Sdate
ldDate.val = GetObjectValue("cpe_date")
'xStrDailyPost = DateToStr(ldDate)
'Call MsgBox("Daily Post Date: " & xStrDailyPost, vbOKOnly, "TEST")
serr1 = SetObjectValue("cld_id08", xStrDailyPost) <- Error highlights "xStrDailyPost"
End Sub
Definition for SetObjectValue:
Declare Function SetObjectValue Lib "swimapi.dll" Alias "VBA_SetObjectValue" (ByVal ctlname$, newval As Variant) As Integer
Thank you in advance!
You are probably working with code that was originally written with the Dynamics SL (actually it was Solomon IV at the time) Basic Script Language (BSL) macro language instead of VBA.
Regardless... the fix is, pass results of the "val" method of your xStrDailyPost instance of SDate. SO the code should look like:
serr1 = SetObjectValue("cld_id08", xStrDailyPost.val)
I've not actually tested this but I'm pretty sure this will address your issue.
If you want a little more background, "Sdate" is really just a very thin wrapper of an integer (actually I think it's a short, but I've never found I really needed to know for sure). the "Val" method returns the underlying integer in the SDate variable.
I'm conducting a VBA code where I use a function defined by the company. This function is contained in a Project which is Password protected, which I will not get access to, and I'm rather sure it should not be needed.
I can call the function through the worksheet "directly", i.e. in a cell I can write =TONNES(B2,B3,B4) and the cell output is the correct value. However in VBA when I use:
Private Sub CommandButton1_Click()
Dim param1 as String, param2 as String, param3 as String
param1 = Cells(2,2)
param2 = Cells(2,3)
param3 = Cells(2,4)
Cells(1,3) = TONNES(param1, param2, param3)
End sub
I get the error that the function TONNES is not a sub or function.
I have saved my Macro in a Module, and I don't have access to the actual code of the User defined function. Is there a way to be able to use this through VBA? As it can be used directly in the worksheet, but not through VBA, can that conclude that the function is disabled through VBA for some reason?
EDIT: The function is an add-in (more specifically I have a Company add-in which contains the data from production in a summarization page, which has created these functions in order to present these in the summarization page).
So I've finally found a solution. Basically going into Tools -> References in the VBA Environment (Alt + F11) and adding in the specific references caused a solution to this issue. Hopefully this may be of help for someone else with this problem.
I had a line of VBA code that basically looked like this:
MyControls.Add(Factory.CreateMyControl(param1, param2))
Where Factory.CreateMyControl is just a sneaky way to allow the new instance of my class module being returned to have a constructor.
It was working without any issues for several weeks. Suddenly, it begins throwing the error object doesn't support this property or method which is baffling me because everything looks like it always has.
After stepping into and through the code, I finally narrowed it down to the line above, and found the issue. The issue was the pair of parentheses surrounding the parameter(s) for the Add function. When I changed the code to the following:
MyControls.Add Factory.CreateMyControl(param1, param2)
It worked just as it always had before the unexpected break.
I now understand that this is the basic syntax in VBA for calling Sub's with parameters: to simply include all parameters in a comma-separated fashion without any parentheses (unless you're setting a Function's return value to another variable or using it's value for some other purpose).
My real question is, why did this suddenly just stop working?
Is it a common occurrence using VBA in Office 2007 for code that once worked to break without warning?
Or could this have been caused by some kind of patch that happened without my knowledge?
With parentheses around, the Sub's parameters per default were passed ByVal instead of ByRef. Without parentheses around, the default is ByRef
Example:
Dim r As Range
Sub test(v As Variant)
MsgBox TypeName(v)
End Sub
Sub main()
Set r = Range("A1")
test r 'ByRef; TypeName is Range
test (r) 'ByVal; TypeName is not Range but the type of the content of A1
End Sub
I'm using Excel 2010, and have defined the following 3 functions in spreadsheet's Module.
Option Explicit
Public Function AAA() As Double
AAA = 3
End Function
Public Function AAA2() As Double
AAA2 = 4
End Function
Public Function AAA3AAA() As Double
AAA3AAA = 5
End Function
When I reference the three functions in my spreadsheet by entering the following into 3 adjacent cells
=AAA()
=AAA2()
=AAA3AAA()
The second function generates a #REF error. The other functions work as expected. Anyone know why this is happening? The reason I'm asking is a few of my macros quit working when I upgraded from Office XP to Office 2010. After quite a bit of experimenting, it appears the function name itself is the culprit? The error did not occur in Excel from Office-XP.
Same thing happened to me. What I notice is that unlike the other two, "AAA2" could be the text of a cell address. I suspect that's the problem.
I am trying to create a custom vb.net Excel 2007 function (UDF) using VS 2010 and have gotten to this stage (borrowing heavily from Eric Carter's example at http://blogs.msdn.com/b/eric_carter/archive/2004/12/01/273127.aspx):
Namespace AutomationAddin
<Guid("1aeeb1b5-e099-4f7f-aeb0-3e9f19b64f62")>
<ClassInterface(ClassInterfaceType.AutoDual)>
<ComVisible(True)>
Public Class MyFunctions
Public MyFunctions()
Public Function MultiplyNTimes(ByVal number1 As Double, ByVal number2 As Double, ByVal timesToMultiply As Double) As Double
Dim result As Double = number1
For i As Integer = 0 To timesToMultiply - 1
result = result * number2
Next
Return result
End Function
<ComRegisterFunctionAttribute()>
Public Shared Sub RegisterFunction(ByVal type As Type)
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"))
Dim key As RegistryKey = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), True)
key.SetValue("", (System.Environment.SystemDirectory + "\mscoree.dll"), RegistryValueKind.String)
End Sub
<ComUnregisterFunctionAttribute()>
Public Shared Sub UnregisterFunction(ByVal type As Type)
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), False)
End Sub
Private Shared Function GetSubKeyName(ByVal type As Type, ByVal subKeyName As String) As String
Dim s As System.Text.StringBuilder = New System.Text.StringBuilder
s.Append("CLSID\{")
s.Append(type.GUID.ToString.ToUpper)
s.Append("}\")
s.Append(subKeyName)
Return s.ToString
End Function
End Class
End Namespace
However, when I build it using VS 2010 and try to load it in Excel 2007 using the Addin Manager>Automation I find it listed as AutomationAddin.AutomationAddin.MyFunctions and click OK only to get the error "AutomationAddin.AutomationAddin.MyFunctions is not a valid add-in." I have set the Build settings to Register for COM interop.
I've had a look online and tried following this article How to get COM Server for Excel written in VB.NET installed and registered in Automation Servers list? but to no avail. I checked my registry (after I built my project) and under CLSID/{myGuid}/InprocServer32/Default the data is set to C:\WINDOWS\system32\mscoree.dll and CLSID/{myGuid}/Programmable already exists.
I am not quite sure what I am doing wrong and would appreciate any guidance or suggestions on the topic.
Cheers,
Ben
You might want to check out this article (Build and Deploy a .NET COM Assembly) which might be helpful in your case.
I don't know if this is relevant to the question (especially after all this time) but I originally started with a COM add-in (created using Visual Studio 2010's Excel 2010 add-in project builder). I then added an automation add-in (for UDFs) by hand in the same project using the Eric Carter blog and other examples. The two worked fine independently. It was only after combining the two in the same namespace (for some obsessively tidy reason) that I started getting the "... is not a valid add-in" error. Spent a day tearing my hair out and then separated the namespaces again - problem went away.