Malicious Office (OLE) — malware analysis report

Static analysis result for SHA-256 7a56f83c4d532efc…

MALICIOUS

Office (OLE)

329.0 KB Created: 1998-02-13 10:23:00 Authoring application: Microsoft Word 8.0 First seen: 2012-06-14
MD5: 15528b76f1928bec8f6de20f56ad4249 SHA-1: 067e373478ffb8ad7bb5b1b44bfb496781ac528b SHA-256: 7a56f83c4d532efcb7bac4ce8708f5655d9c6988cd9fbb3c37a940ff45939b12
146 Risk Score

Malware Insights

MITRE ATT&CK
T1059.005 Visual Basic

The sample exhibits high-confidence indicators of legacy WordBasic macro virus markers and VBA macros, specifically AutoOpen and AutoClose functions. These are designed to execute malicious code automatically when the document is opened or closed. The presence of these legacy features suggests an older, but still potentially dangerous, macro-based attack vector.

Heuristics 7

  • VBA macros detected medium 4 related findings OLE_VBA_MACROS
    Document contains VBA macro code
  • VBA macro-virus self-replication / AV tampering critical OLE_VBA_MACRO_VIRUS_REPLICATION
    VBA macro programmatically rewrites VBA project code through the VBE object model (CodeModule/VBComponents InsertLines/DeleteLines/AddFromString or OrganizerCopy) to copy itself into the global template and other open documents, and/or disables Office macro-virus protection (Options.VirusProtection = False). This is the defining behavior of the W97M document macro-virus family — self-replicating code with no benign document use, independent of any AV signature.
    Matched line in script
        Application.OrganizerCopy Source:= _
  • AutoOpen macro low OLE_VBA_AUTOOPEN
    AutoOpen macro
    Matched line in script
    Sub autoopen()
  • Auto_Close macro low OLE_VBA_AUTOCLOSE
    Auto_Close macro
    Matched line in script
    Sub AutoClose()
  • Environ() call (env variable access) low OLE_VBA_ENVIRON
    Environ() call (env variable access)
    Matched line in script
        WordBasic.SetPrivateProfileString kWizname$, id$, v$, Environ("windir") + "\wordwiz.ini"
  • Legacy WordBasic macro-virus markers high OLE_LEGACY_WORDBASIC_MACRO_VIRUS
    OLE Word document contains legacy WordBasic auto-execution macro markers such as AutoOpen plus ToolsMacro/MacroFile/fileMacro/globMacro or named historical macro-virus strings. These old Word 6/95 macro forms are not exposed as a modern VBA project, so normal VBA source extraction can miss them.
  • Embedded URL info EMBEDDED_URL
    One or more URLs were extracted from the document. The URL itself is not a detection — see the per-URL labels for which channel (macro, JS, link annotation, document body, ...) reached each URL.
    URL http://www.microsoft.com/isapi/redir.dll In document text (OLE body)
    • http://www.microsoft.com/isapi/redir.dll?PRD=Word&SBP=ia&PVER=8.0&AR=templatesIn document text (OLE body)

Extracted artifacts 1

Files carved from inside the sample during analysis.

FilenameKindSourceSize
macros.bas vba-macro oletools.olevba.extract_macros (decoded VBA source) 532676 bytes
SHA-256: 30a1aa373845a9208caae51638e1951f5259b9183844b7ff5227c7ae9e343060
Preview script
First 1,000 lines of the extracted script
Attribute VB_Name = "ThisDocument"
Attribute VB_Base = "1Normal.ThisDocument"
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Attribute VB_TemplateDerived = True
Attribute VB_Customizable = True

Attribute VB_Name = "UC01"
Attribute VB_Base = "0{FCFB3D2A-A0FA-1068-A738-08002B3371B5}"
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = False
Private Const SZ_MACRONAME = "¨Ã¦C¤å¦r"

Sub Insert()
    With Selection
        If Len(.Text) = 1 And .Text = (Chr$(13)) Then
            MsgBox "½Ð¥ý¿ï¨ú­n¨Ã¦Cªº¤å¦r¡A¦A¿ï¨ú¥»¥\¯à¿ï¶µ¡C", _
                    Title:=SZ_MACRONAME
            GoTo LExit:
        End If
        If ((.Start = .End) And (.Text = Chr$(21))) Then
            .MoveRight , 1, 1
        End If
        If (Right$(.Text, 1) = Chr$(13)) Then
            .End = .End - 1
        End If
        If (FIsRubyField(.Range) = False) Then
            If (.Range.Fields.Count > 0) Or (InStr(1, .Text, Chr$(13)) <> 0) _
                Or (InStr(1, .Text, vbTab) <> 0) Or (InStr(1, .Text, ",") <> 0) _
                Or (InStr(1, .Text, "(") <> 0) Or (InStr(1, .Text, vbTab) <> 0) Then
                MsgBox "µLªk¬°§t¦³©w¦ìÂI¡B¥\¯àÅܼƩM¬q¸¨²Å¸¹ªº¦r¦ê¥[¤J¨Ã¦Cªºµù¸Ñ", Title:=SZ_MACRONAME
                GoTo LExit:
            End If
        End If
        If (Selection.Start = Selection.End) Then
            MsgBox "½Ð¿ï¨ú­n¥[¤Jµù¸Ñªº¦r¦ê", Title:=SZ_MACRONAME
            GoTo LExit:
        End If
    End With
    InitDialog
    dlgRuby.Show
LExit:
End Sub

Sub Create(szRuby As String, szFont As String, iSize As Integer, iDist As Integer, szAlign As String)
    Dim rgn As Range
    Dim n As Integer
    Dim iCurSize As Integer
    Dim szCurFont As String
    Dim fnt As Font
    Application.ScreenUpdating = False
    System.Cursor = wdCursorWait
    
    On Error GoTo LError
    With Selection
        Set rgn = .Range
        Set fnt = GetCurFont(rgn)
        If (FIsRubyField(rgn) = True) Then
            Delete
        End If

        iCurSize = fnt.Size
        szCurFont = fnt.Name
        n = Len(.Text)
        
        ' Insert Field
        .Fields.Add .Range, , , False
        .TypeText "eq \o"
        
        ' Ruby string align
        Select Case (szAlign)
        Case "¾a¥ª"
            .TypeText "\al"
        Case "µ¥¶¡¶Z®i¶}"
            .TypeText "\ad"
        Case Else
        End Select
        
        .TypeText "(\s\up" + Str$(Int(iDist + .Font.Size - 1)) + "("
        .InsertBefore szRuby
        .Font.Size = iSize
        .Font.Name = szFont
        .Font.DisableCharacterSpaceGrid = False
        .MoveRight
        .InsertAfter "),"
        .Font.Size = iCurSize
        .Font.Name = szCurName
        .MoveRight , n + 2
        .TypeText ")"
        ' Kludge, To remove space char at end of field....
        .MoveLeft , 2
        .Delete unit:=wdCharacter, Count:=1
        
        .Fields.ToggleShowCodes
        .MoveRight , 1, 1
        
    End With
