Visual Studio Macro to Paste similar to String.Format - visual-studio

I'd like to be able to cut/copy a string like "<strong>{0}</strong>" for example.
I'd like to then select some code such as "Hello, World" and then invoke a macro which will result in "<strong>Hello, World</strong>".
How could you do this?
Update: WHY do I want to do this?
I could just make a macro or shortcut to add something specific like a <strong> tag to a selection. However, my idea to create any sort of "surround with" paste behavior on the fly.
Fairly often, I paste in a list of fields or properties. So from somewhere else I get
PersonID
FirstName
LastName
And just as an example, I know I want to set those up as
FieldName = dataRow("FieldName").Value
With my magic macro, I could select the following and press CTRL+C to get it in my clipboard:
{0} = dataRow("{0}").Value
Then all I have to do is go line by line and apply my magic paste.

Fun little project.
Option Strict Off
Option Explicit Off
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics
Public Module StringFormatModule
Private clipText As String
Public Property ClipboardText() As String
Get
RunThread(AddressOf GetClipboardText)
Return clipText
End Get
Set(ByVal value As String)
clipText = value
RunThread(AddressOf CopyToClipboard)
End Set
End Property
Private Function RunThread(ByVal fct As Threading.ThreadStart)
Dim thread As New Threading.Thread(fct)
thread.ApartmentState = Threading.ApartmentState.STA
thread.Start()
thread.Join()
End Function
Private Sub GetClipboardText()
clipText = My.Computer.Clipboard.GetText()
End Sub
Private Sub CopyToClipboard()
My.Computer.Clipboard.SetText(clipText)
End Sub
Sub FormatSelectedTextWithCopiedText()
Dim formatString As String
formatString = ClipboardText
Dim token As String
Dim selectedText As TextSelection
selectedText = DTE.ActiveDocument.Selection
token = selectedText.Text
selectedText.Text = String.Format(formatString, token)
End Sub
End Module
I borrowed the clipboard code from here.
This does work. I tested it on a text file, copy your formatstring into the clipboard (ctrl-c), highlight the text you want to format, and then run the macro (i just doubleclicked it from the macro explorer but you could make a keyboard shortcut).

Wouldn't it be better to define a macro that added the 'strong' tags around the selected text? Then you could assign it to Ctrl+B or whatever.
Having to select both chunks of text and invoking the macro twice seems too much like hard work to me.
(maybe you need to explain why you want to do this)

Instead of {0}, I use &. Assign macro to Ctrl+Q and you are all set!
' Wraps the current selection with the specified text. Use the & character as the anchor for the selected text.
Public Sub WrapSelection()
Dim selection As TextSelection = DirectCast(DTE.ActiveDocument.Selection, TextSelection)
DTE.UndoContext.Open("Wrap Selection")
Try
Dim sInput As String = InputBox("Wrap(&&, state)")
If Len(sInput) > 0 Then
Dim sContent As String = selection.Text
Dim iStart As Integer = InStr(sInput, "&") - 1
Dim iEnd As Integer = InStrRev(sInput, "&")
selection.Insert(sInput.Substring(0, iStart) + sContent + sInput.Substring(iEnd), vsInsertFlags.vsInsertFlagsContainNewText)
'selection.Insert(sInput.Substring(iEnd), vsInsertFlags.vsInsertFlagsInsertAtEnd)
End If
Catch ex As Exception
DTE.UndoContext.SetAborted()
MsgBox(ex.Message)
Finally
'If an error occured, then need to make sure that the undo context is cleaned up.
'Otherwise, the editor can be left in a perpetual undo context
DTE.UndoContext.Close()
End Try
End Sub

Related

callbyname vb6 using string as argument

I am trying to set some images's visibility to false by using CallByName and a loop through the objects.
here is the code
Private Sub command1Click
dim theobj_str as string
dim ctr as integer
for ctr = 1 to 3
theobj_str = "Images" & ctr
CallByName theobj_str, "Visible", vbLet,False
end for
END SUB
It throws an error "TYPE MISMATCH" on "CallByName **theobj_str**..."
The CallByName takes an object as its first argument. I need to somehow convert the string "theobj_str" into an object. How can I do this ?
The CallByName works fine if I call it like : CallByName Images2, "Visible", vbLet,False
Thanks
If you don't need to use CallByName you could loop through the controls collection and check the type. If the type matches the control you want to hide then you can set it's visible property that way.
The code would look like this:
Private Sub Command_Click()
SetControlVisibility "Image", False
End Sub
Private Sub SetControlVisibility(ByVal controlType As String, ByVal visibleValue As Boolean)
Dim ctrl As Control
For Each ctrl In Me.Controls
If TypeName(ctrl) = controlType Then
ctrl.Visible = visibleValue
End If
Next
End Sub
Doing it this way will allow you to add more image controls to your form without having to remember to change your counts in the for loop.
Hope that helps.

