Visual Basic OLE DLL for Parsing the Database and Modifying Entities


The function to append single unit fractions to text and leaders will be called VBSUFAppend (for Visual Basic Single Unit Fraction Append).

Using the same Visual Basic project created in Example DLL to Show, Hide, or Toggle Point Display, add the following function declaration to GENERAL.CLS:

        Public Function VBSUFAppend(dummy As String)

Recall that OLE DLLs called from Visual CADD need to accept a string parameter. No parameter is used by VBSUFAppend, so we must specify a dummy.

Several variables will be required, and will be explained in the following as they are used.

                Dim iRet As Integer
                Dim iKind As Integer
                Dim iLen As Integer

                Dim hEnt As Long

                Dim strSUF As String
                Dim strText As String
                Dim strBuffer As String * 1024

In Visual Basic, characters can be represented by their byte value using the function Chr. The special character required for the single unit fractions is Chr(1). The following will put the necessary special codes into the string strSUF.

                 strSUF = " " & Chr(1) & "Nn" & Chr(1) & "/" _
                        & Chr(1) & "Dd" & Chr(1) & Chr(1)

This will produce a fraction n/d (for numerator over denominator), which can be edited by the user to insert the appropriate numeric values. The complete code will appear as *Nn*/*Dd**, using * to indicate the unprintable character represented by a hexadecimal byte equal to 1 (one).

The undo level is begun and settings are saved by:

                '       begin undo
                Call VCBeginOperation(iError)
                Call VCSaveSettings

Near the end of the program, we will include VCEndOperation and VCRestoreSettings to end the undo level and restore the settings.

To use the tool, the user must first select the text and leader entities to which he wishes to append the single unit fractions. The user does this in Visual CADD before starting the tool. The application finds the first entity selected by:

                '       get first selected entity
                iRet = VCFirstSelected(iError, iKind)

When the application calls VCFirstSelected, two values are returned (besides the error code). The integer iRet is a success code. It is 1 (one) if it found a selected entity, and 0 (zero) if no entity was selected. The integer iKind is the number representing the kind of the first entity selected. Both iRet and iKind will be used later.

If VCFirstSelected succeeds, it also makes the first selected entity the current entity. By being current, the Visual CADD API is ready to work on the entity.

The iRet can be tested to see if anything was selected. If so, the application will process it, then move to next selected entity. It will keep doing this until it processes the last selected entity and the request for the next entity fails. This can be done with a Do While … Loop.

                '       while more entities
                Do While (iRet <> 0)

We will add the Loop later to close the Do While.

As mentioned above, the Visual CADD API can work on entities either by working on the current entity or by referring to an entity by its entity handle. When we get ready to modify the text or leader entity, we will need to duplicate it with VCDuplicate. VCDuplicate requires the entity handle to work, so we can get that handle now and save it. The overview of this example cautioned against storing (or saving) entity handles for later use because they may change. We are safe in this case because the database will not change before we use the saved entity handle.

                        '       get selected entity handle
                        hEnt = VCGetCurrentEntityHandle(iError)

The application is being designed to add single unit fractions to text and leaders, so we need to check to see if the current entity is one of those kinds.

                        '       check for entity kind text
                        If (iKind = TEXT2D) Then

If it is a text entity, then we want to append the single unit fraction to it. We will do this by creating a new text entity just like the original, but with the fraction appended.

The first step is to make all the settings match the current entity (i.e., the text entity).

                                '       match current
                                Call VCMatchCurrentEntity(iError)

The only setting we must change is the text string. The new string will be the original string with the single unit fraction appended.

                                '       get existing text and append SUF
                                iLen = VCGetTextString(iError, strBuffer)
                                strText = left(strBuffer, iLen) & strSUF
                                Call VCSetTextString(iError, strText)

Note that the string passed to the VCGetTextString, strBuffer, was declared as a fixed-length string. This is the string which holds the text string returned by this routine. The string passed to VCSetTextString, strText, was declared variable-length. This is the string which holds the text string passed to this routine.

Variable-length and fixed-length strings are stored differently by Visual Basic. This is an important distinction for Visual CADD API.

Strings which are returned by the Visual CADD API routines should be declared as fixed-length with a length at least as large as the largest string to be returned. Or, the strings should be declared as variable-length but first initialized with a string which is at least as large as the largest string to be returned. One of these is necessary to ensure that the string is large enough to hold the returned string. Fixed-length strings are recommended for strings returned by Visual CADD API routines, because they need not be initialized by the application (they are automatically initialized when declared).

Strings which are passed to the Visual CADD API routines may be either fixed-length or variable length. In practice, variable-length strings are a bit easier to work with, because there is no need to be concerned with exceeding their length (up to 2 billion characters), and are recommended for strings passed to Visual CADD API routines.

Lastly, the string returned to strBuffer is null-terminated. Because strBuffer is fixed-length, if we were to simply concatenate the strings - for example, strText = strBuffer & strSUF - we would get the full length of strBuffer, including and beyond its null-terminator, followed by strSUF. This would cause strText to end at the same null-terminator - not the desired result.

Instead, to append strSUF to strBuffer, it is necessary to use the number of left-most characters of strBuffer up to its null-terminator, as specified by the string length iLen returned from VCGetTextString. This is done with the left function in Visual Basic.

Now that all the text settings are ready, the new entity with the single unit fraction is created by duplicating the original. VCDuplicate, which duplicates the entity, must reference the entity handle - it does not work on the current entity. Once duplicated, the original is deleted by VCSetCurrentErased, which does work on the current entity.

                                '       duplicate, delete original
                                Call VCDuplicate(iError, hEnt)
                                Call VCSetCurrentErased(iError)

Those steps complete the work on text entities. The steps for leader entities are similar.

                        ElseIf (iKind = LEADER2D) Then

                                '       match current
                                Call VCMatchCurrentEntity(iError)

                                '       get existing text and append SUF
                                iLen = VCGetLeaderString(iError, strBuffer)
                                strText = left(strBuffer, iLen) & strSUF
                                Call VCSetLeaderString(iError, strText)

                                '       duplicate, delete original
                                Call VCDuplicate(iError, hEnt)
                                Call VCSetCurrentErased(iError)

There are a couple of differences between the code for the leader and the code for the text - VCGetLeaderString and VCSetLeaderString are used instead, which are self explanatory.

The End If completes the If which tested for text or leaders.

                        End If

At this point, the original entity is deleted but still in the database. Deleting only marks the entity as deleted, because leaving the deleted entities in the database facilitates the undo and redo. Moreover, this deleted entity is still the current entity. VCDuplicate and the other routines which create new entities do not make those new entities current.

Now that we are done processing the current entity (i.e., the original entity), we should deselect it. Deselecting is not always necessary, but in this case, the current entity has been deleted. Leaving deleted entities selected can have unpredictable results, because they will not appear to the user.

                        '       deselect entity
                        Call VCSetCurrentDeSelected(iError)

Now that the entity has been deselected, we are completely done processing it. The next selected entity is found by using VCNextSelected.

                        '       get next entity
                        iRet = VCNextSelected(iError, iKind)

VCNextSelected works much like VCFirstSelected. It returns a success code (iRet), and error code (iError), and an entity kind (iKind). It also makes the next entity the current entity.

We are now ready to complete the Do While loop. When the application returns to the Do While, it will again test iRet. The first time through the Do While, the iRet is from the VCFirstSelected, and all subsequent times through, the iRet is from the VCNextSelected.

                Loop

The application will loop through all selected entities until VCNextEntity fails and returns a 0 (zero) to iRet. When it does, the program proceeds past the Loop and continues.

When the program falls through the loop, processing of all selected entities is complete and we are ready to restore the original settings and end the undo level.

                '       end undo
                Call VCRestoreSettings
                Call VCEndOperation(iError)

Because entities have been deleted and created, we should redraw the drawing and end.

                '       redraw
                Call VCInvalidateRect

        End Function

The final step is to create the OLE DLL using the File, Make OLE DLL File command in Visual Basic. Name your DLL VBVCADD.DLL, for Visual Basic - Visual CADD, and save it in your VBVCADD project folder. If you are adding this new function to the project created by a previous tutorial, you may replace the original VBVCADD.DLL with your new one.

To run your OLE DLL, include the following in your CMDEXT.DEF (recommended) or Assign Script (AS), where the first line is omitted for scripts.

        SUFAppend,SUA, ,Single Unit Fraction Append, Single Unit Fraction Append,
                DllName;OLEVCADD.DLL;DllFunName;VBOleDll;
                DllCmdLine;VbVCadd.General|VBSUFAppend|;DllRun;

To use SUFAppend, the user first selects the text and leaders to which he wants to append single unit fractions. Then, from Visual CADD, running SUFAppend (SUA) will append the single unit fractions to each selected text and leader. When SUFAppend returns the user to Visual CADD, the user will need to edit all the text and leaders to enter the fractional values and move the fractions to the appropriate places within the text by using cut-and-paste (CTRL+C, CTRL+X, and CTRL+V). The fractional values must be typed in place of the 'n' and 'd', being careful not to change any of the rest of the special codes, including the 'N' and 'D'.

Programming Index | VB and VC++ Setup | Example 3 Overview | Tutorial 4