Home About Us Services Experience Technology Resources Careers News Contact Us
Mission and Values
Leadership Team
Certifications
Capability Statement
Consulting
Development
Turnarounds
Support
Success Stories
Presentations
Publications
Awards
EDI
RFID
Extranet
Voice and Speech
Natural Language
Handheld and Mobile
Articles and Reference
Code Samples
Downloads
Regular Reading
Email Subscriptions
Services Recommendations
Software Recommendations
Current Opportunities
Careers for Developers
FoxPro Code Samples
StringBuilder Class  |  Class Factory  |  Distance from MapQuest

StringBuilder Class (FoxPro Advisor, March, 2003)
The StringBuilder class allocates huge blocks of memory at once, then keeps writing into this memory block.

DEFINE CLASS StringBuilder AS CUSTOM
   nBlockSize = 64 * 1024
   nNextChar  = 0
   nAllocated = 0
   nPointer   = 0
   * Allocate memory. Initial size can be specified.
   PROCEDURE Init(tnInitialSize AS NUMBER)
      DECLARE LONG GetProcessHeap IN Win32API
      DECLARE LONG HeapAlloc IN Win32API LONG, LONG, LONG
      IF VARTYPE(m.tnInitialSize) == "N"
         THIS.nAllocated = m.tnInitialSize
      ELSE
         THIS.nAllocated = THIS.nBlockSize
      ENDIF
      THIS.nPointer  = HeapAlloc(GetProcessHeap(), 0, THIS.nAllocated)
      THIS.nNextChar = THIS.nPointer
      IF THIS.nPointer == 0
         ERROR "Out of memory"
      ENDIF
   ENDPROC
   * Free all resources
   PROCEDURE Destroy
      DECLARE LONG GetProcessHeap IN Win32API
      DECLARE LONG HeapFree IN Win32API LONG, LONG, LONG
      IF THIS.nPointer # 0
         HeapFree(GetProcessHeap(), 0, THIS.nPointer)
      ENDIF
   ENDPROC
   * Adds a new substring. Pass string by reference.
   PROCEDURE Append(rcString)
      DECLARE LONG GetProcessHeap IN Win32API
      DECLARE LONG HeapReAlloc IN Win32API LONG, LONG, LONG, LONG
      LOCAL lnLength, lnSize
      lnLength = LEN(m.rcString)
      IF THIS.nNextChar + m.lnLength > THIS.nPointer + THIS.nAllocated
         lnSize          = THIS.nNextChar - THIS.nPointer
         THIS.nAllocated = THIS.nAllocated + THIS.nBlockSize
         THIS.nPointer   = HeapReAlloc(GetProcessHeap(), 0, THIS.nPointer, THIS.nAllocated)
         IF THIS.nPointer == 0
            ERROR "Out of memory"
         ENDIF
         THIS.nNextChar = THIS.nPointer + m.lnSize
      ENDIF
      SYS(2600, THIS.nNextCHar, m.lnLength, m.rcString
   ENDPROC
   * Returns the whole string
   FUNCTION GetString
      RETURN SYS(2600, THIS.nPointer, THIS.nNextChar - THIS.nPointer)
ENDDEFINE
To Use:
loSB = NewObject("StringBuilder", "StringBuilder.PRG")
loSB.Append("Hello ")
loSB.Append("world")
? loSB.GetString()    && Prints "Hello world"
Notes:
Performance drastically depends on the nBlockSize property. In the worst case, this parameter matches the size of the string to add. This forces StringBuilder to re-allocate memory for each call to Append. The ideal case if if nBlockSize matches the size of the final string. Then no re-allocation is necessary. The key to succeeding is to keep your working strings relatively small compared to the final result string, and reduce the number of times you append to the result.

Class Factory
One approach to simplifying the creation of server-sided COM objects is to use a ClassFactory object to create the objects. This is a very small COM DLL that is installed on the server and can be called from each client (depending on how you choose, either by CLSID or by registering locally on each PC). Then you call the CreateClass method in order to create other COM objects on the server. This way you don't need to have each COM DLL registered on the client since the actual creation of the object happens on the server and the object is then passed back to the client.

The ClassFactory really only needs one method, CreateClass(), however we also use this object from our SQL Server machines to access COM objects across the network so we also have a CreateClassEx method since SQL Server cannot handle creation of distributed objects.

Here's the code:

DEFINE CLASS ClassFactory AS Session OLEPUBLIC
   PROCEDURE CreateClass (lcClassName)
   RETURN CREATEOBJECT(lcClassName)
   ENDPROC
   PROCEDURE CreateClassEx (lcClassName, lcServer)
   RETURN CREATEOBJECTEX(lcClassName, lcServer)
   ENDPROC
ENDDEFINE
Distance From MapQuest
An inexpensive way to compute the exact distance between two addresses can be derived from the MapQuest Directions function. Note that this method depends on the layout of the web page that MapQuest returns; if the page layout or URL changes, then this code will not work. This routine requires a connection to the Internet.

lcSrcAddr  = [2222+Oak+Pkwy]    && Replace spaces with "+"
lcSrcCity  = []
lcSrcState = []
lcSrcZip   = [11111]
lcTrgAddr  = [1000+Main+St]
lcTrgCity  = [AnyTown]
lcTrgState = [GA]
lcTrgZip   = []
lcURL      = [http://www.mapquest.com/directions/main.adp?go=1] +;
             [&1a=] + lcSrcAddr +;
             [&1c=] + lcSrcCity +;
             [&1s=] + lcSrcState +;
             [&1z=] + lcSrcZip +;
             [&2a=] + lcTrgAddr +;
             [&2c=] + lcTrgCity +;
             [&2s=] + lcTrgState +;
             [&2z=] + lcTrgZip +;
             [&2ah=] + [] +;
             [&formtype1=address&formtype2=address]
lcTarget   = [Total Est. Distance: ]
oHTTP = CreateObject("MSXML2.XMLHTTP")
oHTTP.Open([GET],lcURL,.F.)
oHTTP.Send()
lcHTMLcode = oHTTP.ResponseText
lnMiles    = VAL(substr(lcHTMLCode, at(lcTarget, lcHTMLCode) + len(lcTarget), 20))
© The Intellection Group, Inc.  All Rights Reserved
Privacy Statement    Disclaimer