AutoCAD Architecture Vision Tools in AutoCAD

I have both AutoCAD and AutoCAD Architecture installed on my system. AutoCAD Architecture has a tab called Vision Tools with a nifty command called Display By Layer to set the display order of objects in accordance with the layers of the drawing. Is there anyway to add this tab or use this command in AutoCAD?
Not sure if you're looking for a built-in feature or APIs for it.
For a built in feature, check the DRAWORDER command. For an API/programming approach, check the respective DrawOrderTable method. See below:
Update: please also check this 3rd party tool: DoByLayer.
[CommandMethod("SendToBottom")]
public void commandDrawOrderChange()
{
Document activeDoc
= Application.DocumentManager.MdiActiveDocument;
Database db = activeDoc.Database;
Editor ed = activeDoc.Editor;
PromptEntityOptions peo
= new PromptEntityOptions("Select an entity : ");
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
{
return;
}
ObjectId oid = per.ObjectId;
SortedList<long, ObjectId> drawOrder
= new SortedList<long, ObjectId>();
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
) as BlockTable;
BlockTableRecord btrModelSpace =
tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForRead
) as BlockTableRecord;
DrawOrderTable dot =
tr.GetObject(
btrModelSpace.DrawOrderTableId,
OpenMode.ForWrite
) as DrawOrderTable;
ObjectIdCollection objToMove = new ObjectIdCollection();
objToMove.Add(oid);
dot.MoveToBottom(objToMove);
tr.Commit();
}
ed.WriteMessage("Done");
}
With some help from VBA it might look by this. Note i did not add fancy listbox code. I just show the worker and how to list layers. The trivial Code to add things to a listbox on a form and how to sort / rearrange listbox items can be found on any excel / VBA forum on the web . Or you just uses a predefined string like in the example. To get VBA to work download and install the acc. VBA Enabler from autocad. It is free.
'select all items on a layer by a filter
Sub selectALayer(sset As AcadSelectionSet, layername As String)
Dim filterType As Variant
Dim filterData As Variant
Dim p1(0 To 2) As Double
Dim p2(0 To 2) As Double
Dim grpCode(0) As Integer
grpCode(0) = 8
filterType = grpCode
Dim grpValue(0) As Variant
grpValue(0) = layername
filterData = grpValue
sset.Select acSelectionSetAll, p1, p2, filterType, filterData
Debug.Print "layer", layername, "Entities: " & str(sset.COUNT)
End Sub
'bring items on top
Sub OrderToTop(layername As String)
' This example creates a SortentsTable object and
' changes the draw order of selected object(s) to top.
Dim oSset As AcadSelectionSet
Dim oEnt
Dim i As Integer
Dim setName As String
setName = "$Order$"
'Make sure selection set does not exist
For i = 0 To ThisDrawing.SelectionSets.COUNT - 1
If ThisDrawing.SelectionSets.ITEM(i).NAME = setName Then
ThisDrawing.SelectionSets.ITEM(i).DELETE
Exit For
End If
Next i
setName = "tmp_" & time()
Set oSset = ThisDrawing.SelectionSets.Add(setName)
Call selectALayer(oSset, layername)
If oSset.COUNT > 0 Then
ReDim arrObj(0 To oSset.COUNT - 1) As ACADOBJECT
'Process each object
i = 0
For Each oEnt In oSset
Set arrObj(i) = oEnt
i = i + 1
Next
End If
'kills also left over selectionset by programming mistakes....
For Each selectionset In ThisDrawing.SelectionSets
selectionset.delete_by_layer_space
Next
On Error GoTo Err_Control
'Get an extension dictionary and, if necessary, add a SortentsTable object
Dim eDictionary As Object
Set eDictionary = ThisDrawing.modelspace.GetExtensionDictionary
' Prevent failed GetObject calls from throwing an exception
On Error Resume Next
Dim sentityObj As Object
Set sentityObj = eDictionary.GetObject("ACAD_SORTENTS")
On Error GoTo 0
If sentityObj Is Nothing Then
' No SortentsTable object, so add one
Set sentityObj = eDictionary.AddObject("ACAD_SORTENTS", "AcDbSortentsTable")
End If
'Move selected object(s) to the top
sentityObj.MoveToTop arrObj
applicaTION.UPDATE
Exit Sub
Err_Control:
If ERR.NUMBER > 0 Then MsgBox ERR.DESCRIPTION
End Sub
Sub bringtofrontbylist()
Dim lnames As String
'predefined layer names
layer_names = "foundation bridge road"
Dim h() As String
h = split(layernames)
For i = 0 To UBound(h)
Call OrderToTop(h(i))
Next
End Sub
'in case you want a fancy form here is how to get list / all layers
Sub list_layers()
Dim LAYER As AcadLayer
For Each LAYER In ThisDrawing.LAYERS
Debug.Print LAYER.NAME
Next
End Sub
to make it run put the cursor inside the VBA IDE inside the code of list_layers andpress F5 or choose it from the VBA Macro list.