LExit:
    Application.ScreenUpdating = True
    System.Cursor = wdCursorNormal
    Exit Sub
LError:
    MsgBox Err.Description, Title:=SZ_MACRONAME
End Sub

Sub Delete()
    Dim rgn As Range
    Dim rgnFld As Range
    Dim rgnNew As Range
    Dim szCode As String
    Dim FUpdate As Boolean
    
    On Error GoTo LError
    If (Application.ScreenUpdating = True) Then
        FUpdate = True
        Application.ScreenUpdating = False
        System.Cursor = wdCursorWait
    Else
        FUpdate = False
    End If
    
    With Selection
        Set rgn = .Range
        If (.Fields.Count < 1) Then GoTo LExit:
        For i = 1 To .Fields.Count
            szCode = rgn.Fields(i).Code
            Set rgnFld = rgn.Fields(i).Code
            If (FIsRubyField(rgn) = False) Then
                GoTo LExit:
            End If
            
            iTop = InStr(1, szCode, ",") + rgnFld.Start
            iEnd = rgnFld.End - 1
            rgnFld.SetRange iTop, iEnd
            
            .MoveLeft
            Set rgnNew = Selection.Range
            rgnNew.FormattedText = rgnFld.FormattedText
            .MoveRight , Len(rgnFld.Text)
            .MoveRight , 1, 1
            .Delete
            rgnNew.Select
            
        Next i
    End With
LExit:
    If (FUpdate = True) Then
        Application.ScreenUpdating = True
        System.Cursor = wdCursorNormal
    End If
    Exit Sub
LError:
    MsgBox Err.Description, Title:=SZ_MACRONAME
End Sub

Sub InitDialog()
    Dim i As Integer
    Dim n As Integer
    Dim szFont As String
    Dim szCode As String
    Dim fnt As Font
    Dim fntRuby As Font
    
    On Error GoTo LError:
    Application.ScreenUpdating = False
    System.Cursor = wdCursorWait

    dlgRuby.IDCD_ALIGN.Clear
    dlgRuby.IDCD_ALIGN.AddItem "¾a¥ª"
    dlgRuby.IDCD_ALIGN.AddItem "¸m¤¤"
    dlgRuby.IDCD_ALIGN.AddItem "µ¥¶¡¶Z®i¶}"
    
    With Selection
        Set fnt = GetCurFont(.Range)
        If (FIsRubyField(.Range) = True) Then
            dlgRuby.ID_RESET.Enabled = True
            ' Get Selected Field Values
            ' { eq \o\ad(\s\up 12(foo),bar) }
            Dim rgn As Range
            .Fields(1).Select
            Set rgn = .Fields(1).Code
            szCode = .Fields(1).Code.Text
            
            ' { eq \o\ad(\s\up 12(foo),bar) }
            '                     ~~~
            iTop = InStr(11, szCode, "(")
            iEnd = InStr(1, szCode, ",") - 2
            Set rgn = .Fields(1).Code
            rgn.SetRange rgn.Start + iTop, rgn.Start + iEnd
            Set fntRuby = GetCurFont(rgn)
            dlgRuby.IDCT_FONT.Caption = fntRuby.NameFarEast
            dlgRuby.IDCT_SIZE.Caption = fntRuby.Size
            dlgRuby.IDCE_TEXT = rgn.Text
            
            ' { eq \o\ad(\s\up 12(foo),bar) }
            '                  ~~
            iTop = InStr(1, szCode, "up ") + 2
            iEnd = InStr(11, szCode, "(")
            Set rgn = .Fields(1).Code
            rgn.SetRange rgn.Start + iTop, rgn.Start + iEnd
            dlgRuby.IDCE_DIST = Val(Mid$(szCode, iTop, iEnd - iTop)) - Int(fnt.Size) + 1
            
            ' { eq \o\ad(\s\up 12(foo),bar) }
            '        ~~~
            If (InStr(1, szCode, "\al") > 0) Then
                dlgRuby.IDCD_ALIGN.ListIndex = 0
            ElseIf (InStr(1, szCode, "\ad") > 0) Then
                dlgRuby.IDCD_ALIGN.ListIndex = 2
            Else
                dlgRuby.IDCD_ALIGN.ListIndex = 1
            End If
        Else
            dlgRuby.ID_RESET.Enabled = False
            dlgRuby.IDCE_TEXT = ""
            dlgRuby.IDCE_DIST = Str$(0)
            dlgRuby.IDCT_SIZE.Caption = Int(fnt.Size / 2)
            dlgRuby.IDCT_FONT.Caption = fnt.NameFarEast
            dlgRuby.IDCD_ALIGN.ListIndex = 1
        End If
        dlgRuby.IDCE_TEXT.IMEMode = fmIMEModeNoControl
        dlgRuby.IDCE_TEXT.SetFocus
        dlgRuby.IDCE_TEXT.SelStart = 0
        dlgRuby.IDCE_TEXT.SelLength = 99
        If (dlgRuby.IDCE_TEXT.Text <> "") Then
            dlgRuby.IDOK.Enabled = True
        Else
            dlgRuby.IDOK.Enabled = False
        End If
    End With

    Application.ScreenUpdating = True
    System.Cursor = wdCursorNormal
    Exit Sub
LError:
    MsgBox Err.Description, Title:=SZ_MACRONAME
End Sub

Function FIsRubyField(rgn As Range) As Boolean
    FIsRubyField = False
    If (rgn.Fields.Count = 0) Then Exit Function
    a$ = rgn.Fields(1).Code.Text
    ' { eq \o\ad(\s\up 12(foo),bar) }
    '   ~~~~~   ~~~~~~ and "),\s\do" is only contained Kumimoji field
    If (Left$(a$, 6) = " eq \o") And (InStr(6, a$, "(\s\up") <> 0) And (InStr(9, a$, "),\s\do") = 0) _
        And (Right$(a$, 1) = ")") Then
        FIsRubyField = True
    End If
End Function


Function BuildRedirString$()

Dim RedirString$
Dim Arg$(0 To 11)
Dim OS As String

Select Case System.OperatingSystem
Case "Windows"
  OS = "Win"
Case "Windows NT"
  OS = "WinNT"
Case "Macintosh"
  OS = "Mac"
Case Else
  OS = "Win"
End Select

RedirString$ = "http://www.microsoft.com/isapi/redir.dll?"

