Problem whit VBA macros works in Office365 - vba

I faced with problem how macros works after start using Office365. In general macros should fill WORD template tags and bookmarks from txt data file. The problem is somtimes same data from data file doesn't past into template and there isn't any logics. It may be first,last, middele records of table. And more over most of times macros fill all data correctly. In Office2013/2016 all work properly.
Is there any ideas about this?
Macros code
Option Explicit
Type t_Ar
Col() As String
End Type
Dim isAutoOpen As String, _
WITHOUT_OLE As String, _
USE_JAR As String, _
UseUnicode As String, fs, f
Private Function GetFullPath(FullName As String) As String
Dim NameParts, Res As String, i As Integer
NameParts = Split(FullName, Application.PathSeparator)
Res = NameParts(0)
For i = 1 To UBound(NameParts) - 1
Res = Res + Application.PathSeparator + NameParts(i)
Next
GetFullPath = Res
End Function
Sub AutoOpen()
Dim FileNameData As String, FullPathMacros As String, ParsName, Cnt As Integer, _
AppMacros As Application, DocMacros As Document
'Stop
isAutoOpen = "X"
Set AppMacros = Application
Set DocMacros = AppMacros.ActiveDocument
'Mac косячит, вместо Path возвращает FullName
' FullPathMacros = Application.ActiveDocument.Path
FullPathMacros = GetFullPath(DocMacros.FullName)
ParsName = Split(DocMacros.Name, "_")
Cnt = UBound(ParsName)
If Cnt = 3 Then
If ParsName(0) = "ZWWW" And ParsName(1) = "MACROS" And ParsName(2) = "WORD" Then
If AppMacros.Documents.Count > 1 Then
' AppMacros.ActiveWindow.Visible = False
Else
AppMacros.Visible = False
End If
ParsName = Split(ParsName(3), ".")
FileNameData = FullPathMacros + AppMacros.PathSeparator + "ZWWW_DATA_" + ParsName(0) + ".txt"
FillVariables FileNameData, DocMacros
If WITHOUT_OLE = "X" Then
If AppMacros.Documents.Count > 1 Then
DocMacros.Close
Else
AppMacros.Quit
End If
End If
End If
End If
isAutoOpen = ""
End Sub
Private Function isFileUnicode(NameFileData As String) As Boolean
Dim b1 As Byte, b2 As Byte
isFileUnicode = False
On Error Resume Next
Open NameFileData For Random Access Read As #5 Len = 1
Get #5, 1, b1
Get #5, 2, b2
Close #5
If b1 = 0 Or b2 = 0 Then
isFileUnicode = True
End If
End Function
Private Sub OpenFileData(FileData As String)
Dim CodePageTxt As Integer
If UseUnicode <> "X" Then
Open FileData For Input As #1
Else
CodePageTxt = -2
If UseUnicode = "X" Then
CodePageTxt = -1
End If
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.OpenTextFile(FileData, 1, 0, CodePageTxt)
End If
End Sub
Private Sub CloseFileData()
If UseUnicode <> "X" Then
Close #1
Else
f.Close
End If
End Sub
Private Function isEndOfFileData() As Boolean
If UseUnicode <> "X" Then
isEndOfFileData = EOF(1)
Else
isEndOfFileData = f.AtEndOfStream
End If
End Function
Private Function ReadLineData() As String
Dim Ln As String
If UseUnicode <> "X" Then
Line Input #1, Ln
Else
Ln = f.ReadLine
End If
ReadLineData = Ln
End Function
Sub MakeFullDir(FullName As String)
Dim ArrName, NewDir As String, Cnt As Integer
ArrName = Split(FullName, Application.PathSeparator)
On Error Resume Next
Err.Clear
Cnt = 0
Do While Cnt < UBound(ArrName)
If NewDir = "" Then
NewDir = ArrName(Cnt)
Else
NewDir = NewDir + Application.PathSeparator + ArrName(Cnt)
End If
Err.Clear
ChDir NewDir
If Err.Number <> 0 Then
Err.Clear
MkDir NewDir
End If
Cnt = Cnt + 1
Loop
End Sub
Public Sub FillVariables(ByVal FileData As String, ByVal DocTempl) ' As Document
UserFormProgress.UserFormProgressShow FileData, DocTempl
End Sub
Public Sub ZWWW_FillVariables(ByVal FileData As String, ByVal DocTempl) ' As Document
Dim fs, f, _
Ln As String, r As Range, Ofs As Range, _
Ar() As t_Ar, i As Long, Cnt As Long, _
value, CurrRange As Range, _
RowsCount As Long, _
MACROSNAME, ErrNumber, VarError, _
Doc As Document, _
RangeStart, RangeEnd, RangeSize, _
NewStart, NewEnd, NewSize, _
RangeTempl, b As Bookmark, Dupl As Range, Fd As Find, _
CheckSpel, CheckGram, PasteAdjTblFormat As Boolean
' FileData As String
' QTable As QueryTable,
Dim Param, _
ProgressStep As Long, _
Psw As String, _
ResDialogPrint, _
TEMP_NAME As String, _
FILE_NAME As String, _
FILE_PATH As String, _
FULL_NAME As String, _
MACROS_NAME As String, _
DEBUG_MODE As String, _
CLOSE_FORM As String, _
PRINTDIALOG As String, _
PROTECT_WB As String, _
StartTime As Date, _
CurrentTime As Date
StartTime = Time * 100000
CurrentTime = StartTime
If isFileUnicode(FileData) Then
UseUnicode = "X"
Else
UseUnicode = ""
End If
RowsCount = 1
ErrNumber = 0
With Application
Set Doc = .ActiveDocument
.DisplayAlerts = wdAlertsNone
.ScreenUpdating = False
End With
With Options
CheckSpel = .CheckSpellingAsYouType
CheckGram = .CheckGrammarAsYouType
.CheckSpellingAsYouType = False
.CheckGrammarAsYouType = False
End With
OpenFileData FileData
Ln = ReadLineData()
Cnt = Ln
Do While Not isEndOfFileData() And Cnt > 0
Cnt = Cnt - 1
Ln = ReadLineData()
Param = Split(Ln, Chr(9))
If UBound(Param) = 1 Then
Select Case Param(0)
Case "TEMP_NAME"
TEMP_NAME = Param(1)
FULL_NAME = GetFullPath(Application.ActiveDocument.FullName) + Application.PathSeparator + TEMP_NAME
FULL_NAME = Replace(FULL_NAME, "\", Application.PathSeparator)
FULL_NAME = Replace(FULL_NAME, "/", Application.PathSeparator)
Case "FILE_NAME"
FILE_NAME = Param(1)
Case "FILE_PATH"
FILE_PATH = Param(1)
FILE_PATH = Replace(FILE_PATH, "\", Application.PathSeparator)
FILE_PATH = Replace(FILE_PATH, "/", Application.PathSeparator)
Case "WITHOUT_OLE"
WITHOUT_OLE = Param(1)
On Error Resume Next
Open Application.ActiveDocument.Path + Application.PathSeparator + Application.ActiveDocument.Name + ".err" For Input As #2
If Err.Number = 0 Then
WITHOUT_OLE = "X"
Close #2
Else
Err.Clear
End If
On Error GoTo 0
Case "USE_JAR"
USE_JAR = Param(1)
Case "MACROSNAME"
MACROS_NAME = Param(1)
Case "DEBUG_MODE"
DEBUG_MODE = Param(1)
Case "CLOSE_FORM"
CLOSE_FORM = Param(1)
Case "PRINTDIALOG"
PRINTDIALOG = Param(1)
Case "PROTECT"
PROTECT_WB = Param(1)
End Select
End If
Loop
If DEBUG_MODE = "X" Then
Application.Visible = True
Stop
End If
If isAutoOpen = "X" And WITHOUT_OLE = "" Then
CloseFileData
Exit Sub
End If
If (WITHOUT_OLE = "X" Or USE_JAR = "X") And FULL_NAME <> "" Then
' Dim App As New Word.Application
Dim App As Word.Application
If Left(UCase(Application.System.OperatingSystem), 7) = "WINDOWS" Then
Set App = New Application
Else
Set App = Application
End If
App.Documents.Open FULL_NAME
Set DocTempl = App.ActiveDocument
'сбросить Режим чтения в Word 2013,
'т.к. не заполняются колонтитулы
If DocTempl.ActiveWindow.View.ReadingLayout = True Then
'недостаточно сбросить Режим чтения,
'т.к. 2013 переводит в режим Черновик
DocTempl.ActiveWindow.View.Type = wdPrintView
End If
Else
Set App = DocTempl.Application
End If
DocTempl.Activate
Set Doc = App.ActiveDocument
PasteAdjTblFormat = App.Options.PasteAdjustTableFormatting
App.Options.PasteAdjustTableFormatting = False
If DEBUG_MODE = "X" Then
App.Visible = True
App.ScreenUpdating = True
Else
App.ScreenUpdating = False
App.DisplayAlerts = wdAlertsNone
End If
Cnt = 0
i = 0
Do While Not isEndOfFileData()
i = i + 1 'f.Line
Ln = ReadLineData()
ReDim Preserve Ar(1 To i) As t_Ar
Ar(i).Col = Split(Ln, Chr(9), 6, vbBinaryCompare)
Loop
CloseFileData
ProgressStep = UBound(Ar, 1) / 10
If ProgressStep > 50 Then
ProgressStep = 50
End If
If ProgressStep < 1 Then
ProgressStep = 1
End If
Err.Clear
ErrNumber = 0
Set r = Doc.Range
VarError = 0
i = 0
Do While Not i >= UBound(Ar, 1)
i = i + 1
App.ScreenUpdating = True
If DEBUG_MODE = "X" Then
App.ScreenUpdating = True
Else
App.ScreenUpdating = False
End If
'If i Mod ProgressStep = 0 Then
CurrentTime = Time * 100000 - StartTime
If CurrentTime > 1 Then
CurrentTime = Time * 100000
StartTime = CurrentTime
Dim ScrUpd As String
If DEBUG_MODE = "X" Then
ScrUpd = ", ScreenUpdating = "
If App.ScreenUpdating Then
ScrUpd = ScrUpd + "true"
Else
ScrUpd = ScrUpd + "false"
End If
End If
ProgressBar i, UBound(Ar, 1), FULL_NAME + ScrUpd
End If
With Ar(i)
' VarName = .Col(0)
' VarNum = .Col(1)
' FindText = .Col(2)
' Value = .Col(5)
' ErrNumber = 0
On Error Resume Next
If .Col(0) = "" Then
Set r = Doc.Range
ErrNumber = Err.Number
Else
If .Col(0) <> "*" Then
'At new VarName
Set b = Doc.Bookmarks(.Col(0))
Set r = b.Range
Set CurrRange = r.Duplicate
ErrNumber = Err.Number
If ErrNumber = 0 Then
r.Copy
'RowsCount = r.Rows.Count
RangeStart = r.Start
RangeEnd = r.End
RangeSize = RangeEnd - RangeStart
Doc.UndoClear
End If
If DEBUG_MODE = "X" Then
b.Select
r.Select
CurrRange.Select
End If
End If
If ErrNumber = 0 Then
If .Col(1) <> "*" Then
'At new VarNum
If .Col(1) <> 0 Then
r.Move 10, 1 'RowsCount
If DEBUG_MODE = "X" Then
r.Select
End If
If .Col(3) = "V" Then
Err.Clear
Set RangeTempl = Doc.Bookmarks(.Col(5)).Range
VarError = Err.Number
If DEBUG_MODE = "X" Then
RangeTempl.Select
End If
If VarError = 0 Then
NewStart = RangeTempl.Start
NewEnd = RangeTempl.End
RangeTempl.Copy
r.PasteAndFormat wdListCombineWithExistingList '(wdFormatOriginalFormatting)
NewSize = NewEnd - NewStart
NewStart = r.Start
NewEnd = NewStart + NewSize
r.End = NewEnd
If DEBUG_MODE = "X" Then
r.Select
End If
End If
Else
Set RangeTempl = CurrRange 'b.Range
RangeTempl.Copy
r.PasteAndFormat wdListCombineWithExistingList '(wdFormatOriginalFormatting)
b.Start = CurrRange.Start
b.End = CurrRange.End
NewStart = r.Start
NewEnd = NewStart + RangeSize
r.End = NewEnd
If DEBUG_MODE = "X" Then
r.Select
End If
End If
End If
Doc.UndoClear
End If
End If
End If
If ErrNumber = 0 Then
If .Col(2) = "" Then
If .Col(3) = "" Or .Col(3) = "S" Then
If DEBUG_MODE = "X" Then
r.Select
End If
r.Text = .Col(5)
ElseIf .Col(3) = "M" Then
Err.Clear
Set Dupl = r.Duplicate
If DEBUG_MODE = "X" Then
Dupl.Select
End If
'MacrosName = "'" + ActiveWorkbook.Name + "'" + "!" + .Col(5)
'MACROSNAME = .Col(5)
'App.Run MACROSNAME, Dupl
'If Err.Number <> 0 Then
' App.Run MACROSNAME
'End If
RunUserMacros App, .Col(5), Dupl
End If
Else
If .Col(3) = "S" Then
If DEBUG_MODE = "X" Then
r.Select
End If
Set Fd = r.Find
Fd.Execute FindText:=.Col(2), replacewith:=.Col(5), Replace:=wdReplaceAll
End If
End If
End If
End With
Err.Clear
Loop
Doc.UndoClear
i = 0
Do While Not i >= UBound(Ar, 1)
i = i + 1
With Ar(i)
If (.Col(0) <> "" And .Col(0) <> "*" And _
Val(.Col(1)) <> 0 And .Col(1) <> "*") Then
Err.Clear
Set b = Doc.Bookmarks(.Col(0))
If Err.Number = 0 Then
Set r = b.Range
If DEBUG_MODE = "X" Then
r.Select
End If
r.Delete
Set r = b.Range
If Err.Number = 0 Then
If DEBUG_MODE = "X" Then
r.Select
End If
r.Cells.Delete
End If
End If
End If
If .Col(3) = "V" Then
Err.Clear
Set b = Doc.Bookmarks(.Col(5))
If Err.Number = 0 Then
Set r = b.Range
If DEBUG_MODE = "X" Then
r.Select
End If
r.Delete
Set r = b.Range
If Err.Number = 0 Then
If DEBUG_MODE = "X" Then
r.Select
End If
r.Cells.Delete
End If
End If
ElseIf .Col(3) = "D" Then
Err.Clear
Set b = Doc.Bookmarks(.Col(0))
If Err.Number = 0 Then
Set r = b.Range
If DEBUG_MODE = "X" Then
r.Select
End If
r.Delete
Set r = b.Range
If Err.Number = 0 Then
If DEBUG_MODE = "X" Then
r.Select
End If
r.Cells.Delete
End If
End If
End If
End With
Loop
Doc.UndoClear
With App
.ScreenUpdating = True
.DisplayAlerts = wdAlertsAll
End With
With Options
.CheckSpellingAsYouType = CheckSpel
.CheckGrammarAsYouType = CheckGram
.PasteAdjustTableFormatting = PasteAdjTblFormat
End With
If WITHOUT_OLE = "X" Or USE_JAR = "X" Then
If PROTECT_WB = "X" Then
Err.Clear
Psw = Time
Doc.Protect Type:=3, noreset:=False, Password:=Psw
If Err.Number <> 0 Then
Err.Clear
Doc.Protect Type:=1, noreset:=False, Password:=Psw
End If
End If
Dim New_FULL_NAME As String, ErrSave, Saved_as_PDF As Boolean
New_FULL_NAME = FILE_PATH + FILE_NAME
If UCase(FULL_NAME) <> UCase(New_FULL_NAME) And FILE_NAME <> "" Then 'New_FULL_NAME <> ""
MakeFullDir New_FULL_NAME
If File_as_PDF(New_FULL_NAME) Then
Doc.Save
ErrSave = Save_as_PDF(Doc, New_FULL_NAME)
If ErrSave = 0 Then
Saved_as_PDF = True
End If
Else
Err.Clear
Doc.SaveAs FileName:=New_FULL_NAME
ErrSave = Err.Number
If ErrSave <> 0 Then
Doc.Save
End If
End If
Else
Doc.Save
End If
App.DisplayAlerts = True
App.ScreenUpdating = True
If CLOSE_FORM <> "X" Then
If Not Saved_as_PDF Then
With App
.DisplayAlerts = True
.ScreenUpdating = True
.Visible = True
End With
Else
Open_as_PDF New_FULL_NAME
End If
End If
If PRINTDIALOG = "X" Then
If Not Saved_as_PDF Then
ResDialogPrint = App.Dialogs.Item(wdDialogFilePrint).Show
End If
End If
If CLOSE_FORM = "X" Or _
PRINTDIALOG = "X" Or _
Saved_as_PDF Then
App.Quit
End If
End If
End Sub
Sub RunUserMacros(App, Val, Rng)
Dim MACROSNAME As String, Param1 As String, it_Params, Cnt As Integer
it_Params = Split(Val, Chr(9), 2, vbBinaryCompare)
Cnt = UBound(it_Params)
On Error Resume Next
Err.Clear
If Cnt >= 1 Then
MACROSNAME = it_Params(0)
Param1 = it_Params(1)
App.Run MACROSNAME, Rng, Param1
If Err.Number <> 0 Then
App.Run MACROSNAME, Param1
End If
Else
MACROSNAME = Val
App.Run MACROSNAME, Rng
If Err.Number <> 0 Then
App.Run MACROSNAME
End If
End If
Err.Clear
End Sub
Sub ProgressBar(LenPart, LenAll, Txt)
UserFormProgress.LabelText.Caption = Txt
UserFormProgress.LabelProgress.Width = (LenPart / LenAll) * UserFormProgress.FrameProgress.Width
' UserFormProgress.Show
UserFormProgress.Repaint
DoEvents
End Sub

Related

Need to slightly tweak this code...need it to find exact match and I'm out of my league

Public Function FindCodes(keywords As Range, text As String)
'FindCodes = "TEST"
Dim codeRows As Collection
Dim codeString As String
Set codeRows = New Collection
'Find Codes
For Each Item In keywords
Dim keywordArr() As String
Dim i As Integer
i = 0
If Item.Row <> 1 Then 'Ignore first row
keywordArr() = Split(Item, ",")
'On Error Resume Next
On Error GoTo ErrHandler
For Each s In keywordArr()
If InStr(LCase(text), LCase(s)) <> 0 Then
codeRows.Add Item.Row, CStr(Item.Row)
End If
Next s
End If
Next Item
'Build Codes String
If codeRows.Count > 0 Then
Dim codeArr() As String
'Set codeArr = New Collection
'Dim i As Integer
'i = 0
ReDim codeArr(codeRows.Count)
For Each s In codeRows
'codeArr.Add s, CStr(Worksheets("Codes").Range("A" & s).Value)
codeArr(i) = Worksheets("Codes").Range("A" & s).Value
'Set i = Worksheets("Codes").Range("B" + s).Value
i = i + 1
Next s
End If
'FindCodes = Join(codeArr, ",")
If UBound(codeArr) > 1 Then
FindCodes = Join(codeArr, ",")
ElseIf UBound(codeArr) = 1 Then
FindCodes = codeArr(0)
Else
FindCodes = ""
End If
ErrHandler:
If Err.Number = 457 Or Err.Number = 0 Or Err.Number = 20 Then
'foo = someDefaultValue
Resume Next
Else
'Err.Raise Err.Number
FindCodes = CVErr(xlErrValue)
End If
End Function
Sub temp()
Dim r As Range
Set r = Worksheets("Codes").Range("B:B")
MsgBox FindCodes(r, ".")
End Sub
Your code seems over-complex, but maybe I'm misunderstanding what it's supposed to do.
Try this:
Public Function FindCodes(keywords As Range, text As String)
Dim c As Range, keywordArr, s, rv
'only look at used cells
Set keywords = Application.Intersect(keywords, keywords.Worksheet.UsedRange)
For Each c In keywords.Cells
If c.Row > 1 And Len(c.Value) > 0 Then 'Ignore first row and empty cells
keywordArr = Split(c.Value, ",")
For Each s In keywordArr
If LCase(Trim(s)) = LCase(Trim(text)) Then
'grab value from ColA and go to next cell
rv = rv & IIf(Len(rv) = 0, "", ",") & c.EntireRow.Cells(1).Value
Exit For
End If
Next s
End If
Next c
FindCodes = rv
End Function

SlideShowWindows error (integer out of range)

I'm preparing a quiz using on PowerPoint using the controllers of VBA scripts. My aim to set multiple questions, each has 4 choices.
I've set everything, when trying to run (starting with the method: "BeginQuiz") it's interrupted by the following error:
SlideShowWindows (unknown number) Integer out of range
My code is below:
Const NOOFQS = 4
'Used to manipulated the unicode values of bulleted lists
Const UD_CODE_1 = 111
Const UD_CODE_2 = 8226
Public QNo As Integer
Public ExitFlag As Boolean
Public Qs() As String
Public Choices() As String
Public Ans() As Integer
Public UserAns() As Integer
Sub NextSlide()
' Store the ans for later
'UserAns(QNo - 1) = 1
If QNo < NOOFQS Then
QNo = QNo + 1
SlideShowWindows(1).Presentation.Slides("QSlide").Shapes(1).TextFrame.TextRange.Text = Qs(QNo - 1)
AssignValues
Else
Call StopQuiz
End If
DoEvents
End Sub
Sub PreviousSlide()
Static X As Integer
If QNo > 1 Then
QNo = QNo - 1
AssignValues
End If
End Sub
Sub StopQuiz(Optional EndType As Boolean = False)
' EndType is used as a boolean Flag to indicate whether the user ran out of time
' or whether it was normal exit
Dim ScoreCard As Integer
Dim Ctr As Integer
ExitFlag = True
With SlideShowWindows(1)
For Ctr = 0 To NOOFQS - 1
If Ans(Ctr) = UserAns(Ctr) Then ScoreCard = ScoreCard + 1
Next Ctr
If EndType = False Then
.Presentation.Slides("EndSlide").Shapes("Closing").TextFrame.TextRange.Text = "Your score is : " & ScoreCard & " correct out of " & NOOFQS
Else
.Presentation.Slides("EndSlide").Shapes("Closing").TextFrame.TextRange.Text = "Sorry!!! Either you ran out of time or you chickened out" _
& vbCrLf & "Better luck next time." & vbCrLf _
& "Your score is: " & ScoreCard & " correct out of " & NOOFQS
End If
.View.GotoSlide (.Presentation.Slides("EndSlide").SlideIndex)
End With
End Sub
Sub StopIt()
Call StopQuiz(True)
End Sub
Sub BeginQuiz()
Dim Ctr As Integer
ReDim Qs(NOOFQS)
ReDim Ans(NOOFQS)
ReDim UserAns(NOOFQS)
ReDim Choices(NOOFQS, 4)
' All the questions
Qs(0) = "1) ãä Ãæá ãä ÝÊÍ ÇáÞÏÓ ÈÚÏ ÚãÑ¿"
Qs(1) = "2) ãä åí Ãæá ãä ÃÓáãÊ ãä ÇáäÓÇÁ¿"
Qs(2) = "3) ãÇ åí ÇáãäØÞÉ ÇáÊí ÍÑÑåÇ ãÍãÏ ÇáÝÇÊÍ¿"
Qs(3) = "4) ãÇ åæ Ãæá ãÓÌÏ Ýí ÇáÅÓáÇã¿"
' Set all user answers to negative
For Ctr = 0 To NOOFQS - 1
UserAns(Ctr) = -1
Next Ctr
' All the choices 3 each for a question
Choices(0, 0) = " ÕáÇÍ ÇáÏíä ÇáÃíæÈí"
Choices(0, 1) = " ÇáÞÇÆÏ ÇáãÙÝÑ"
Choices(0, 2) = " ÎÇáÏ Èä ÇáæáíÏ"
Choices(0, 3) = " ÇáÙÇåÑ ÈíÈÑÓ"
Choices(1, 0) = " ÃÓãÇÁ ÈäÊ ÃÈí ÈßÑ "
Choices(1, 1) = " ÓæÏÉ ÈäÊ ÒãÚÉ "
Choices(1, 2) = " ÎÏíÌÉ ÈäÊ ÎæíáÏ "
Choices(1, 3) = " Ãã ÚãÇÑ Èä íÇÓÑ "
Choices(2, 0) = " ØáíØáÉ "
Choices(2, 1) = " ÇáÞÇÏÓíÉ "
Choices(2, 2) = " ÇáÞÓØäØíäíÉ "
Choices(2, 3) = " ÇáÃäÏáÓ"
Choices(3, 0) = " ãÓÌÏ ÞÈÇÁ"
Choices(3, 1) = " ãÓÌÏ Ðí ÇáäæÑíä"
Choices(3, 2) = " ÇáãÓÌÏ ÇáäÈæí"
Choices(3, 3) = " ÇáÈíÊ ÇáÍÑÇã"
' Provide the answer list here.
' Ans(0) = 0 means that the correct answer to the 1st question is the 1st choice.
' Ans(1) = 1 means that the correct answer to the 2nd question is the 2nd choice.
' Ans(2) = 1 means that the correct answer to the 3rd question is the 2nd choice.
Ans(0) = 0
Ans(1) = 2
Ans(2) = 2
Ans(3) = 0
QNo = 1
AssignValues
With SlideShowWindows(1)
.View.GotoSlide (.Presentation.Slides("QSlide").SlideIndex)
End With
' Comment the line below to stop the timer.
Call Tmr
End Sub
Sub SetBulletUnicode(ShapeName As String, Code As Integer)
With SlideShowWindows(1).Presentation.Slides("QSlide").Shapes(ShapeName).TextFrame.TextRange.ParagraphFormat.Bullet
.UseTextFont = msoTrue
.Character = Code
End With
End Sub
Sub ButtonChoice1()
UserAns(QNo - 1) = 0
AssignValues
End Sub
Sub ButtonChoice2()
UserAns(QNo - 1) = 1
AssignValues
End Sub
Sub ButtonChoice3()
UserAns(QNo - 1) = 2
AssignValues
End Sub
Sub Tmr()
'Just in the eventuality that you click the start button twice
'isRunning stores the current state of the macro
'TRUE = Running; FALSE = Idle
ExitFlag = False
Static isRunning As Boolean
If isRunning = True Then
End
Else
isRunning = True
Dim TMinus As Integer
Dim xtime As Date
xtime = Now
With ActivePresentation.Slides(2).Shapes("Timer")
'Countdown in seconds
TMinus = 59
Do While (TMinus > -1)
DoEvents
' Rather crude way to determine if a second has elapsed
If ExitFlag = True Then
.TextFrame.TextRange.Text = "00:00:00"
isRunning = False
Exit Sub
End If
If Format(Now, "ss") <> Format(xtime, "ss") Then
xtime = Now
.TextFrame.TextRange.Text = Format(TimeValue(Format(Now, "hh:mm:ss")) - _
TimeSerial(Hour(Now), Minute(Now), Second(Now) + TMinus), "hh:mm:ss")
TMinus = TMinus - 1
' Let the display refresh itself
End If
Loop
End With
Debug.Print "came here"
isRunning = False
StopQuiz True
End
End If
End Sub
Sub AssignValues()
SetBulletUnicode "Choice1", UD_CODE_1
SetBulletUnicode "Choice2", UD_CODE_1
SetBulletUnicode "Choice3", UD_CODE_1
SetBulletUnicode "Choice4", UD_CODE_1
Select Case UserAns(QNo - 1)
Case 0
SetBulletUnicode "Choice1", UD_CODE_2
Case 1
SetBulletUnicode "Choice2", UD_CODE_2
Case 2
SetBulletUnicode "Choice3", UD_CODE_2
Case 3
SetBulletUnicode "Choice4", UD_CODE_2
End Select
With SlideShowWindows(1).Presentation.Slides("QSlide")
.Shapes(1).TextFrame.TextRange.Text = Qs(QNo - 1)
.Shapes("Choice1").TextFrame.TextRange.Text = Choices(QNo - 1, 0)
.Shapes("Choice2").TextFrame.TextRange.Text = Choices(QNo - 1, 1)
.Shapes("Choice3").TextFrame.TextRange.Text = Choices(QNo - 1, 2)
.Shapes("Choice4").TextFrame.TextRange.Text = Choices(QNo - 1, 3)
End With
End Sub
Sub ShowAnswers()
Dim AnsList As String
AnsList = "The answers are as follows:" & vbCrLf
For X = 0 To NOOFQS - 1
AnsList = AnsList & Qs(X) & vbTab & " Answer:" & Choices(X, Ans(X)) & vbCrLf
Next X
MsgBox AnsList, vbOKOnly, "Correct answers"
End Sub

VBA loop for label names

I have a Word table containing Legacy DropDown List. There is 11 rows and let's say 4 columns. Each cell contains a Legacy DropDown List which puts the count to 11 per column (44 total).
I have to take the data from these Legacy DropDown List and put it into Labels in another table on another page of the same document.
No problem so far, I made it work though I had to do write it all down instead of using a loop because I couldn't find a way to put a variable in my label name.
I shortened my code to only the first row of the first week (therefore 4 labels) because otherwise it would have been too long and there is no need for it to be that way.
Current code :
Sub Week1()
'Week 1
If ActiveDocument.FormFields("Dom1").DropDown.ListEntries.Count <> 0 And ActiveDocument.FormFields("Dom1").DropDown.ListEntries.Item(ActiveDocument.FormFields("Dom1").DropDown.Value).Name <> "Choose a DOM." Then
lblDom1W1.Caption = ActiveDocument.FormFields("Dom1").DropDown.ListEntries.Item(ActiveDocument.FormFields("Dom1").DropDown.Value).Name
End If
If ActiveDocument.FormFields("Sit1").DropDown.ListEntries.Count <> 0 Then
If ActiveDocument.FormFields("Sit1").DropDown.Value <> 0 Then
If ActiveDocument.FormFields("Sit1").DropDown.ListEntries.Item(ActiveDocument.FormFields("Sit1").DropDown.Value).Name <> "Choose a SIT" Then
lblSit1W1.Caption = ActiveDocument.FormFields("Sit1").DropDown.ListEntries.Item(ActiveDocument.FormFields("Sit1").DropDown.Value).Name
End If
End If
End If
If ActiveDocument.FormFields("Int1").DropDown.ListEntries.Count <> 0 Then
If ActiveDocument.FormFields("Int1").DropDown.Value <> 0 Then
lblInt1W1.Caption = ActiveDocument.FormFields("Int1").DropDown.ListEntries.Item(ActiveDocument.FormFields("Int1").DropDown.Value).Name
End If
End If
If ActiveDocument.FormFields("Gram1").DropDown.ListEntries.Count <> 0 And ActiveDocument.FormFields("Gram1").DropDown.ListEntries.Item(ActiveDocument.FormFields("Gram1").DropDown.Value).Name <> "Choose a GRAM." Then
lblGram1W1.Caption = ActiveDocument.FormFields("Gram1").DropDown.ListEntries.Item(ActiveDocument.FormFields("Gram1").DropDown.Value).Name
End If
So this works. That being said, I would like to loop it so I could have this much code only once instead of having it repeated 11 times per week for 11 weeks.
I already named the labels for them to be easy with a loop. Therefore, their names are all lblDom1W1 down to lblDom11W1 for the first week and so on for the other labels (only the last digit changes ( e.i. lblDom1W2 down to lblDom11W2)).
Furthermore, I thought and tried these methods which I thought wouldn't work and didn't :
labelName & value
labelName(value)
I looked through this post but I didn't quite understood everything in it and I'm not sure if that's what I need since it's VB.NET and no exactly VBA. Post I checked
EDIT:
Following user R3uK comment, I tried this but it doesn't work either. I gives me the Invalid qualifier for my leLabelDom.Caption...:
Sub Week1()
'Week1
Dim labelDom As String
labelDom = "lblDom"
Dim week1 As String
week1 = "W1"
Dim leLabelDom As String
For k = 1 To 11
leLabelDom = labelDom & k & week1
If ActiveDocument.FormFields("ListeDomaine" & k).DropDown.ListEntries.Count <> 0 And ActiveDocument.FormFields("ListeDomaine" & k).DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeDomaine" & k).DropDown.Value).Name <> "Choisissez un domaine." Then
leLabelDom.Caption = ActiveDocument.FormFields("ListeDomaine" & k).DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeDomaine" & k).DropDown.Value).Name
End If
EDIT 2 - Working:
Started from the user R3uK answer and end up with this code which works. Huge thanks to you R3uK !
Sub Remplir()
Dim leLabelDom As String, _
wDocD As Word.Document, _
IsHd As InlineShape, _
leLabelSit As String, _
leLabelInt As String, _
leLabelGram As String, _
semaine As String
Set wDoc = ActiveDocument
If ActiveDocument.FormFields("ListeSemaine").DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeSemaine").DropDown.Value).Name = "Semaine 1" Then
semaine = "S1"
lblMaterielS1.Caption = TextBoxMateriel.Text
lblEvaluationS1.Caption = TextBoxEvaluation.Text
End If
If ActiveDocument.FormFields("ListeSemaine").DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeSemaine").DropDown.Value).Name = "Semaine 2" Then
semaine = "S2"
lblMaterielS2.Caption = TextBoxMateriel.Text
lblEvaluationS2.Caption = TextBoxEvaluation.Text
End If
If ActiveDocument.FormFields("ListeSemaine").DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeSemaine").DropDown.Value).Name = "Semaine 3" Then
semaine = "S3"
lblMaterielS3.Caption = TextBoxMateriel.Text
lblEvaluationS3.Caption = TextBoxEvaluation.Text
End If
If ActiveDocument.FormFields("ListeSemaine").DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeSemaine").DropDown.Value).Name = "Semaine 4" Then
semaine = "S4"
lblMaterielS4.Caption = TextBoxMateriel.Text
lblEvaluationS4.Caption = TextBoxEvaluation.Text
End If
If ActiveDocument.FormFields("ListeSemaine").DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeSemaine").DropDown.Value).Name = "Semaine 5" Then
semaine = "S5"
lblMaterielS5.Caption = TextBoxMateriel.Text
lblEvaluationS5.Caption = TextBoxEvaluation.Text
End If
If ActiveDocument.FormFields("ListeSemaine").DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeSemaine").DropDown.Value).Name = "Semaine 6" Then
semaine = "S6"
lblMaterielS6.Caption = TextBoxMateriel.Text
lblEvaluationS6.Caption = TextBoxEvaluation.Text
End If
If ActiveDocument.FormFields("ListeSemaine").DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeSemaine").DropDown.Value).Name = "Semaine 7" Then
semaine = "S7"
lblMaterielS7.Caption = TextBoxMateriel.Text
lblEvaluationS7.Caption = TextBoxEvaluation.Text
End If
If ActiveDocument.FormFields("ListeSemaine").DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeSemaine").DropDown.Value).Name = "Semaine 8" Then
semaine = "S8"
lblMaterielS8.Caption = TextBoxMateriel.Text
lblEvaluationS8.Caption = TextBoxEvaluation.Text
End If
If ActiveDocument.FormFields("ListeSemaine").DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeSemaine").DropDown.Value).Name = "Semaine 9" Then
semaine = "S9"
lblMaterielS9.Caption = TextBoxMateriel.Text
lblEvaluationS9.Caption = TextBoxEvaluation.Text
End If
If ActiveDocument.FormFields("ListeSemaine").DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeSemaine").DropDown.Value).Name = "Semaine 10" Then
semaine = "S10"
lblMaterielS10.Caption = TextBoxMateriel.Text
lblEvaluationS10.Caption = TextBoxEvaluation.Text
End If
If ActiveDocument.FormFields("ListeSemaine").DropDown.ListEntries.Item(ActiveDocument.FormFields("ListeSemaine").DropDown.Value).Name = "Semaine 11" Then
semaine = "S11"
lblMaterielS11.Caption = TextBoxMateriel.Text
lblEvaluationS11.Caption = TextBoxEvaluation.Text
End If
For k = 1 To 11
leLabelDom = "lblDomaine" & k & semaine
leLabelSit = "lblSituation" & k & semaine
leLabelInt = "lblIntention" & k & semaine
leLabelGram = "lblGrammaire" & k & semaine
If wDoc.FormFields("ListeDomaine" & k).DropDown.ListEntries.Count <> 0 And _
wDoc.FormFields("ListeDomaine" & k).DropDown.ListEntries.Item(wDoc.FormFields("ListeDomaine" & k).DropDown.Value).Name <> "Choisissez un domaine." _
Then
If wDoc.InlineShapes.Count <> 0 Then
For Each IsH In wDoc.InlineShapes
If IsH.Type = wdInlineShapeOLEControlObject Then
If TypeName(IsH.OLEFormat.Object) = "Label" Then
If IsH.OLEFormat.Object.Name = leLabelDom Then
IsH.OLEFormat.Object.Caption = wDoc.FormFields("ListeDomaine" & k).DropDown.ListEntries.Item(wDoc.FormFields("ListeDomaine" & k).DropDown.Value).Name
End If
End If
End If
Next
End If
End If
If wDoc.FormFields("ListeSituation" & k).DropDown.ListEntries.Count <> 0 _
Then
If wDoc.FormFields("ListeSituation" & k).DropDown.Value <> 0 _
Then
If wDoc.FormFields("ListeSituation" & k).DropDown.ListEntries.Item(wDoc.FormFields("ListeSituation" & k).DropDown.Value).Name <> "Choisissez une situation" _
Then
If wDoc.InlineShapes.Count <> 0 Then
For Each IsH In wDoc.InlineShapes
If IsH.Type = wdInlineShapeOLEControlObject Then
If TypeName(IsH.OLEFormat.Object) = "Label" Then
If IsH.OLEFormat.Object.Name = leLabelSit Then
IsH.OLEFormat.Object.Caption = wDoc.FormFields("ListeSituation" & k).DropDown.ListEntries.Item(wDoc.FormFields("ListeSituation" & k).DropDown.Value).Name
End If
End If
End If
Next
End If
End If
End If
End If
If wDoc.FormFields("ListeIntention" & k).DropDown.ListEntries.Count <> 0 And _
wDoc.FormFields("ListeIntention" & k).DropDown.Value <> 0 _
Then
If wDoc.InlineShapes.Count <> 0 Then
For Each IsH In wDoc.InlineShapes
If IsH.Type = wdInlineShapeOLEControlObject Then
If TypeName(IsH.OLEFormat.Object) = "Label" Then
If IsH.OLEFormat.Object.Name = leLabelInt Then
IsH.OLEFormat.Object.Caption = wDoc.FormFields("ListeIntention" & k).DropDown.ListEntries.Item(wDoc.FormFields("ListeIntention" & k).DropDown.Value).Name
End If
End If
End If
Next
End If
End If
If wDoc.FormFields("ListeGrammaire" & k).DropDown.ListEntries.Count <> 0 And _
wDoc.FormFields("ListeGrammaire" & k).DropDown.ListEntries.Item(wDoc.FormFields("ListeGrammaire" & k).DropDown.Value).Name <> "Choisissez un niveau." _
Then
If wDoc.InlineShapes.Count <> 0 Then
For Each IsH In wDoc.InlineShapes
If IsH.Type = wdInlineShapeOLEControlObject Then
If TypeName(IsH.OLEFormat.Object) = "Label" Then
If IsH.OLEFormat.Object.Name = leLabelGram Then
IsH.OLEFormat.Object.Caption = wDoc.FormFields("ListeGrammaire" & k).DropDown.ListEntries.Item(wDoc.FormFields("ListeGrammaire" & k).DropDown.Value).Name
End If
End If
End If
Next
End If
End If
Next k
Set wDoc = Nothing
End Sub
In your edit, you try to use a property for a String, but Properties are only for Object variables.
So, you need to find where are stored the controls, in InlineShapes and then loop and filter it to narrow it down to your specific control and change its value.
Here is something that should work or at least is probably close (can't test it) :
Sub OuO()
Dim leLabelDom As String, _
wDoc As Word.Document, _
wListE As DropDown, _
IsH As InlineShape
Set wDoc = wDoc
For k = 1 To 11
leLabelDom = "lblDom" & k & "W1"
Set wListE = wDoc.FormFields("ListeDomaine" & k).DropDown
If wListE.ListEntries.Count <> 0 And _
wListE.ListEntries.Item(wListE.Value).Name <> "Choisissez un domaine." _
Then
If wDoc.InlineShapes.Count <> 0 Then
For Each IsH In wDoc.InlineShapes
If IsH.Type <> wdInlineShapeOLEControlObject Then
Else
'filter on name
With IsH.OLEFormat.Object
If .Name <> leLabelDom Then
Else
.Caption = wListE.ListEntries.Item(wListE.Value).Name
End If
End With
End If
Next IsH
Else
End If
Else
End If
Next k
Set wDoc = Nothing
Set wListE = Nothing
End Sub

Do Until loop in VBA does not break on Exit Sub

I wrote the following code in order to ask for an input.
validInput = False
Do
str = InputBox("Some text...")
If str = vbNullString Then
MsgBox ("Input canceled")
Exit Sub
Else
If IsNumeric(str) Then
exchange = CCur(str)
validInput = True
Else
MsgBox ("Input invalid.")
End If
End If
Loop Until validInput
However, if I cancel my input it keeps asking me for an input and the loop goes on even though I added the Exit Sub line.
I tried to add validInput = True before Exit Sub but that didn't work either.
What am I missing?
EDIT:
Here is the whole sub.
Public Sub CurrencyCheck()
Dim ws As Worksheet
Set ws = ActiveWorkbook.Worksheets("Datenbank")
Dim lastRow As Long
lastRow = ws.Cells(Rows.Count, 4).End(xlUp).Row
Dim i As Long
Dim j As Long
Dim curSymbol As String
Dim exchange As Currency
Dim str As String
Dim curArr() As String
Dim arrCnt As Integer
arrCnt = 1
Dim curInArr As Boolean
curInArr = False
Dim curIndex As Integer
Dim validInput As Boolean
ReDim curArr(1 To 2, 1 To arrCnt)
For i = 1 To lastRow
If ws.Cells(i, 4).Value <> "Price" And ws.Cells(i, 4).Value <> "" Then
curSymbol = Get_Currency(ws.Cells(i, 4).text) 'Function that returns currency symbol (€) or abbreviation (EUR)
If curSymbol <> "€" Then
For j = LBound(curArr, 2) To UBound(curArr, 2)
If curArr(1, j) = curSymbol Then
curInArr = True
curIndex = j
End If
Next j
If Not curInArr Then
If curSymbol = "EUR" Then
ReDim Preserve curArr(1 To 2, 1 To arrCnt)
curArr(1, arrCnt) = curSymbol
curArr(2, arrCnt) = 1
curIndex = arrCnt
arrCnt = arrCnt + 1
Else
validInput = False
Do Until validInput
str = InputBox("Some text...")
If str = vbNullString Then
MsgBox ("Input canceled.")
Exit Sub
Else
If IsNumeric(str) Then
exchange = CCur(str)
validInput = True
Else
MsgBox ("Input invalid.")
End If
End If
Loop
ReDim Preserve curArr(1 To 2, 1 To arrCnt)
curArr(1, arrCnt) = curSymbol
curArr(2, arrCnt) = exchange
curIndex = arrCnt
arrCnt = arrCnt + 1
End If
End If
ws.Cells(i, 4).Value = StringToCurrency(ws.Cells(i, 4).text)
ws.Cells(i, 4).Value = ws.Cells(i, 4).Value * curArr(2, curIndex)
ws.Cells(i, 4).NumberFormat = "#,##0.00 €"
End If
End If
Next i
End Sub
EDIT2: When I run the input loop as a subroutine by itself it works. The macro is run in another workbook and doing that it fails...
EDIT3: My bad. The problem is not related to the code but to the positioning of the subroutine. It was called of and over again because it was called in a loop. I have to apologize. Thanks to everyone.
This will loop until a numeric is entered:
Sub dural()
Dim validInput As Boolean
Dim strg As String, x As Variant
validInput = False
Do
strg = Application.InputBox(Prompt:="enter value", Type:=2)
If strg = "False" Then
ElseIf IsNumeric(strg) Then
x = CCur(strg)
validInput = True
End If
Loop Until validInput
End Sub
EDIT#1:
This version will quit the loop if the user touches the CANCEL button or the red x button:
Sub dural()
Dim validInput As Boolean
Dim strg As String, x As Variant
validInput = False
Do
strg = Application.InputBox(Prompt:="enter value", Type:=2)
If strg = "False" Or strg = "" Then
validInput = True
ElseIf IsNumeric(strg) Then
x = CCur(strg)
validInput = True
End If
Loop Until validInput
End Sub
I don't think is a null string. Try this
If str = vbNullString or str = "" Then

how to check OS system date format using excel vba

I am using excel 2007, ms visual basic 6.0.
I required to check the window os date format (e.g, whether is it using d/m/yyyy or m/d/yyyy), in order to using the following code.
Dim lastdateofmonth As Date
Dim lastwhichday As String
slastdayofmonth = "31"
'if the OS system is using m/d/yyyy then use this
lastdateofmonth = (sTxtMMM + "/" + slastdayofmonth + "/" + TxtYYYY)
lastwhichday = Weekday(lastdateofmonth)
'if th OS system is using d/m/yyyy then use this
lastdateofmonth = (slastdayofmonth+ "/" + sTxtMMM + "/" + TxtYYYY)
anyone can help? Thanks in advance
hmm... i found a better way
'========== Check OS Date format========
Dim OSDateFormatType As Integer
' 0 = month-day-year; 1 = day-month-year; 2 = year-month-day
If Application.International(xlDateOrder) = 0 Then
OSDateFormatType = 0
ElseIf Application.International(xlDateOrder) = 1 Then
OSDateFormatType = 1
ElseIf Application.International(xlDateOrder) = 2 Then
OSDateFormatType = 2
End If
But this only work for excel.
Check below code....
Sub getSystemDateFormat()
Application.AskToUpdateLinks = False
Application.DisplayAlerts = False
If isSheetExists(ThisWorkbook, "Temp") = False Then
ThisWorkbook.Sheets.Add After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)
ThisWorkbook.ActiveSheet.Name = "Temp"
End If
ThisWorkbook.Sheets("Temp").Cells(1, 1) = ""
'On Error GoTo ErrHandle
'Get Date format
lngDateFormat = Application.International(xlDateOrder)
'Get Date Separator
strDateSeparator = Application.International(xlDateSeparator)
'Get leading 0 for day
If Application.International(xlDayLeadingZero) Then
strDayFormat = "dd"
Else
strDayFormat = "d"
End If
'Get leading 0 for month
If Application.International(xlMonthLeadingZero) Then
strMonthFormat = "mm"
Else
strMonthFormat = "m"
End If
'Get 4 digit/2 digit format for year
If Application.International(xl4DigitYears) Then
strYearFormat = "yyyy"
Else
strYearFormat = "yy"
End If
'Consolidate the values
If lngDateFormat = 0 Then ' Month-Day-Year
lngPos1 = InStr(1, Now(), strDateSeparator)
If lngPos1 = 4 Then
strMonthFormat = "mmm"
End If
strDateFormat = strMonthFormat & strDateSeparator & strDayFormat & strDateSeparator & strYearFormat
ElseIf lngDateFormat = 1 Then ' Day-Month-Year
lngPos1 = InStr(1, Now(), strDateSeparator)
lngPos2 = InStr(lngPos1 + 1, Now(), strDateSeparator)
If lngPos2 - lngPos1 = 4 Then
strMonthFormat = "mmm"
End If
strDateFormat = strDayFormat & strDateSeparator & strMonthFormat & strDateSeparator & strYearFormat
Else ' Year-Month-Day
lngPos1 = InStr(1, Now(), strDateSeparator)
lngPos2 = InStr(lngPos1 + 1, Now(), strDateSeparator)
If lngPos2 - lngPos1 = 4 Then
strMonthFormat = "mmm"
End If
strDateFormat = strYearFormat & strDateSeparator & strMonthFormat & strDateSeparator & strDayFormat
End If
MsgBox strDateFormat
EndLine:
ThisWorkbook.Sheets("Temp").Activate
ThisWorkbook.Sheets("Temp").Cells(1, 1) = strDateFormat
Exit Sub
ErrHandle:
If Err.Description <> "" Then
ThisWorkbook.Sheets("Temp").Cells(1, 1) = Err.Description
End If
ThisWorkbook.Sheets("Temp").Activate
End Sub
Function isSheetExists(wbk As Workbook, strSheetName As String) As Boolean
isSheetExists = False
For i = 1 To wbk.Sheets.Count
If wbk.Sheets(i).Name = strSheetName Then
isSheetExists = True
Exit For
End If
Next i
End Function
The best way:
if Application.International(xlMDY) then ...
True - month, day, year
False - day, month, year
https://msdn.microsoft.com/en-us/library/office/ff840213%28v=office.15%29.aspx