vb6, variable not defined for Label using Module

Sorry to ask such a dumb question.. but for the life of me i cant get it.. i have searched EVERYWHERE... This is a Re-Creation of my code that gives the same error. This is the most basic example i could re-create.
I dont understand why i have to declare a Label ?? (or an object)
What I am trying to accomplish is use my main form to call all the modules.
This is the FORM
'frmMain.frm
Option Explicit
Public Sub btnOpen_Click()
GetNum
End Sub
This is the MODULE
'modGet.bas
Option Explicit
Public Sub GetNum()
Dim a As String
Dim b As String
a = "hello"
b = "world"
-> Label1.Caption = a 'ERROR, Compile Error, Variable not Defined. (vb6)
Label2.Caption = b
End Sub
YES, i have a form, with a Button named 'btnOpen', i have 2 Labels named 'Label1' & 'Label2'
If i ADD..
Dim Label1 As Object 'in MODULE
i get a different error..
ERROR '91' Object Variable or With block variable not set
IF I put everything in 1 FORM, it works..(but i want to use separate modules)
I Commented out 'OPTION EXPLICIT' ... same error.
In another Test, i got the error for a TextBox..
TextBox1.Text = x
Once i get the answer for this, i can apply it for everything... I'm sure it's simple too and imma feel stupid. :-(
One of my Main Things is Querying WMI, and i get the ERROR '91' for the Label (This is in a For Each Loop) .. But its the same error, its like its makin me Declare Objects..(using Modules)
Label1.Caption = objItem.Antecedent
If Someone Could PLEASE Help me...
Use
form1.label1.caption = a
But make sure form1 is loaded
You get the error because Label1 and Label2, and your other controls for that matter do not exist in the scope of modGet.bas. They can only be referenced (the properties accessed or set), from with the form. The different error you get when you add Dim Label1 As Object is caused because an you defined Label1 as an Object, not as a Label, and an object does not have a Caption property. Unless you have a good reason for putting the GetNum sub in a .bas module move it into the form and it should work.
I modified the second example. It will modify the strings passed into it in a way that when execution passes back to the form you can assign the strings to your textboxes. I am against modifying controls on a form from another module because it goes against the idea of encapsulation.
'modGet.bas
Option Explicit
Public Function GetHello() As String
Dim strHello As String
strHello = "Hello"
GetHello = strHello
End Function
'frmMain.frm
'Option Explicit
Public Sub btnOpen_Click()
Label1.Caption = GetHello()
End Sub
Something a little different.
'MyModule.bas
Public Sub HelloWorld ByRef Value1 As String, ByVal Value2 As String)
On Error GoTo errHelloWorld
Value1 = "Hello"
Value2 = "World"
Exit Sub
errHelloWorld:
' deal with the error here
End Sub
'frmMain.frm
Option Explicit
Private Sub frmMain_Load()
Dim strText1 As String
Dim strText2 As String
HelloWorld(strText1, strText2)
Text1.Text = strText1
Text2.Text = strText2
End Sub
I also added basic error handling in the second example

Trying to automatically split data in excel with vba