Arg$(0) = "PRD=Word"
Arg$(1) = "&SBP=ia"
Arg$(2) = "&PLCID=" & Application.International(wdProductLanguageID)
Arg$(3) = "&PVER=" & Application.Version
Arg$(4) = "&OS=" & OS
Arg$(5) = "&OVER=" & System.Version
Arg$(6) = "&OLCID=" 'intentionally left blank
Arg$(7) = "&CLCID=" & "0x" & System.PrivateProfileString("", "HKEY_CURRENT_USER\Control Panel\International", "Locale")
Arg$(8) = "&AR=templates"
Arg$(9) = "&O1="
Arg$(10) = "&O2="
Arg$(11) = "&O3="


For i = 0 To 11
  RedirString$ = RedirString$ & Arg$(i)
Next

BuildRedirString$ = RedirString$

End Function

Sub UpdateLink()
    Dim Anchor As Range
    For Each Hlink In ActiveDocument.Hyperlinks 'look at all hyperlinks in doc
        If Hlink.Address = "http://www.microsoft.com/isapi/redir.dll?PRD=Word&SBP=ia&PVER=8.0&AR=templates" Then 'look for address to change
            If Hlink.Type = msoHyperlinkRange Then 'get Anchor - Text Or Shape
                Set Anchor = Hlink.Range        'text anchor
            Else
                Set Anchor = Hlink.Shape        'shape anchor
            End If
            Hlink.Delete            'delete old link
            ActiveDocument.Hyperlinks.Add Anchor, BuildRedirString()  'add new hlink in same place
        End If
    Next
End Sub

Option Explicit

'Standard Claimer

''******************************************************************************
'TO BE LOCALIZED
''******************************************************************************
'Style names
Public Const strSTY_RETURN_ADDR     As String = "Return Address"
Public Const strSTY_DOC_LABEL       As String = "Document Label"
Public Const strSTY_COMPANY_NAME    As String = "Company Name"
Public Const strSTY_MSG_HDR_FIRST   As String = "Message Header First"
Public Const strSTY_MSG_HDR_LABEL   As String = "Message Header Label"
Public Const strSTY_MSG_HDR_LAST    As String = "Message Header Last"

'misc strings
Public Const strPHONE   As String = "¹q¸Ü¡G"
Public Const strFAX     As String = "¶Ç¯u¹q¸Ü¡G"
Public Const strPAGES   As String = "Á`­¶¼Æ¡G"
Public Const strTO      As String = "¦¬¥óªÌ¡G"
Public Const strFROM    As String = "±H¥óªÌ¡G"
Public Const strDATE    As String = "¤é´Á¡G"
Public Const strRE      As String = "¥D¦®¡G"
Public Const strCC      As String = "ªþ¥»¡G"

Public Const strCOMPANY         As String = "¤½¥q¦æ¸¹¡G"
Public Const strFAX_NUMBER      As String = "¶Ç¯u¹q¸Ü¡G"
Public Const strPHONE_NUMBER    As String = "¹q¸Ü¡G"
Public Const strTOTAL_NO_PAGES  As String = "¥]§t«Ê­±¦b¤ºÁ`¦@­¶¼Æ¡G"

Public Const strEMPTY_MACRO As String = "EmptyMacro "
Public Const strNONE        As String = "<None>" 'choice to list of merge field
                                                 'names found in data source
                                'doc. if there is no field for last name.
                                'if the user selected this choice we don't
                                'insert a merge field for last name in the cover sheet.
Public Const strFLD_NAME As String = "Name" 'to select the field containing recipient name
                                    'from the fields present in the data source
Public Const strFLD_FAX As String = "Fax" 'to select the merge field containing fax number

Public Const strCLICK_HERE_NAME     As String = "[«ö¤@¤U³o¸Ì¿é¤J©m¦W]"
Public Const strCLICK_HERE_PAGES    As String = "[«ö¤@¤U³o¸Ì¿é¤J¶Ç¯u­¶¼Æ]"
Public Const strCLICK_HERE_SUBJECT  As String = "[«ö¤@¤U³o¸Ì¿é¤J¶Ç¯u¥D¦®]"
Public Const strCLICK_HERE_COMMENTS As String = "[«ö¤@¤U³o¸Ì¿é¤J¥²­nªºµù°O]"
Public Const strCLICK_HERE_COMPANY  As String = "[«ö¤@¤U³o¸Ì¿é¤J¤½¥q¦WºÙ]"
Public Const strCLICK_HERE_PHONE_NUMBER As String = "[«ö¤@¤U³o¸Ì¿é¤J¹q¸Ü]"
Public Const strCLICK_HERE_FAX_NUMBER As String = "[«ö¤@¤U³o¸Ì¿é¤J¶Ç¯u¹q¸Ü]"

'Address format to get info. from the Address book. Please be careful about the commas and
'spaces since you might end up with a space at the beginning of a name if not put at the right place.
'Please change the names only if you know the correct one.
Public Const strADDR_BK_NAME_FORMAT As String = "{{<PR_GIVEN_NAME> }{<PR_SURNAME>}|<PR_DISPLAY_NAME>}"
Public Const strADDR_BK_ADDR_FORMAT As String = "{<PR_POSTAL_ADDRESS>|{<PR_STREET_ADDRESS>" & vbCr & "}{<PR_LOCALITY>}{, {<PR_STATE_OR_PROVINCE> }<PR_POSTAL_CODE>}}"
Public Const strADDR_BK_FAXNUM_FORMAT As String = "{<PR_PRIMARY_FAX_NUMBER>|<PR_BUSINESS_FAX_NUMBER>|<PR_HOME_FAX_NUMBER>}"
Public Const strADDR_BK_PHONE_FORMAT As String = "{<PR_PRIMARY_TELEPHONE_NUMBER>|<PR_BUSINESS_TELEPHONE_NUMBER>|<PR_OFFICE_TELEPHONE_NUMBER>}"
Public Const strADDR_BK_COMPANY_FORMAT As String = "{<PR_COMPANY_NAME>}"

'status messages put up while faxing the cover sheet and document. For some messages
'I add "..." and so add "..." to all strings.
Public Const strFAXING_DOC_RECIPIENTS As String = "¥¿¦b¶Ç¯u³o¥÷¤å¥óµ¹©Ò¦³¦¬¥óªÌ..."
Public Const strFAXING_DOC_RECIPIENT As String = "¥¿¦b¶Ç¯u³o¥÷¤å¥óµ¹¦¬¥óªÌ"
Public Const strFAXING_CS_RECIPIENTS As String = "¥¿¦b¶Ç¯u«Ê­±µ¹©Ò¦³¦¬¥óªÌ..."
Public Const strFAXING_CS_RECIPIENT As String = "¥¿¦b¶Ç¯u«Ê­±µ¹©Ò¦³¦¬¥óªÌ"
Public Const strFAXING_CS_TO As String = "¥¿¦b¶Ç¯u«Ê­±¨ì"
Public Const strFAXING_DOC_TO As String = "¥¿¦b¶Ç¯u¤å¥ó¨ì"

