Excel VBA save Word.Range in Header to Array - vba

I am currently creating a macro that needs to save Word.Range instances to an array.
I want those range objects to be anywhere in the document. For the regular content stuff this works just fine, but when I am trying to save a range in the header, I cannot get it to work.
The sub definition:
Function GetSelectionRanges(rRng As Object, sFind As String) As Variant
rRng is a StoryRange
The code for the regular conntent ranges is as follows:
Set tmpSelections(i) = WdDoc.Range(Start:=rRng.Start, End:=rRng.End)
This one works absolutely fine and I can work with it.
I tried to extend it so it can store header objects as well:
Set tmpSelections(i) = WdDoc.StoryRanges(rRng.storytype).Range(Start:=rRng.Start, End:=rRng.End)
This, however, does not work. It says object does not support this attribute/method.
My problem at the moment is that the start and end are obtained correctly but if I use the WdDoc.Range method it uses the text stored in the regular content and thus not working as I want it to.
Definitions:
WdDoc As Object
tmpSelections() As Object
Later on I want to work with the single ranges and eventually replace values but that is a later step that cannot be incorporated in that routine.

The StoryRanges property returns a collection of Range objects, so you don't need to call .Range.
If you want to select a range within the StoryRange, use SetRange:
Set tmpSelections(i) = wdDoc.StoryRanges(rRng.StoryType)
tmpSelections(i).SetRange Start:=rRng.Start, End:=rRng.End

Related

Filling a variant array with charts in Excel VBA

I am working on a file that creates up to 120 charts based on data, variables, and format selections from the user. To do this I create a variant array to hold the charts which allows me to easily reference them for adding data, formatting, etc. This method has worked well for me so far.
Now I would like to let users make small tweaks to formatting (adjust the min and max on the axis, add or remove legend entries, etc.). To do this I would like to continue referencing the charts from an array, but I can't seem to add the existing charts to the variant array.
When I initially create the charts I use this line to add the chart to the array when it is created. I fill in appropriate parameters to place and size the chart and this seems to work fine.
Set charts(graphIndex) = activeSheet.ChartObjects.Add(...)
After creating all the charts, I think the non Global variables used are cleared from the cache (at least that is my current understanding). This means that in order to make these tweaks I need to reinitialize and redefine the variant array that I use to reference the charts. This is what I am struggling with. This is my current attempt to add the existing chart to the variant array.
charts(graphIndex) = Worksheets(activeSheetName).ChartObjects("chart name").Chart
When I run the code I am getting a "Run-time error '438': Object doesn't support property or method."
Hopefully I provided enough context, but any help on this would be greatly appreciated. This feels like it should be fairly easy, but I couldn't find any information online.
I am just guessing that in your code if you had the Set word it would have worked (However, I am not seeing the whole code, thus not sure).
This works, if you make sure to have 3 charts named "Diagramm 1", "Diagramm 2" and "Diagramm 3" on the first worksheet:
Option Explicit
Sub TestMe()
Dim cht2 As Chart
Dim varArray As Variant
With Worksheets(1)
Set cht2 = .ChartObjects("Diagramm 2").Chart
varArray = Array(.ChartObjects("Diagramm 1").Chart, cht2)
ReDim Preserve varArray(2)
Set varArray(2) = .ChartObjects("Diagramm 3").Chart
Dim cnt As Long
For cnt = LBound(varArray) To UBound(varArray)
Debug.Print varArray(cnt).Name
Next cnt
End With
End Sub
The Reedim Preserve increases the array units with one additional, while it keeps what it already has. Thus, at the end this is what we have in the locals:

VBA to Assign Named Range Reference

I am trying to assign a named range's reference from VBA. I generate a string that I want to be the named range's reference.
Ultimately my code is much more complicated than what I will show here but this boils out the gist of my problem. I can assign the reference no problem, however, when I look at the named range in the names manager I notice that all of my quotes have been doubled. For instance I have a named range called "exampleName" and so I run the following:
Sub Example()
Dim exampleStr As String
exampleStr = "EVALUATE("" = "" &ADDRESS(5,8))"
ThisWorkbook.Names("exampleName").RefersTo = exampleStr
End Sub
The code executes alright, but if I check under Name Manager I see:
As you can see, under Refers To I've 'earned' an extra set of quotes around the equals sign. For my actual sub this becomes problematic as I have to iterate, augmenting Refers To on each iteration. Each time I iterate, all of my quotes are replicated. Within only a few turns I have way more quotes than intended.
Any input on where I'm going wrong?