I have absolutely no experience programming in excel vba other than I wrote a function to add a data stamp to a barcode that was scanned in on our production line a few weeks back, mainly through trial and error.
Anyways, what I need help with right now is inventory is coming up and every item we have has a barcode and is usually scanned into notepad and then manually pulled into excel and "text to columns" is used. I found the excel split function and would like a little bit of help getting it to work with my scanned barcodes.
The data comes in in the format: 11111*A153333*11/30/11 plus a carriage return , where the * would be the delimiter. All the examples I've found don't seem to do anything, at all.
For example here is one I found on splitting at the " ", but nothing happens if I change it to *.
Sub splitText()
'splits Text active cell using * char as separator
Dim splitVals As Variant
Dim totalVals As Long
splitVals = Split(ActiveCell.Value, "*")
totalVals = UBound(splitVals)
Range(Cells(ActiveCell.Row, ActiveCell.Column + 1), Cells(ActiveCell.Row, ActiveCell.Column + 1 + totalVals)).Value = splitVals
End Sub
And this is applied in the Sheet1 code section, if that helps.
It really can't be this complicated, can it?
Edit: Trying to add in Vlookup to the vba.
So as I said below in the comments, I'm now working on getting the vlookup integrated into this, however it just returns N/A.
Here is the sub I wrote based on the link below
Public Sub vlook(ByRef codeCell As Range)
Dim result As String
Dim source As Worksheet
Dim destination As Worksheet
Set destination = ActiveWorkbook.Sheets("Inventory")
Set source = ActiveWorkbook.Sheets("Descriptions")
result = [Vlookup(destination!(codeCell.Row, D), source!A2:B1397, 2, FALSE)]
End Sub
And I was trying to call it right after the For loop in the worksheet change, and just created another for loop, does this/should this be a nested for loop?
Just adding the code to the VBA behind the worksheet won't actually cause it to get called. You need to handle the worksheet_change event. The following should help:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Dim cell As Range
For Each cell In Target.Cells
If cell.Column = 1 Then SplitText cell
Next
Application.EnableEvents = True
End Sub
Public Sub SplitText(ByRef codeCell As Range)
'splits Text active cell using * char as separator
Dim splitVals As Variant
Dim totalVals As Long
splitVals = Split(codeCell.Value, "*")
totalVals = UBound(splitVals)
Range(Cells(codeCell.Row, codeCell.Column), Cells(codeCell.Row, codeCell.Column + totalVals)).Value = splitVals
End Sub
If you want to process the barcodes automatically on entering them, you need something like this (goes in the worksheet module).
Private Sub Worksheet_Change(ByVal Target As Range)
Dim splitVals As Variant
Dim c As Range, val As String
For Each c In Target.Cells
If c.Column = 1 Then 'optional: only process barcodes if in ColA
val = Trim(c.Value)
If InStr(val, "*") > 0 Then
splitVals = Split(val, "*")
c.Offset(0, 1).Resize( _
1, (UBound(splitVals) - LBound(splitVals)) + 1 _
).Value = splitVals
End If
End If 'in ColA
Next c
End Sub

Control Properties in Visual Basic 6

Is there a way to ask for a control property in a loop??
I need somethig like this:
For each p in control.properties
if p = "Value" then
msgbox "I Have Value Property"
elseif p = "Caption" then
msgbox "I Have Caption Property"
end if
next
It could be done somehow?
Found this code on Experts Exchange. Add a reference to TypeLib Information.
Public Enum EPType
ReadableProperties = 2
WriteableProperties = 4
End Enum
Public Function EnumerateProperties(pObject As Object, pType As EPType) As Variant
Dim rArray() As String
Dim iVal As Long
Dim TypeLib As TLI.InterfaceInfo
Dim Prop As TLI.MemberInfo
On Error Resume Next
ReDim rArray(0) As String
Set TypeLib = TLI.InterfaceInfoFromObject(pObject)
For Each Prop In TypeLib.Members
If Prop.InvokeKind = pType Then
iVal = UBound(rArray)
rArray(iVal) = UCase$(Prop.Name)
ReDim Preserve rArray(iVal + 1) As String
End If
Next
ReDim Preserve rArray(UBound(rArray) - 1) As String
EnumerateProperties = rArray
End Function
You can ask for a list of the readable, or writeable properties.
Bonus, ask if a specific property exists.
Public Function DoesPropertyExist(pObject As Object, ByVal _
PropertyName As String, pType As EPType) As Boolean
Dim Item As Variant
PropertyName = UCase$(PropertyName)
For Each Item In EnumerateProperties(pObject, pType)
If Item = PropertyName Then
DoesPropertyExist = True
Exit For
End If
Next
End Function
Beaner has given an excellent direct answer to the question you have asked.
I'm guessing what you might be trying to do. Perhaps you're trying to get the "text" from a control but you don't know the type of the control at runtime. You could consider something like this, which tries a number of hard-coded property names in turn until something works.
Function sGetSomeText(ctl As Object) As String
On Error Resume Next
sGetSomeText = ctl.Text
If Err = 0 Then Exit Function
sGetSomeText = ctl.Caption
If Err = 0 Then Exit Function
sGetSomeText = ctl.Value
If Err = 0 Then Exit Function
sGetSomeText = "" 'Nothing worked '
End Function
Another approach would be to check the type of the control at runtime. You can use
If TypeName(ctl) = "whatever" or
If TypeOf ctl Is whatever.
Then you could switch to code for specific control types that definitely have the Text property, etc.
I'm not sure what you're hoping to accomplish, but I'm pretty sure VB6 does not support what you're talking about. You could try something like this:
If control.Value Is Not Nothing Then
msgbox "I Have Value Property"
Else If control.Caption Is Not Nothing Then
msgbox "I Have Caption Property"
See if that accomplishes what you're looking to do.

Resources