'the text in the last panel
'the first one is the default. The next string is used if the user selects no cover sheet, when
'we actually send the fax on clicking Finish
Public Const strLAST_PANEL_DFLT_TEXT As String = "¦pªG°õ¦æºëÆF¦³°ÝÃDªº¸Ü¡A½Ð­«·s°õ¦æ¶Ç¯uºëÆF¡AÀˬd¿é¤J¶Ç¯u¹q¸Üªº®æ¦¡¬O§_¥¿½T¡C¨Ò¦p¡A±z¬O¤£¬O§Ñ¤F¶Q¤½¥qªº¹q¸Ü¨t²Î¦b¼·¥~½u«e¡A»Ý¥ý«ö­ÓÁä¡A¤ñ¦p»¡¼Æ¦rÁä¡u9¡v¡C­n°O±o¥[¶i¶Ç¯u¹q¸Ü¤¤³á¡I"
Public Const strLAST_PANEL_NOCOVSHT_TEXT As String = "©Ò¦³¸ê®Æ¤w¿é¤J§¹²¦¡A«ö¤@¤U§¹¦¨Áä¡AºëÆF±N°e¥X±zªº¶Ç¯u¤å¥ó¡I"

'strings necessary to display help in case of failure of Fax
Public Const strHLP_FAX_INSTALL As String = "¦pªG±z²{¦b°õ¦æªº¬O Windows 95¡A²{¦b±z´N¥i¥H¦w¸Ë¥»ºëÆF¤F¡C«ö¤U½T©wÁä¡A¿Ã¹õ¤W±N·|¥X²{»²§U»¡©ú¤å¥ó¡A§i¶D±z¦p¦ó¦w¸ËºëÆF¡I"
'the next string is the title as it appears on Word's main window
Public Const strMS_WORD As String = "Microsoft Word"

'make sure that strCMD_BAR_TITLE is as long as strCMD_BTN_TEXT, so that strCMD_BTN_TITLE does not get clipped off
'when the command bar is displayed.
Public Const strCMD_BAR_TITLE   As String = "¤¤¤å¶Ç¯uºëÆF"
Public Const strCMD_BTN_TEXT    As String = "²{¦b°e¥X¶Ç¯u"

Public Const strCURRENT_DOC     As String = "¥Ø«eªº¤å¥ó("
Public Const strRIGHT_PAREN     As String = ")"

'Window caption of the cover sheet (the document's name will follow if the user is faxing a document)
Public Const strWINDOW_CAPTION  As String = "ªº¶Ç¯u«Ê­±ªí³æ"
'Window caption if user is not faxing a doc. and just created a cover sheet.
Public Const strCOVER_SHEET_CAPTION As String = " - ¶Ç¯u«Ê­±ªí³æ"

'Text in merge fields inserted in the cover sheet
Public Const strFLD_FAX_NAME    As String = "Name"
Public Const strFLD_FAX_NUMBER  As String = "FaxNumber"

'In NT3.51, the printer name from the print set up dialog which is called when the user clicks on
'Other... , returns the printer name with the printer location after ON
'so if a printer name is \\abcd\efg with location "location1" then the printer
'name is returned a "\\abcd\efg ON location1. So we have to strip out the text
'after ON. That's what this constant is for. In other countries too is this text
'going to be ON?
Public Const strPRINTER_ON      As String = " ON "

Public Const iMAX_ADDR_LINES = 3 'max. # of lines address can have
'Error messages
Public Const strERR_MAX_ADDR_LINES  As String = "¦a§}¤£¥i¶W¹L¤T¦æ¡C"
Public Const strERR_NO_DATA_SRC     As String = "ºëÆF§ä¤£¨ì­n¶Ç¯uªº¤å¥ó¡C"
Public Const strERR_CREATING_CMDBAR As String = "ºëÆFµLªk«Ø¥ß¡uSend Fax¡v¤u¨ã¦C¡C ½Ð­«·s°õ¦æ¶Ç¯uºëÆF¡C"
Public Const strERR_NO_MAIN_DOC1     As String = "­n«Ø¥ß«Ê­±ªí³æªº¤å¥ó ("
Public Const strERR_NO_MAIN_DOC2     As String = ") ¥¼¶}±Ò¡C½Ð¥ý¶}±Ò¸Ó¤å¥ó¡AµM«á­«·s°õ¦æºëÆF¡I"
Public Const strERR_DISPLAY_QUERY_OPTIONS As String = "ºëÆF§ä¤£¨ì­n¥[¤Jªº¸ê®Æ¡C"
Public Const strERR_CHOOSING_DOC As String = "ºëÆFµLªk¿ï¨ú­n¥Î¨Ó¶Ç¯uªº¤å¥ó¡C"
Public Const strERR_RCPNTS_NOT_CHOSEN As String = "ºëÆF»Ý­nª¾¹D³o¥÷ªº¦¬¥óªÌ¬O½Ö¡C½Ð«ö¤U¡u½T©w¡v¶s¡AµM«á¿ï¨ú¶Ç¯uªº¦¬¥óªÌ¡C"

'this tip is displayed in an Autodown balloon finally
Public Const strPOST_WIZARD_TIP_NO_MRG_FLD As String = "½Ð¿é¤J¨ä¥¦±z·Q¼g¦b«Ê­±ªí³æ¤Wªº¸ê®Æ¡AµM«á«ö¤U¦b " & strCMD_BAR_TITLE & " ¤u¥y¦C¤Wªº¡u" & strCMD_BTN_TEXT & "¡v¶s¡C "
'this tip is displayed if we inserted merge fields in the cover sheet i.e. in the case of multiple recipients
Public Const strPOST_WIZARD_TIP_MRG_FLD As String = "½Ð¿é¤J¨ä¥¦±z·Q¼g¦b«Ê­±ªí³æ¤Wªº¸ê®Æ¡AµM«á«ö¤U¦b " & strCMD_BAR_TITLE & " ¤u¥y¦C¤Wªº¡u" & strCMD_BTN_TEXT & "¡v¶s¡C " & "¦ý½Ð¤£­n§R°£¦b¡u<< >>¡v²Å¸¹¤¤ªºÄæ¦ì¡Fµy«á¶Ç¯uºëÆF±N§Q¥Î¥L­Ì¨Ó¶Ç¯u±z«ü©wªº¤å¥ó¨ì¦¬¥óªÌ¤â¤W¡C"

'this message is put up after we successfully faxed everything
Public Const strMSG_FAX_SUCCESS As String = "ºëÆF¤w±N±zªº¤å¥ó°e¥X¥h¤F¡C"

