Unable to assign formula to cell range in Excel - vb.net

Someone else's code in the project, that I am trying to fix up.
listO.Range(i, j).FormulaR1C1 = FormulaMatrix(i, j)
where FormulaMatrix(i, j) is always a String value. Whatever random/test value, I try with, is being assigned successfully, except when it is a formula, eg.
=IF(LENGTH([#Units])>0;[#SalesAmount]-[#DiscountAmount]0)
If I remove the = sign in the beginning of the formula, it gets assigned correctly, but then it's useless, because it's not a formula.
#Units, #SalesAmount, #DiscountAmount are references/names of columns.
So, when assigning a formula, I get an exception HRESULT: 0x800A03EC. I looked up in this answer in order to get explanation and followed some of the instructions there. I determined that my problem is the following: the problem happens due to a function entered in a cell and it is trying to update another cell.
Checked out also this post. I tried quite different (like putting just the formulas without = and then run over again and put the equal signs), but same problem.
I am clueless of how to approach this.

.formulalocalworks! (While .formula, .value and .formular1c1 don't.)
I've just started working with VB.NET and came into a very similar issue. This was my simplified data at first (Table1 in Sheet1):
Then after applying the code below I had this:
The whole code for the form:
Imports Excel = Microsoft.Office.Interop.Excel
Public Class Form1
'~~> Define your Excel Objects
Dim xlApp As New Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
Dim strAddress As String = "C:\Temp\SampleNew.xlsx"
Dim list1 As Object
Private Sub btnOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOpen.Click
'~~> Add a New Workbook (IGNORING THE TWO DOT RULE)
xlWorkBook = xlApp.Workbooks.Open(strAddress)
'~~> Display Excel
xlApp.Visible = True
'~~> Set the relevant sheet that we want to work with
xlWorkSheet = xlWorkBook.Sheets("Sheet1")
With xlWorkSheet
'~~> Change the range into a tabular format
list1 = .ListObjects("Table1")
End With
list1.range(2, 4).formulalocal = "=IF(LEN([#Month])>5;[#Income]-[#MoneySpent];0)"
'~~> Save the file
xlApp.DisplayAlerts = False
xlWorkBook.SaveAs(Filename:=strAddress, FileFormat:=51)
xlApp.DisplayAlerts = True
'~~> Close the File
xlWorkBook.Close()
'~~> Quit the Excel Application
xlApp.Quit()
'~~> Clean Up
releaseObject(xlApp)
releaseObject(xlWorkBook)
End Sub
'~~> Release the objects
Private Sub releaseObject(ByVal obj As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
End Class
#Siddharth Rout helped a lot to build this code, as he owns this awesome site: http://www.siddharthrout.com/

The error might be coming from your current data, respectively, the layout of the sheet. I would suggest you to check what is inside the listO.Range(i, j).FormulaR1C1 before you assign the formula.
I have had a case where the range has already got wrong data inside, and then strangely, I don't know why, I cannot assign the new formula.
If that is the case - try clearing the value of the range and then assigning the formula:
listO.Range(i, j).FormulaR1C1 = ""
listO.Range(i, j).FormulaR1C1 = FormulaMatrix(i, j)

The problem might be with your formula. Try this-
=IF(LEN([#Units])>0,[#SalesAmount]-[#DiscountAmount],0)
If this doesn't work, I would try using the .formula method instead of .formulaR1C1.. Is there any reason in particular you are using R1C1 references?

Related

Determine if a VBComponent regards a workbook or a worksheet

The following code allows me to go through the workbook and worksheets that have macros:
For Each VBCmp In ActiveWorkbook.VBProject.VBComponents
Msgbox VBCmp.Name
Msgbox VBcmp.Type
Next VBCmp
As this page shows, for a workbook and a sheet, their type are both 100, ie, vbext_ct_Document. But I still want to distinguish them: I want to know which VBCmp is about a workbook, which one is about a worksheet.
Note that VBCmp.Name can be changed, they are not necessarily always ThisWorkbook or Sheet1, so it is not a reliable information for what I am after.
Does anyone know if there exists a property about that?
Worksheet objects and Workbook objects both have a CodeName property which will match the VBCmp.Name property, so you can compare the two for a match.
Sub Tester()
Dim vbcmp
For Each vbcmp In ActiveWorkbook.VBProject.VBComponents
Debug.Print vbcmp.Name, vbcmp.Type, _
IIf(vbcmp.Name = ActiveWorkbook.CodeName, "Workbook", "")
Next vbcmp
End Sub
This is the Function I'm using to deal with exported code (VBComponent's method) where I add a preffix to the name of the resulting file. I'm working on an application that will rewrite, among other statements, API Declares, from 32 to 64 bits. I'm planning to abandon XL 32 bits definitely. After exportation I know from where did the codes came from, so I'll rewrite them and put back on the Workbook.
Function fnGetDocumentTypePreffix(ByRef oVBComp As VBIDE.VBComponent) As String
'ALeXceL#Gmail.com
Dim strWB_Date1904 As String
Dim strWS_EnableCalculation As String
Dim strChrt_PlotBy As String
Dim strFRM_Cycle As String
On Error Resume Next
strWB_Date1904 = oVBComp.Properties("Date1904")
strWS_EnableCalculation = oVBComp.Properties("EnableCalculation")
strChrt_PlotBy = oVBComp.Properties("PlotBy")
strFRM_Cycle = oVBComp.Properties("Cycle")
If strWB_Date1904 <> "" Then
fnGetDocumentTypePreffix = "WB_"
ElseIf strWS_EnableCalculation <> "" Then
fnGetDocumentTypePreffix = "WS_"
ElseIf strChrt_PlotBy <> "" Then
fnGetDocumentTypePreffix = "CH_"
ElseIf strFRM_Cycle <> "" Then
fnGetDocumentTypePreffix = "FR_"
Else
Stop 'This isn't expected to happen...
End If
End Function

Why does assigning a reference in my spreadsheet sometimes work and sometimes not?

I have a few cells in my excel workbook which are available for a client to put his own values. I wanted the workbook to initialize those cells with default values. In order to do so I have a worksheet "Arkusz do makr", where I store the values.
In a module "GM" I declare a variable to reference my worksheet easier like this:
Public M As Worksheet
Then I initialize this variable and set my default values like this (in ThisWorkbook):
Private Sub Workbook_Open()
Set M = Worksheets("Arkusz do makr")
Worksheets("Values").Range("Value1") = M.Range("Value1")
Worksheets("Values").Range("Value2") = M.Range("Value2")
Worksheets("Values").Range("Value3") = M.Range("Value3") `etc
End Sub
Now sometimes this works like a charm, and sometimes, when I open the workbook I get a
Run-time error '91': Object variable or With block variable not set.
Could someone please explain this behaviour to me? Additionally I would like to ask if my approach makes sense, since I have a hard time grasping the order of events in excel as well as the range of its objects.
EDIT: Additionally I should mention that the Debug function highlights the first Worksheets... line in my code. In specific worksheets I reference the M object as well, though I thought it changes anything here...
Try to change the code of this Sub like below.
I have added a simple error handling - if there is no worksheet "Arkusze do makr" or "Values" in your workbook, warning message is displayed and default values are not copied.
You can find more comments in code.
Private Sub Workbook_Open()
Dim macrosSheet As Excel.Worksheet
Dim valuesSheet As Excel.Worksheet
'------------------------------------------------------------------
With ThisWorkbook
'This command is added to prevent VBA from throwing
'error if worksheet is not found. In such case variable
'will have Nothing as its value. Later on, we check
'the values assigned to those variables and only if both
'of them are different than Nothing the code will continue.
On Error Resume Next
Set macrosSheet = .Worksheets("Arkusz do makr")
Set valuesSheet = .Worksheets("Values")
On Error GoTo 0 'Restore default error behaviour.
End With
'Check if sheets [Values] and [Arkusz do makr] have been found.
'If any of them has not been found, a proper error message is shown.
'In such case default values are not set.
If valuesSheet Is Nothing Then
Call VBA.MsgBox("Sheet [Values] not found")
ElseIf macrosSheet Is Nothing Then
Call VBA.MsgBox("Sheet [Arkusz do makr] not found")
Else
'If both sheets are found, default values are copied
'from [Arkusz do makr] to [Values].
'Note that if there is no Range named "Value1" (or "Value2" etc.)
'in any of this worksheet, another error will be thrown.
'You can add error-handling for this case, similarly as above.
With valuesSheet
.Range("Value1") = macrosSheet.Range("Value1")
.Range("Value2") = macrosSheet.Range("Value2")
.Range("Value3") = macrosSheet.Range("Value3")
End With
End If
End Sub

VB Com Error for Naming Sheets on a Worksheet

I keep getting an error that says
"An unhandled exception of type
'System.Runtime.InteropServices.COMException' occurred in
Microsoft.VisualBasic.dll"
Additional information: Exception from HRESULT: 0x800A03EC"
on the line where I'm trying to change the name of the sheets from Workbook reportApp. On my timeWorkbook there are headings in cells A1, then cell D1, and so on.
I want it to loop until there is no more values, but I can't change the name. I can change the name of the sheets in that workbook if I put reportApp.Sheets(s).Name = "Name this sheet", but I don't want to do that. I was wondering if there was any problem with my type or code that would get around this?
Private Sub generateReportButton_Click(sender As Object, e As EventArgs) Handles generateReportButton.Click
Dim timeApp As Excel.Application = New Excel.Application
Dim timeClockPath As String = "C:\Users\njryn_000\Desktop\Project ACC\Clock-In Excel\TimeClock.xlsx"
Dim timeWorkbook As Excel.Workbook = timeApp.Workbooks.Open(timeClockPath, ReadOnly:=False, IgnoreReadOnlyRecommended:=True, Editable:=True)
Dim timeWorksheet As Excel.Worksheet = timeWorkbook.Worksheets("TA")
Dim reportApp As Excel.Application = New Excel.Application
Dim reportPath As String = "C:\Users\njryn_000\Desktop\Project ACC\Report\Blank Timecard Report9.xlsx"
Dim reportWorkbook As Excel.Workbook = reportApp.Workbooks.Open(reportPath, ReadOnly:=False, IgnoreReadOnlyRecommended:=True, Editable:=True)
Dim reportWorksheet As Excel.Worksheet = reportWorkbook.Worksheets("Sheet" & 1)
Dim s As Integer
Dim i As Integer
Dim f As Integer
Dim taName As String
Dim taID As String
i = 0
f = 0
s = 1
With timeWorksheet.Range("A1")
Do
i += 3
s += 1
reportApp.Sheets(s).Name = timeWorksheet.Range("A1").Offset(0, i).Value
Loop Until IsNothing(timeWorksheet.Range("A1").Offset(0, 0).Offset(0, i).Value)
You've already solved your problem but you may not be able to add an answer yet so here is some feedback.
When you use a With block you can then refer to whatever you referenced at the top of that block with a single dot ('.') after that. Its a syntax which reduces writing the same thing over and over. In the snippet below I've removed all references to timeWorksheet.Range("A1") and added a leading dot.
With timeWorksheet.Range("A1")
Do
i += 3
s += 1
' Since you are using a With block this statement is simplified.
reportApp.Sheets(s).Name = .Offset(0, i).Value
' I removed the .Offset(0, 0) as it is redundant.
' If you have it in to solve a bug you can put it back.
Loop Until IsNothing(.Offset(0, i).Value)
' More code here...
End With
Also you've realised that you can use the Val() function to fix your code. Reading the documentation, it explains that this function will take a string and begin reading a number from it, ignoring whitespace. As soon as it reaches a non-numeric, non-whitespace character it stops and returns the number ignoring whatever else is in the string.
It seems that this isn't really solving your problem, it just works around it. I'd look at what other characters are present in the cells you are looping through and deal with them explicitly. Otherwise you might end up with strange results.

Check whether a named textbox exist in the excel using VBA

Platform : MS Excel 2007(MS Visual Basic 6.0)
I have a few excel file with different textboxes in them.
All the textboxes were name. E.g TxTbox_AAAA, TxtBox_BBBB
Most of them have similar number of Textboxes with same name.
I also required to update the content inside the textboxes. But like i said... some excel file doesn't contain the textboxes.
E.g aaa.xls and bbb.xls have TexTbox_AAAA, TextBox_BBBB
and ccc.xls only have TexTbox_AAAA
my script is something like this
xlApp.ActiveSheet.TextBoxes("TextBox_AAAA").Text = TxtAAAA
xlApp.ActiveSheet.TextBoxes("TextBox_BBBB").Text = TxtBBBB
but if i run, it will encounter run-time error '1004':
Unable to get the TextBoxes property of the Worksheet class
which i suspect it is due to the excel doesn't have this textbox named "TextBox_BBBB"
so how do i put a check before xlApp.ActiveSheet.TextBoxes("TextBox_BBBB").Text = TxtBBBB
to check if this worksheet/activesheet doesn't contain TextBoxes("TextBox_BBBB"), it will not execute this step?
Since a TextBox is a Shape, here is one way to tell if a specific TextBox is on the activesheet:
Public Function IsItThere(sIn As String) As Boolean
IsItThere = False
If ActiveSheet.Shapes.Count = 0 Then Exit Function
For Each s In ActiveSheet.Shapes
If s.Name = sIn Then
IsItThere = True
Exit Function
End If
Next s
End Function
Not sure but try this:
Dim ws as Worksheet
Dim shp as Shape
Set ws = Activesheet '~~> change to suit
For Each shp in ws.Shapes
If shp.Name = "Textbox_Name" Then
'~~> your code here
End If
Next
Hope this helps
Thanks L42 and Gary's Student
I got it.. i should put
For Each s In xlApp.ActiveSheet.Shapes
instead of
For Each s In ActiveSheet.Shapes
only
Thanks for the help!!! =)

Exporting Excel Range as image (VB.NET)

I have a working excel vba macro that does what I want from here and I am trying to convert it to VB.NET.
The code from VBA:
Sub bah()
''' Set Range you want to export to file
Dim rgExp As Range: Set rgExp = Range("B2:C6")
''' Copy range as picture onto Clipboard
rgExp.CopyPicture Appearance:=xlScreen, format:=xlBitmap
''' Create an empty chart with exact size of range copied
With ActiveSheet.ChartObjects.Add(Left:=rgExp.Left, Top:=rgExp.Top, _
Width:=rgExp.Width, Height:=rgExp.Height)
.Name = "ChartVolumeMetricsDevEXPORT"
.Activate
End With
''' Paste into chart area, export to file, delete chart.
ActiveChart.Paste
ActiveSheet.ChartObjects("ChartVolumeMetricsDevEXPORT").Chart.Export "C:\Users\ajohnson\Desktop\workdamnit.jpg"
ActiveSheet.ChartObjects("ChartVolumeMetricsDevEXPORT").Delete
End Sub
What this does is take an excel range and then put it into a chart that is a copy of the range and save it as a JPG.
Here is my most recent attempt at making it VB.NET:
Dim xlApp As New Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
Dim xlRange As Excel.Range
xlWorkBook = xlApp.Workbooks.Open("C:\test.xlsx")
xlWorkSheet = xlWorkBook.Sheets("Sheet1")
xlRange = xlWorkSheet.Range("B2:C6")
With xlWorkSheet.ChartObjects.add(xlRange.Left, xlRange.Top, xlRange.Width, xlRange.Height)
.name = "Chart1"
.activate()
End With
xlWorkSheet.ChartObjects("Chart1").Paste()
xlWorkSheet.ChartObjects("Chart1").chart.export(Filename:="C:\Users\ajohnson\Desktop\saveit.jpg")
xlWorkSheet.ChartObjects("Chart1").delete()
I am running into trouble converting the ActiveChart.Paste method. I can't get it to work in VB.NET. It either throws an error or It just leaves an empty box when I do it in VB.NET (if I add .chart before the paste it runs, but doesn't paste any values), but in VBA it fills in the values of interest. I have tried creating a chart object, but that did not seem to work either.
I feel like I am close to having it sorted out, but I can't quite get it. I suppose I could leave it as a VBA macro and call it from VB.NET, but that seems absurd on some level. Any help would be greatly appreciated. I am also open to different approaches, its just this is the thing I came across that worked well in VBA, so I figured it was a good starting point.
Thanks as always!
I just had to hit the MSDN up a little harder to get there. Turns out you have to put the chartobject inside a chart, the code I got working looks like:
xlRange = xlWorkSheet.Range("B2:C6")
xlRange.CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlPicture)
Dim oChtobj As Excel.ChartObject = xlWorkSheet.ChartObjects.add(xlRange.Left, xlRange.Top, xlRange.Width, xlRange.Height)
Dim oCht As Excel.Chart
oCht = oChtobj.Chart
oCht.Paste()
oCht.Export(Filename:="C:\saveit.jpg")
oChtobj.Delete()
I was going to delete the question, since it got solved by me so quickly (this ignores the decent bit of time I spent before I posted it here), but when I search for a problem like mine it comes to this page, so maybe this will help someone in the future. If you are looking to copy a range from excel to a jpg for some reason (perhaps attaching it to the body of an outlook email, because that is what I am doing), this should work for you.
And the C# equivalent requires the call to Activate() or COMException will be thrown
Excel.Range xlRange = xlWorkSheet.Range("B2:C6");
range.CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlPicture);
Excel.ChartObject chartObj = myWorksheet.ChartObjects().Add(range.Left, range.Top, range.Width, range.Height);
chartObj.Activate(); // Don't Forget!
Excel.Chart chart = chartObj.Chart;
chart.Paste();
chart.Export(#"C:\image.png");
chartObj.Delete();