User Defined Functions in Automation Addin behave differently Excel 2007 - excel-2007

I have created an automation addin in C# .NET and have a shim dll for it. The
shim dll has all the User Defined methods in it that calls the appropriate
methods in the .NET assembly.
The problem that I am facing is related to Excel 2007.
In Excel 2003,
1. Add a new shape to a worksheet
2. Insert >> Function >> SUM. The Function arguments dialog comes up
3. click on the newly inserted shape instead of a cell
Note: Nothing happens and no cell value is entered automatically in the
argument box
Now in Excel 2007,
1. Insert a new shape
2. Formulas Ribbon Tab >> Insert Function >> SUM. Function Arguments dialog
comes up
3. Click on the newly inserted shape
Note that now an error dialog is displayed saying "The formula you typed
contains an error"
This dialog comes up for a predefined function (SUM). If I select my
function from the list in-place of SUM, the error dialog is not displayed and
the Function Argument dialog just vanishes. The cell then shows an error
smarttag.
Is there something that needs to be put into the SHIM dll for each function?
Like an attribute or something that will display this error dialog. OR maybe
some special value that is returned by the method to tell that the argument
has generated an error.
The function defined in the COM shim are like:
STDMETHOD(GetArea)(MyExcelAddIn::Range *r, double *pRetVal)
{
return m_pMyUDF->GetArea(r, pRetVal);
}

I contacted Microsoft and they confirmed that this is a bug in the Excel product. I will post the bug link when I get it from them.

Related

Can't change value of empty PDF form field from VBA

I'm trying to automate populating a PDF form from MS Access VBA. The form itself is maintained online and so my process is:
Download the form
Open it in Adobe
Auto-populate fields
Save / send it on to others
All of this I'm doing from Access VBA. I've encountered an issue on step 3, however.
What I noticed was, if I try to populate the field from VBA, it works fine if the field already has a value. However, on a new / blank form, it generates an error.
Specifically, I call it using the document Javascript object (jso) thusly:
jso.xfa.resolveNode("form." & jso.getNthFieldName(0)).rawValue = 'test'
If the form field is not populated, VBA errors, saying the object doesn't have the rawValue property.
I'm guessing some sort of model initialization is forestalled until the form is populated at least once. The field reference exists in the jso.xfa model, but the property itself is otherwise inaccessible.
Is there a way around this other than pre-populating a "dummy" form? I'd rather not have to maintain / update it as the original gets changed online.

How to reference tables/queries/reports in access using an alias name?

In my Access database, I have tables with the naming convention of "t_customers" or "t_orders". I have a combo box which lets me pick from these options. For a better look, I want to have the options in the combo box without the "t_", so one of the options is just "customers". Then in VBA, I can access the combo box's value of "customers" and then pass that as a parameter to my function which will export the contents of the associated table "t_customers" to an excel file.
Is this possible to do? I can think of using a select case statement and for each combo box value I manually assign the related table value, but there has to be a better way. Is there some sort of short cut that does this in Access using a relationship or similar feature without coding? Or is there a simpler way to code this?
EDIT:
I am also trying to get the value of the current item selected in my combo box named "cbTable". I have no macros attached to the combo box. I have a button that when pressed it runs a macro which calls my VBA function. In the function I have this code:
Dim cbValue As String
cbValue = cbTable.Value
MsgBox (cbValue)
I get this error:
Runtime Error '424'
Object Required
The error is on the
cbValue = cbTable.Value
line. What is wrong with this code and how do I get the current value of the combo box?
Thanks in advance.
You can set your RowSource for your combobox to
SELECT MSysObjects.Name, Replace(MSysObjects.Name,"t_","") AS Expr1
FROM MSysObjects
WHERE (((MSysObjects.Type)=1) AND ((MSysObjects.Flags)=0));
Then set the Column Count to 2, the Column Widths to 0;2 (the second number just needs to be any positive number) an the Bound Column to 1.
Now when you go to call your function the value of the combobox will be the real name of the table, t-customers, but what you saw on your form was customers.
As for accessing that combobox a few things need to be in place.
Let's say you have a form, Form1, and your combobox, cbTable, is on that form.
So when your form runs it looks like this
Now let's say you have an OnChange even for that combobox
Notice that when you type cbTable it appears in the intellisense (ctrl+space). This tells you that your object is accessible at this scope.
Now if you were in another module where that variable is out of scope you would get this error when you try to compile.
Because Module1 has no idea what cbTable is. However, you can reference anything so long as it's fully qualified. So if we run this test with your form open, and "orders" selected all 3 of these lines are equivalent
Forms("Form1").cbTable
Form_Form1!cbTable
Forms("Form1").Controls("cbTable")
Notice at the top of all my modules it says Option Explicit. This forces your code to basically be checked for syntax/scope validity before you run it. Tools > Options

What is the most idiomatic way to load and save values from an MFC CPropertySheet?