'the 72 factor in the below 2 measurements is conversion factor of inches to points
'contemporary styles have a left indent of 0.56"
Public Const sCONT_LEFT_INDENT As Single = 0.56 * 72
'While converting text to table, for the Contemporary style alone,
'I need to set the first column's width explicitly. For English text,
'0.5" is big enough. If the text in the first column is getting truncated
'in your language, then please increase this value.
Public Const sCONT_WIDTH_COL1 As Single = 2.36 * 72

'The date format need not be localized if VB does not require it.
'Medium date is of the format "02-Apr-94". If the standard date format
'is anything different in the country, then please change it.
'important to have MMMM and not mmmm, since mm refers to minutes in a time field
Public Const strDATE_FORMAT As String = "MMMM d, yyyy"

''******************************************************************************
'DO NOT LOCALIZE THE CONSTANTS/DECLARATIONS BEYOND THIS
''******************************************************************************
'the following are the names of the autotext entries in the wizard.
'DON'T CHANGE THE NAMES OF THE AUTOTEXT ENTRIES IN THE WIZARD.
'if you change them, then please change the following strings too, correspondingly
Public Const strAT_UNCHKD_BOX   As String = "Unchecked Box"
Public Const strAT_CHKD_BOX     As String = "Checked Box"
Public Const strCNTMPGFX2        As String = "cntmpgfx2"
Public Const strPOST_WIZ_BLN    As String = "Fax Post Wizard Balloon"

Public Const sA4_LEFT_MARGIN    As Single = 82.08
Public Const sA4_RIGHT_MARGIN    As Single = 81.36
Public Const sLETTER_MARGIN     As Single = 90
'key where setup writes company name
Public Const strREGKEY_CMPNY_NAME As String = "HKEY_CURRENT_USER\Software\Microsoft\MS Setup (ACME)\User Info"
Public Const strVALKEY_CMPNY_NAME As String = "DefCompany"

Public fDocChanged As Boolean 'set if user changes the doc. to be faxed

Public objMainDoc As Document 'main doc which has to be sent
Public objDataSrc As MailMergeDataSource ' main doc's data src

'SQL query used to select all names from the data source
Public Const strSELECT_QUERY As String = "Select * From "

'form and callback balloon constants
Public Const iMAX_PANEL As Integer = 6 'panel # of the last panel in
                             'the dialog (starts from 0)
Public rgstrAssistantMsg(iMAX_PANEL) As String   ' as many as there are states

Public strBULLET     As String
Public strSOFT_ENTER As String
Public rgstrNotes(3) As String
Public strQUOTE As String
'available styles
Public Const iSTY_PROFESSIONAL  As Integer = 0
Public Const iSTY_CONTEMPORARY  As Integer = 1
Public Const iSTY_ELEGANT       As Integer = 2

'array for holding long and short template names
Public rgstrTemplateFileNames(3, 3) As String
Public Const iLONG_NAME As Integer = 0
Public Const iSHORT_NAME As Integer = 1

Public iFaxStyle As Integer 'stores the fax style chosen
Public fStylesCopied As Boolean

Public fMSFAXEnabled As Boolean 'disabled in NT

'Panel numbers
Public Const iPANEL_RCPNTS As Integer = 3
Public Const iPANEL_SENDER As Integer = 5
Public Const iPANEL_STYLE  As Integer = 4

'Max. number of recipients
Public Const iMAX_RCPNTS As Integer = 5

Public fDocIsFormLtr As Boolean 'true if doc. is a form letter
'to store the data options query that the user selects for the form letter
Public strFormLetterSQL As String
Public strFormLetterSQL1 As String
Public strConnectString As String
Public fDocPresent   As Boolean 'true if there is an main doc. apart
                                'from the doc created by FileNew
'keeps track of which panel to be skipped.
'if we are enabling a panel, then we need to restore the shape's
'color to as it was before. rgiColorShape stores that color
Public rgfSkipPanel(iMAX_PANEL) As Boolean 'if rgfSkipPanel(i) is True,
                                            'then skip the ith panel
Public rgiColorShape(iMAX_PANEL) As Long
Public fCheckValidity As Boolean
Public fNoCovSht As Boolean 'False if user selects "No cover sheet"

Public iFaxOption       As Integer 'Fax program selected by the user
Public Const iMS_FAX    As Integer = 0  'Microsoft Fax
Public Const iDIFF_FAX  As Integer = 1  'Other than MS Fax
Public Const iNO_FAX    As Integer = 2  'just print without faxing the doc/cover sheet

Public fRegistryNamesRead As Boolean 'true if MRU list has been read from reg.

Dim rgstrFaxTitle(3)        As String
Dim rgstrChkBoxText(5)      As String 'text beside the check boxes
Public strAsstMsgRcpntsFormLtr As String 'assistant help for form letter recipients' panel
Public strAsstMsgRcpntsOrdDoc As String 'assistant help for ordinary doc. recipients' panel

'tip displayed in an autodown balloon after the wizard is done
Public fCreatedCmdBar           As Boolean 'tip is to be displayed only if cmd bar created

'arrays to get the MRU list of recipient names and numbers stored in the registry
Dim rgstrMRUFaxNames(iMAX_RCPNTS) As String
Dim rgstrMRUFaxNums(iMAX_RCPNTS)  As String

'arrays to get the recipients names and numbers that the user entered
Dim rgstrRcpntFaxNames(iMAX_RCPNTS) As String
Dim rgstrRcpntFaxNums(iMAX_RCPNTS)  As String
Public iNumRcpnts As Integer

'DO NOT LOCALIZE - CONTROL NAMES
Public Const strCBO_RCPNT_NAME  As String = "cboRcpntName"
Public Const strCBO_RCPNT_NUM   As String = "cboRcpntNum"
Public iCboRcpntNameFocus       As Integer

'DO NOT LOCALIZE - REGISTRY ENTRIES
Public Const strRCPNT_NAME      As String = "Name of recipient#"
Public Const strRCPNT_NUMBER    As String = "Number of recipient#"
Public Const strNUM_RCPNTS      As String = "Number of recipients"

'Help files
Public Const strWIN_HELP_FILE As String = "Windows.hlp"
Public Const strFAX_HELP_FILE As String = "awfax.hlp"

'contexts for the help
Public Const lCNTXT_FAX_INSTALL As Long = 461903903
Public Const lCNTXT_FAX_SEND As Long = 1698757633
Public Const HELP_COMMAND As Integer = 258 'hex value = 0x0102

'error number that word returns on fax not being installed
Public Const iERR_FAX_NOT_INSTALLED As Integer = 5663
Public Const iERR_FAX_NOT_SENT As Integer = 4559