build method command in cell and run it in vba

I have the following command which runs correctly if placed inside a macro in vba:
Set elements = doc.getElementsByClassName("media-body")
I try to have this command running while taking the information from within a cell. Thus I place
doc.getElementsByClassName("media-body")
in cell D5 , but when I run:
Set elements = evaluate("Range(""D5"")") it throws an error (Run-time error '424': Object required.
Is there a way to solve it?
No, there isn't a way to solve it. Excel.Application.Evaluate only works with a subset of Excel objects. From the documentation:
Remarks
The following types of names in Microsoft Excel can be used
with this method:
Formulas. A1-style references. You can use any
reference to a single cell in A1-style notation. All references are
considered to be absolute references.
Ranges. You can use the range,
intersect, and union operators (colon, space, and comma, respectively)
with references. Defined names. You can specify any name in the
language of the macro.
External references. You can use the ! operator
to refer to a cell or to a name defined in another workbook ? for
example, Evaluate("[BOOK1.XLS]Sheet1!A1").
Chart Objects. You can
specify any chart object name, such as "Legend", "Plot Area", or
"Series 1", to access the properties and methods of that object. For
example, Charts("Chart1").Evaluate("Legend").Font.Name returns the
name of the font used in the legend.
The reason that you get an error 424 is because doc is an object reference in the code you are trying to run from the cell. Evaluate has no clue what doc is, because there is no way to set it to an instance from within a cell.
The only way to do anything meaningful with the cell contents in the question would be to parse the code in the cell and basically run it through an VBA-VBA interpreter.
EDIT
If I understand correctly what you're after (see the comments), what you'd really like is a way to generically search for HTML elements based on name and type. I'd approach this by selecting how to search the element name based on a type parameter. The example below assumes that the target cell (in row sourceRow and column sourceCol) contains the element name, ie "media-body", and the cell to the right contains its type - i.e. "ClassName".
Public Function GetElement(targetSheet As Worksheet, doc As HTMLDocument, _
sourceRow As Long, sourceCol As Long) As IHTMLElement
With targetSheet
'Get the element name from the passed cell.
Dim elementName As String
elementName = .Cells(sourceRow, sourceCol)
'Get the element type from the adjacent cell.
Dim elementType As String
elementType = .Cells(sourceRow, sourceCol + 1)
Select Case elementType
Case "ClassName"
Set GetElement = doc.getElementsByClassName(elementName)
Case "Id"
Set GetElement = doc.getElementById(elementName)
Case "Name"
Set GetElement = doc.getElementsByName(elementName)
'...
End Select
End With
End Function
This could just as easily be accomplished with a comma delimited string in a single cell - something like "media-body,ClassName", or several other methods but this is the direction I'd go.
Replace your:
Set elements = evaluate("Range(""D5"")")
With:
Set elements = Evaluate("D5")

troubles passing a discontinuous named range into a custom function

I've been looking around stack overflow for an answer to this for longer than I care to admit now.
Here's what I have: In a worksheet I have a bunch of discontinuous cells which I need to check for the existence of specific text. I've created a simple function to do this and can do this easily when I define that range manually (in code).
However, when I procedurally create a named range (while doing other stuff) and then try passing in the named range, the function never executes.
I know that the named range is being properly created because I have auto-formatting on it and also I can reference the range with excel formula which accept discontinuous ranges (SUM and whatnot).
Here's the pertinent portions of my code:
Function customProcess1(NamedRange As Range) As Long
For Each c in NamedRange.Cells
...
Next c
End Function
In Excel when I type the formula as "=customProcess1(A1:A2)" I get my number back after the function runs. When I type in "=customProcess1(NamedRange)" my function never even executes.
Again, I'm using the named range as defined already in the document. I can observe the name in the name manager, it references the appropriate cells, i can use the range in formula which accept non-continuous ranges, etc. I can't figure out how to get my working named range into my function.
When I put the formula as "=customProcess1("NamedRange")" the function executes, but since the named range is not ""NamedRange"" but is "NamedRange" it fails to set the object as Range (the object is not found). I've tried taking the named range as a string, but again, if I don't put the quotes around the name, it won't even run the function. So then I've tried passing in a string with the quotes and taking the quotes off inside the function, but this isn't exactly working well either.
In short, I just want to get my non-continuous named range in my custom function. Once I do that, everything is golden.
Anyone have any ideas? I'm not sure why this has been such a chore.
I'm not sure why what you're trying doesn't work and don't really have time to research that part of it, but you could do the following:
Function customProcess1(NamedRange As String) As Long
Dim TheRange As Range
Set TheRange = Range(NamedRange)
For Each c in TheRange.Cells
...
Next c
End Function
Hope this helps.
Adapting your UDF(), I coded:
Function customProcess1(NamedRange As Range) As Long
For Each c In NamedRange.Cells
customProcess1 = customProcess1 + c.Value
Next c
End Function
I then assigned the name Mike to the cells B6,C8,D10 and placed values in these cells. I then placed the formula:
=customProcess1(Mike)
in a cell and got the following:
NOTE:
I did not use =customProcess("Mike")

VBA Error 1004 - PasteSpecial method of Range class

Recently I started getting the error 1004: PasteSpecial method of Range class failed. I know people have said before that it might be that it is trying to paste to the active sheet when there is none, however, as you can see, everything is based on ThisWorkbook so that shouldn't be the problem. It happens extra much when Excel doesn't have the focus.
'references the Microsoft Forms Object Library
Sub SetGlobals()
Set hwb = ThisWorkbook' home workbook
Set mws = hwb.Worksheets("Code Numbers") ' main worksheet
Set hws = hwb.Worksheets("Sheet3") ' home worksheet (Scratch pad)
Set sws = hwb.Worksheets("Status") ' Status sheet
Set aws = hwb.Worksheets("Addresses") ' Addresses sheet
End Sub
Sub Import()
Call SetGlobals
hws.Select
'a bunch of code to do other stuff here.
For Each itm In itms
Set mitm = itm
body = Replace(mitm.HTMLBody, "<img border=""0"" src=""http://www.simplevoicecenter.com/images/svc_st_logo.jpg"">", "")
Call Buf.SetText(body)
Call Buf.PutInClipboard
Call hws.Cells(k, 1).Select
Call hws.Cells(k, 1).PasteSpecial
For Each shape In hws.Shapes
shape.Delete
Next shape
'Some code to set the value of k
'and do a bunch of other stuff.
Next itm
End Sub
Update: mitm and itm have two different types, so I did it for intellisense and who knows what else. This code takes a list of emails and pastes them into excel so that excel parses the html (which contains tables) and pastes it directly into excel. Thus the data goes directly into the sheet and I can sort it and parse it and whatever else I want.
I guess I'm basically asking for anyone who knows another way to do this besides putting it in an html file to post it. Thanks
This probably will not exactly answer your problem - but I noticed a few things in your source code that are too long to place in a comment, so here it is. Some of it is certainly because you omitted it for the example, but I'll mention it anyway, just in case:
Use Option Explicit - this will avoid a lot of errors as it forces you to declare every variable
Call SetGlobals can be simplified to SetGlobals - same for Call Buf.SetText(body) = Bof.SetText Body, etc.
No need to '.Select' anything - your accessing everything directly through the worksheet/range/shape objects (which is best practice), so don't select (hws.Select, hws.Cells(k,1).Select)
Why Set mitm = itm? mitm will therefore be the same object as itm - so you can simply use itm
You're deleteing all shapes in hwsmultiple times - for each element in itms. However, once is enough, so move the delete loop outside of the For Each loop
Instead of putting something in the clipboard and then pasting it to a cell, just assign it directly: hws.Cells(k, 1).Value = body - this should solve your error!
Instead of using global variables for worksheets that you assign in 'SetGlobals', simply use the sheet objects provided by Excel natively: If you look at the right window in the VBE with the project tree, you see worksheet nodes Sheet1 (sheetname), Sheet2 (sheetname), etc.. You can rename these objects - go to their properties (F4) and change it to meaningful names - or your current names (hwb, mws, ...) if you want. Then you can access them throughout your code without any assignment! And it'll work later, even if you change the name of Sheet3to something meaningful! ;-)
Thus, taking it all into account, I end up with the following code, doing the same thing:
Option Explicit
Sub Import()
'a bunch of code to do other stuff here.
For Each shape In hws.Shapes
shape.Delete
Next shape
For Each itm In itms
Call hws.Cells(k, 1) = Replace(itm.HTMLBody, "<img border=""0"" src=""http://www.simplevoicecenter.com/images/svc_st_logo.jpg"">", "")
'Some code to set the value of k
'and do a bunch of other stuff.
Next itm
End Sub