I have a class derived from CPropertySheet and I am having trouble finding the "correct" way to load values on startup and save values when the user presses OK. I'm surprised that I can't find any useful example on the web but there it is.
Ultimately, I need to read values from an external data source and write them back but for now, I have a void LoadValues(void) method on my property sheet that just uses some literals to initialize the controls on the property pages. This works when I call LoadValues() from OnInitDialog(). But if I do:
CMyPropertySheet* pSheet = new CMyPropertySheet("My Title");
pSheet->LoadValues();
if (pSheet->DoModal() == IDOK) {
pSheet->SaveValues();
delete pSheet;
}
(as Microsoft suggests) the values are not there when the property page is displayed; the controls are empty or contain default values. All the MFC control value setting routines seem to return void so there's nothing to test for success. I did read back a value in LoadValues() after I set it and I get the correct value.
Also, SaveValues() sees gibberish. Perhaps the property sheet is torn down before I get out of DoModal() to the values aren't there any more?
I've been told that values should get loaded in OnInitDialog() and I guess I can get my external data source to the object in the constructor but that leaves me having no idea where to save values. There doesn't seem to be a CPropertySheet::OnOK() method. What am I missing?
Although you are working with a property sheet the same issues apply to all modal dialogs. Before you call DoModal the controls do not exist. So if your LoadValues call is attempting to access the controls it will not work. (This would normally produce an assertion in a debug build.) What you need is a two-step operation: (1) LoadValues can access data members of the sheet, so pass the values to the sheet's data members that you create for that purpose. (2) In OnInitDialog of the sheet you can initialize the controls from the data members.
SaveValues needs a similar two-step because the controls no longer exist after DoModal returns. (1) In the sheet's OnOK or equivalent move the data from controls to data members. (2) After DoModal returns you can access the data members to do the SaveValues.

Microsoft Access 2013 Form Objects

I have a database that was create in Access 2010. We recently updated our systems to Access 2013. In Access 2010 I have no errors accessing a form object with
Form_frmName.txtFieldName.Value
However, when using Access 2013 I get a runtime 2424 error stating that "The expression you entered has a field, control, or property name that Microsoft Access can't find. I am accessing from a module.
The module sets these fields visible using
With Form_frmName
.txtFieldName.Visible = True
End With
before attempting to access them.
Has there been any changes in the way form objects are accessed between 2010 and 2013? Is this an issue others have faced?
In Response to #WayneGDunn's questions below
QUOTE:
I need to know exactly what and how you are using this.
1. You have a bound textbox named 'txtFieldName' on a form. As #brad asked, is there a subform, and if so, is this field on the subform?
2. You said the code is in a module, but is the code in the form where the field is defined?
3. Please explain where/what form 'frmQAtab' is (you said your form name was 'frmName', so what is the other, how related?)
4. Is the code in an event? Can you share the entire subroutine?
5. Have you tried creating a dummy query and using the builder to reference the field?
RESPONSE:
1. I have a form (frmMain) with multiple tabbed pages. frmName is one of those tabs, containing the bound field txtFieldName.
2. The module is run from the form the field is in.
3. My apologies frmQAtab is frmName, I just neglected to make that generic in my copy-paste.
4. The event is a button click. The button click runs a sub from a module. That sub makes visible the fields, runs a query based on user input (two date fields), populates the bound fields with the returned record set, then attempts to access them for processing (another query is run to process a complete other set of fields). To post the entire subroutine would be a bit more than I would ask you to chew on. This is legacy code I'm trying to fix, and it's rather large.
5. I have not tried a dummy query. Access is not my field (I'm mainly a C#, scripting, guy.) Is there some suggestions in this area you could give?
One of the following references to your fields should work. I created a form (named 'frmMain'), then created a Tab Control with two tabs. On the first tab, I inserted another form (named 'frm3197'). I also created a text box on the tab control named 'txtFieldName' AND in form 'frm3197'. From a button click on 'frmMain', the following will reference each of those fields.
Private Sub cmdButton1_Click()
Forms![frmMain]![txtFieldName] = Now()
Forms![frmMain]![frm3197].Form![txtFieldName] = Now()
End Sub

How would one detect a property of type "InvalidOperationException" within a collection?

Consider the following vb.net code for an office add-in (for access):
td = db.TableDefs(objectName)
For Each fld In td.Fields
For Each fldprp In fld.Properties
Debug.Print(fldprp.Value.ToString())
Next
Next
the variable "db" is a .net representation of the access vba return result from "Application.CurrentDB()". "td" is of type "DAO.TableDefClass".
This code throws an exception of type "InvalidOperationException" when the value of the fldprp.value property cannot be determined (in Visual Studio, it shows the value as {"Invalid Operation."} in the watch window). fldprp.name, however, is available.
There are only a few properties which this occurs on. I'd like to be able to loop through all the fld.properties and output the values, but ONLY if it is not an exception.
I am pretty sure why it is happening (certain properties are not available in this context). What I need to know is how to detect this at run-time so i can skip the property.
I can't seem to find a solution that will work. Help would be greatly appreciated.
Inside the body of the inner loop, put this at the top:
If TypeOf fldprp Is InvalidOperationException Then Continue
http://msdn.microsoft.com/en-us/library/0ec5kw18%28VS.80%29.aspx
I don't know your specific situation, but what I would suggest is using an explicit filter for the object types you want to include instead of filtering out the ones you don't want to include.