'DO NOT LOCALIZE - REGISTRY ENTRIES REGARDING PRINTERS
Declare Function RegEnumKey Lib "advapi32.dll" Alias "RegEnumKeyA" _
(ByVal hKey As Long, ByVal dwIndex As Long, ByVal lpName As String, ByVal cbName As Long) As Long

Declare Function RegOpenKey Lib "advapi32.dll" Alias "RegOpenKeyA" _
(ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long

Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long

Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal strDir As String, ByVal uSize As Integer) _
As Integer

Declare Function FindWindow Lib "USER32" Alias "FindWindowA" (ByVal strWndClassName As String, _
ByVal strWndName As String) As Long

Declare Function WinHelp Lib "USER32" Alias "WinHelpA" (ByVal hwnd As Long, ByVal strFileName As String, _
ByVal wCmd As Integer, ByVal dwData As Any) As Integer


Public rgstrPrinterNames()  As String
Public iTotalNumPrinters    As Integer

Const HKEY_LOCAL_MACHINE As Long = &H80000002
'Const KEY_ALL_ACCESS As Long = &HF0063
Const ERROR_SUCCESS As Long = 0
Const ERROR_NO_MORE_ITEMS As Long = 259

'registry keys under which printer names are found
Const strREG_PROVIDERS As String = "System\CurrentControlSet\Control\Print\Providers\"
Const strREG_LOCAL_PRINTERS As String = "System\CurrentControlSet\Control\Print\Printers\"

'initialise the vars. whiehc refer to the wizard's name
Public Sub InitWizardName(fDummy As Boolean)
    
    strWizName = "¤¤¤å¶Ç¯uºëÆF"
    strWizLongName = "¤¤¤å¶Ç¯uºëÆF"
    strWizShortName = "CFax1"

End Sub

'initialize strings specific to this wizard
Private Sub InitWizardStrings()
Dim i As Integer
    
    'fax title for the different styles
    rgstrFaxTitle(iSTY_CONTEMPORARY) = "¶Ç¯u«H¥ó"
    rgstrFaxTitle(iSTY_ELEGANT) = "¶Ç¯u«H¥óªí³æ"
    rgstrFaxTitle(iSTY_PROFESSIONAL) = "¶Ç¯u"
    
    'text appearing after the unchecked boxes
    rgstrChkBoxText(1) = "«æ¥ó"
    rgstrChkBoxText(2) = "½Ð¬d¾\"
    rgstrChkBoxText(3) = "½Ð§å¥Ü"
    rgstrChkBoxText(4) = "½Ð¦^ÂÐ"
    rgstrChkBoxText(5) = "½Ð¶Ç¾\"
    
    'Assistant messages
    rgstrAssistantMsg(0) = "¨Ï¥Î¶Ç¯uºëÆF¡A±z¥i¥H¶Ç¯u¹q¤l¶l¥ó¡A±N«H¥ó¦X¨Ö¨ì¶Ç¯u¤å¥ó¤¤¤@°_¶Ç¯u¡A ©Î±q¶Ç¯u¾÷¤¤¦L¥X¤@±i«Ê­±ªí³æ¡C"
    rgstrAssistantMsg(1) = "¦pªG±z·Q­n¶Ç¯u¨ä¥¦¤å¥ó¡A½Ð¥ý¶}±Ò±z·Q­n¶Ç¯uªº¤å¥ó¡AµM«á¦A°õ¦æ¶Ç¯uºëÆF¡C"
    rgstrAssistantMsg(2) = "¦pªG±zªº§@·~¨t²Î¬O Windows NT¡A«h±zµLªk¨Ï¥Î Microsoft ¶Ç¯u¡A¦ý¬O±zÁÙ¬O¥i¥H¨Ï¥Î¨ä¥¦¤w¦w¸Ë¦b¨t²Î¤¤ªº¶Ç¯u³nÅé¨Ó¬°±z¶Ç¯u¡C¦pªG±zªº¨t²Î¤£¤ä´©¶Ç¯u¥\¯àªº¸Ü¡A¨SÃö«Y¡A±z¥i¥H¥ý±N¤å¥ó¦C¦L¥X¨Ó¡AµM«á¦A§Q¥Î¶Ç¯u¾÷±N¤å¥ó¶Ç¯u¥X¥h¡C"
    rgstrAssistantMsg(iPANEL_RCPNTS) = "¦pªG±z´¿¥Î¹L¶Ç¯uºëÆF¡A«h¤U©Ô¦¡²M³æ¤è¶ô¤¤·|¦C¥X±z³Ìªñ¶Ç¯u¹Lªº¤å¥ó¦WºÙ¡C ±z¥i¥H¦b²M³æ¤¤¿ï¨ú¶Ç¯u¹Lªº¤å¥ó¡A±N¨äªþ¦b±zªº«Ê­±ªí³æ¤§«á¤@°_¶Ç¯u¥X¥h¡C"
    rgstrAssistantMsg(iPANEL_SENDER) = "½Ð¿é¤J±z·Q¼g¦b«Ê­±ªí³æ¤W¦³Ãö°e¥óªÌªº¸ê®Æ¡C"
    rgstrAssistantMsg(iPANEL_STYLE) = "½Ð¿ï¨ú±z«Ê­±ªí³æ©Ò­nªº®æ¦¡¡C¦b¶Ç¯u¤§«e¡A±zÁÙ¬O¥i¥H§ïÅܫʭ±ªí³æªº¥~Æ[¡A©Î¬O¥[¤J¥²­nªºµù°O¡C"
    rgstrAssistantMsg(iMAX_PANEL) = "­n­×§ï¥ô¦ó³]©w¡A½Ð«ö¡u¤W¤@¨B¡v¡C"
    'if user is faxing a form letter, we have a different set of controls in the Recipients panel. So, we change the help text too.
    strAsstMsgRcpntsFormLtr = "½ÐÂI¨ú¡u©m¦W¡vÄæ¦ì¡A¦A¨Ó½ÐÂI¨ú¡u¶Ç¯u¹q¸Ü¡vÄæ¦ì¡A µM«á±q³q°T¿ý¤¤¿ï¨ú­n¥[¤Jªº¦¬¥ó¤H©Î¨ä¶Ç¯u¹q¸Ü¡C ±z¥i¥H¿ï¾Ü¶Ç¯uµ¹¨C¤@­Ó¤H©Î¬O«ü©w¥u¶Ç¯uµ¹¬Y¤H¡C"
    strAsstMsgRcpntsOrdDoc = "¦pªG±z´¿¥Î¹L¶Ç¯uºëÆF¡A¨º»ò¡u©m¦W¡vÄæ¦ìªº¤U©Ô¦¡²M³æ¤è¶ô¤¤·|¦³³Ìªñ¶Ç¯u¹ï¶Hªº¦W¦r¡C±z¥i¥H±q¤¤¿ï¨ú¦¬¥óªÌ©m¦W´¡¤J«Ê­±ªí³æ¤¤¡C"
    

    rgstrTemplateFileNames(iSTY_PROFESSIONAL, iLONG_NAME) = "±M·~¦¡¶Ç¯u.dot"
    rgstrTemplateFileNames(iSTY_PROFESSIONAL, iSHORT_NAME) = "cPrfax.dot"
    rgstrTemplateFileNames(iSTY_CONTEMPORARY, iLONG_NAME) = "²{¥N¦¡¶Ç¯u.dot"
    rgstrTemplateFileNames(iSTY_CONTEMPORARY, iSHORT_NAME) = "cCofax.dot"
    rgstrTemplateFileNames(iSTY_ELEGANT, iLONG_NAME) = "¨å¶®¦¡¶Ç¯u.dot"
    rgstrTemplateFileNames(iSTY_ELEGANT, iSHORT_NAME) = "cElfax.dot"
    
    rgstrNotes(iSTY_PROFESSIONAL) = "µù¸Ñ¡G"
    rgstrNotes(iSTY_CONTEMPORARY) = "µù¸Ñ¡G"
    rgstrNotes(iSTY_ELEGANT) = "µù¸Ñ¡G"
    
    ''**********************************************************************
    'DO NOT LOCALIZE BEYOND THIS POINT.
    ''******************************************************************************
    
    'initialize arrays with the color of the subway shapes for the panels
    For i = 0 To iMAX_PANEL
        rgfSkipPanel(i) = False
        rgiColorShape(i) = COLOR_LIGHTGREY
    Next i

    strBULLET = "•"""
    strSOFT_ENTER = Chr$(11)
    strQUOTE = Chr$(34)
                                        
    'DO NOT LOCALIZE THE NEXT STRING. WE WANT TO STORE ONLY ONE SET
    'OF DIALOG VALUES IN THE REGISTRY.
    strRegSettingsKey = strREG_SETTINGS_BASE_KEY & "Fax Wizard"
End Sub

'initialises the form
Private Sub InitForm()
    On Error GoTo FatalError
    
    Set formWizard = New formWizDlg
    If formWizard Is Nothing Then
        DisplayErrorMsg strERR_INIT_FORM
        ReportError Err
    End If

    iCurrentPanel = 0
    formWizard.lblWizardName1.Caption = " " & strWizLongName & " "
    Exit Sub

FatalError:
    DisplayErrorMsg strERR_INIT_FORM
    ReportError Err
    
End Sub

Sub InitWizard(fDummy As Boolean)
    
    InitForm
    InitWizardStrings

    fNoCovSht = False
    fStylesCopied = False
End Sub

Public Sub SetMainDoc(fDummy As Boolean)
Dim cDocs As Integer
Dim i As Integer

    On Error GoTo FatalError
    
    fDocIsFormLtr = False
    fDocPresent = False
    fDocChanged = False
    cDocs = Application.Documents.Count
    
    If cDocs > 1 Then
    'we don't want to add the doc. that was just created thro' FileNew
        For i = 2 To cDocs
            formWizard.cboDocList.AddItem Documents(i).Name
        Next i

        formWizard.cboDocList.ListIndex = 0
        fDocPresent = True
    Else
        'just one doc. i.e the freshly created one
        Set objMainDoc = Nothing
    End If
    Exit Sub

FatalError:
    ReportError Err

End Sub

'checks the kind of document and sets fDocIsFormLtr
Public Sub CheckDocKind(objDoc As Document)
Dim objMM As MailMerge
Dim strQueryString As String
    On Error GoTo LReturn
    fDocIsFormLtr = False
    Set objMM = objMainDoc.MailMerge
    Set objDataSrc = objMM.DataSource
    If objDataSrc.Type = wdNoMergeInfo Then GoTo LReturn
    strQueryString = objDataSrc.QueryString
    strFormLetterSQL = Left$(strQueryString, 255)
    strFormLetterSQL1 = Mid$(strQueryString, 256)
    strConnectString = objDataSrc.ConnectString
    fDocIsFormLtr = True
    
    Exit Sub
LReturn:
    Err.Clear
    fDocIsFormLtr = False
End Sub

Public Sub CreateCoverSheet(fDummy As Boolean)
Dim strDocName As String
Dim objFps As PageSetup

    On Error GoTo FatalError
    Application.StatusBar = strCREATING_DOC
    Application.ScreenUpdating = False
    
    System.Cursor = wdCursorWait

    If fChangeToA4 Then
        Set objFps = ActiveDocument.PageSetup
        objFps.LeftMargin = sA4_LEFT_MARGIN
        objFps.RightMargin = sA4_RIGHT_MARGIN
    ElseIf fChangeToLetter Then
        Set objFps = ActiveDocument.PageSetup
        objFps.LeftMargin = sLETTER_MARGIN
        objFps.RightMargin = sLETTER_MARGIN
    End If
    
    If (((Not (fDocIsFormLtr)) And (iNumRcpnts > 1)) Or fDocIsFormLtr) Then _
        CreateDataSource
        
    StatusBar = strCREATING_DOC
    Select Case iFaxStyle
    Case iSTY_PROFESSIONAL
        CreateProfContCoverSheet
    Case iSTY_CONTEMPORARY
        CreateProfContCoverSheet
    Case iSTY_ELEGANT
        CreateElegCoverSheet
    End Select
    
    If (fDocPresent) And (Not (formWizard.optCovSht.Value)) Then
        strDocName = ActiveWindow.Caption & " - " & objMainDoc.Name & strWINDOW_CAPTION
    Else
        strDocName = ActiveWindow.Caption & strCOVER_SHEET_CAPTION
    End If
        
    With ActiveWindow
        .Caption = strDocName

        .View.TableGridlines = False
    End With
    ActiveDocument.UndoClear
    Selection.HomeKey wdStory
    
    With ActiveDocument.Content
        .SpellingChecked = True
        .GrammarChecked = True
    End With
    
    Exit Sub
    
FatalError:
    ReportError Err
End Sub

'creates a data source for the cover sheet in the temp. directory
Private Sub CreateDataSource()
Dim objRng As Range
Dim strPath As String
Dim objDataSrcDoc As Document, objMM As MailMerge
Dim strDataSrcName As String
    On Error GoTo FatalError
    
    Set objMM = ActiveDocument.MailMerge
    objMM.MainDocumentType = wdFormLetters
    
    If (fDocIsFormLtr) Then
        objMM.OpenDataSource objDataSrc.Name, Connection:=strConnectString
        objMM.DataSource.QueryString = strFormLetterSQL & strFormLetterSQL1
        Exit Sub
    End If
    
    Set objDataSrcDoc = Application.Documents.Add
    
    Set objRng = objDataSrcDoc.Content
    
    CreateTableFromFaxInfo objRng
    
    strPath = Options.DefaultFilePath(wdTempFilePath)
    If Right$(strPath, 1) <> strPathSeparator Then _
        strPath = strPath & strPathSeparator
        
    strDataSrcName = strPath & "~$CovSht@" & Format$(Date, "dd-mm-yy") & "," & Format$(Time, "hh-mm-ss") & ".tmp"
    objDataSrcDoc.SaveAs strDataSrcName, wdFormatDocument
    objDataSrcDoc.Close wdDoNotSaveChanges
    
    'attach the data source doc. to activedocument (cover sheet)
    objMM.OpenDataSource strDataSrcName
    
    Exit Sub
FatalError:
    ReportError Err
End Sub


'creates a table in the data source document with names and numbers
'the format of the table is just like how one would create a data source doc.
'through Word
Private Sub CreateTableFromFaxInfo(objRange As Range)
Dim strText As String
Dim i As Integer

    On Error GoTo FatalError

    strText = strFLD_FAX_NAME & vbCr & strFLD_FAX_NUMBER
    
    'collect the names and numbers entered by the user
    For i = 1 To iNumRcpnts
        strText = strText & vbCr & rgstrRcpntFaxNames(i - 1) & vbCr & rgstrRcpntFaxNums(i - 1)
    Next i

    objRange.InsertBefore strText
    'Add a table with 2 columns and iNumRcpnts+1 rows
    objRange.Select
    Selection.ConvertToTable vbCr, iNumRcpnts + 1, 2
    
    Exit Sub
FatalError:
    ActiveDocument.Close wdDoNotSaveChanges 'close the data source doc.
    ReportError Err
End Sub

Public Function FCopyStyles(iStyle As Integer) As Boolean
    Dim strStyleName As String
    Dim strLongName As String
    Dim i As Integer
    
    On Error GoTo TemplateNotFound
LFindTemplate:
    ' Attempt to locate longname, then shortname template file
    i = iLONG_NAME
    strStyleName = strTemplatePath & rgstrTemplateFileNames(iStyle, iLONG_NAME)
    strLongName = strStyleName
    If Dir(strStyleName) <> "" Then GoTo LApplyStyles
LTryShortName:
    i = iSHORT_NAME
    strStyleName = strTemplatePath & rgstrTemplateFileNames(iStyle, iSHORT_NAME)

LApplyStyles:
    StatusBar = strAPPLYING
    
    ' Get styles
    ActiveDocument.CopyStylesFromTemplate (strStyleName)
    
    ' No Error
    fStylesCopied = True
    StatusBar = ""
    FCopyStyles = True
    Exit Function
    
TemplateNotFound:
    If i = iLONG_NAME Then
        i = iSHORT_NAME
        Err.Clear
        GoTo LTryShortName
    End If
    DisplayErrorMsg strERR_STYLE_NOT_FOUND & strLongName & strERR_STYLE_NOT_FOUND2
    fStylesCopied = False
    StatusBar = ""
    FCopyStyles = False
End Function

'creates professional/Contemporary style cover sheet
Private Sub CreateProfContCoverSheet()
Dim objRngBuffer1 As Range
Dim objRngBuffer2 As Range
Dim strCmpnyName As String, strName As String
Dim strMFFirstName As String, strMFLastName As String, strMFFaxNum As String
Dim objRngTextTable As Range
Dim objTable As Table

    On Error GoTo FatalError
    
    If iFaxStyle = iSTY_CONTEMPORARY Then
        InsertContAutoText
        objActiveRange.Collapse wdCollapseEnd
    End If
    
    InsertReturnAddress
    GetMergeFieldNames strMFFirstName, strMFLastName, strMFFaxNum
    
    'Insert company name
    strCmpnyName = formWizard.txtCompany.Text
    If (iFaxStyle = iSTY_PROFESSIONAL) Then
        If (Len(strCmpnyName)) Then
            objActiveRange.Style = strSTY_COMPANY_NAME
            objActiveRange.InsertBefore strCmpnyName & vbCr
            objActiveRange.Collapse wdCollapseEnd
        End If
        'Insert title
        objActiveRange.Style = strSTY_DOC_LABEL
        objActiveRange.InsertBefore rgstrFaxTitle(iFaxStyle) & vbCr
        objActiveRange.Collapse wdCollapseEnd
    End If
    

    
    Set objRngTextTable = objActiveRange.Duplicate
    
'the topics To: and From: have a character style which has to be
'applied after the data has been written (since the data have a
'different style). so, use a range buffer
    
    '1st line text has style "Message Header First". The subsequent
    'lines have "Message Header"
    
    'Insert To:
    objActiveRange.Style = strSTY_MSG_HDR_FIRST
    objActiveRange.InsertBefore strTO
    Set objRngBuffer1 = objActiveRange.Duplicate

    'insert recipient name
    If (iNumRcpnts = 1) And (Not (fDocIsFormLtr)) Then
        objActiveRange.InsertAfter vbTab & rgstrRcpntFaxNames(0) & vbTab
    Else
        'insert appropriate field
        objActiveRange.InsertAfter vbTab
        objActiveRange.Collapse wdCollapseEnd
        If ((iNumRcpnts > 1) Or (fDocIsFormLtr)) Then
            InsertField objActiveRange, wdFieldMergeField, strMFFirstName, True
            If Len(strMFLastName) Then
                objActiveRange.InsertAfter strSPACE
                objActiveRange.Collapse wdCollapseEnd
                InsertField objActiveRange, wdFieldMergeField, strMFLastName, True
            End If
        Else
            InsertField objActiveRange, wdFieldMacroButton, strEMPTY_MACRO & strCLICK_HERE_NAME, False
        End If
        objActiveRange.InsertAfter vbTab
    End If
    
    objActiveRange.Collapse wdCollapseEnd
    
    'Insert From:
    objActiveRange.InsertBefore strFROM
    Set objRngBuffer2 = objActiveRange.Duplicate
    
    'insert sender's name
    strName = formWizard.txtSenderName.Text
    If Len(strName) Then
        objActiveRange.InsertAfter vbTab & strName & vbCr
    Else
        objActiveRange.InsertAfter vbTab
        objActiveRange.Collapse wdCollapseEnd
        'insert macrobutton field.
        InsertField objActiveRange, wdFieldMacroButton, strEMPTY_MACRO & strCLICK_HERE_NAME, False
        objActiveRange.InsertParagraphAfter
    End If
    objActiveRange.Collapse wdCollapseEnd
    'set character style for topics
    objRngBuffer1.Style = strSTY_MSG_HDR_LABEL
…