Thursday, January 16, 2025

VBA Word - Process all Word documents of a folder, Delete specific lines

The following VBA code processes all Word documents of a folder one by one. It deletes specific lines which contain some specific texts.
Option Explicit

Sub ProcessFiles()
    Dim FSO As Object
    Dim objFldr As Object
    Dim objFyle As Object
    Dim strFileExtension As String
    Dim appWord As Object
    Dim doc As Object
    
    ' Initialize FileSystemObject
    Set FSO = CreateObject("Scripting.FileSystemObject")
    Set objFldr = GetFolder()
    
    If objFldr Is Nothing Then Exit Sub ' Exit if no folder is selected

    ' Initialize Word Application
    Set appWord = CreateObject("Word.Application")
    appWord.Visible = True
    
    ' Process each file in the selected folder
    For Each objFyle In objFldr.Files
        strFileExtension = FSO.GetExtensionName(objFyle.Path)
        If LCase(strFileExtension) = "docx" Or LCase(strFileExtension) = "doc" Then
            ' Open the Word document
            Set doc = appWord.Documents.Open(objFyle.Path)
            doc.Activate
            
            ' Apply table style
            Call TableGridDesignMacro
            
            ' Delete specified lines
            Call DeleteLineBeforeAndContainingCopyCode(doc, "You said:")
            Call DeleteLineBeforeAndContainingCopyCode(doc, "Copy code")
            Call DeleteLineBeforeAndContainingCopyCode(doc, "ChatGPT")
            
            ' Save and close the document
            doc.Save
            doc.Close SaveChanges:=True
            Set doc = Nothing
        End If
    Next
    
    ' Quit Word Application
    appWord.Quit
    Set appWord = Nothing
    Set FSO = Nothing
End Sub

Sub DeleteLineBeforeAndContainingCopyCode(doc As Object, strText As String)
    Dim findRange As Range
    Dim deleteRange As Range

    ' Start from the end of the document
    Set findRange = doc.Content
    findRange.Start = findRange.End
    
    ' Search for the text and delete lines
    Do While findRange.Find.Execute(FindText:=strText, Forward:=False, Wrap:=wdFindStop)
        ' Create a range for the current line
        Set deleteRange = findRange.Paragraphs(1).Range
        
        ' Include the line above if it exists
        If deleteRange.Start > doc.Content.Start Then
            deleteRange.Start = deleteRange.Paragraphs(1).Previous.Range.Start
        End If
        
        ' Delete the range
        deleteRange.Delete
    Loop
End Sub

Function GetFolder() As Object
    Dim FSO As Object
    Dim strFolderPath As String
    Dim objFldr As Object

    ' Create a FileSystemObject
    Set FSO = CreateObject("Scripting.FileSystemObject")
    
    ' Use FileDialog to let the user select a folder
    With Application.FileDialog(msoFileDialogFolderPicker)
        .AllowMultiSelect = False
        .Show
        If .SelectedItems.Count <> 1 Then Exit Function ' Exit if no folder is selected
        strFolderPath = .SelectedItems.Item(1)
    End With
    
    ' Get the selected folder
    Set objFldr = FSO.GetFolder(strFolderPath)
    
    ' Check if the folder contains files
    If objFldr.Files.Count < 1 Then
        MsgBox "No files found in the selected folder.", vbInformation
        Exit Function
    End If
    
    ' Return the folder object
    Set GetFolder = objFldr
    Set FSO = Nothing
End Function

Sub TableGridDesignMacro()
    Dim tbl As Table
    ' Apply "Table Grid" style to all tables in the document
    For Each tbl In ActiveDocument.Tables
        tbl.Style = "Table Grid"
    Next
End Sub

Saturday, December 28, 2024

C# Delegate Revisited

In C#, delegate is a reference type used to encapsulate method with a specific signature and return type. You can encapsulate any matching method in an object of the delegate. A delegate is instanciated similar to class using new operator. We pass a method reference in its constructor. Delegate object can be used to run the method at runtime.

Look at the following example: int x; x=20;
We declare a int type variable and initialize with integer type value.
Same analogy can be drawn w.r.t. delegate.We define a delegate and then declare a variable of delegate type. The variable can be initialized later with relevant value(i.e. the value matching the data type). 

We define a delegate using delegate keyword, (similar to class) which is followed by a return type of method and then method signature (Instead of {}which is followed by class name).
public delegate DelegateName ReturnType Method-Signature
Then delegate reference variable can be declared as follows:
DelegateName refVariableForDelegate;
The delegate reference variable can be initialized with a method reference. A method reference is just the name of a defined method.

Now, We understand the above points by an example.

Suppose, we have the following Operations class with Math related methods in it.
internal class Operations
{
    public static double Sum(double number1, double number2)
    {
        return number1 + number2;
    }
    public static double Product(double number1, double number2)
    {
        return number1 * number2;
    }
}
We observe that Sum and Product have same method signatures. Also, their return type is same i.e. double.

We can define a delegate for these methods which can be as follows:
public delegate double MathFunction(double number1, double number2);
In above delegate definition, note the following points:
  • MathFunction is the name of delegate.
  • The delegate is public in scope.
  • The double is the return type of the delegate.
  • The (double number1, double number2) implies that the delegate can refer to any method of two parameters which are of double type and return type is double.
  • At this moment, when MathFunction delegate is declared, we cannot say what responsibility will be dispatched to MathFunction delegate; actual behavior will be decided when it will be initialized.
Delegate vs Interface: Note that in a sense, abstract method is given when delegate is defined. It is similar to interface but there are differences between interface and delegate. 
  • A class cannot have multiple implementation of interface method but a class can have multiple implementation of delegate method. 
  • A class cannot implement method of interface dynamically but delegate methods can be dynamically implemented.
Delegate Reference Variable & its Initialization: We have just defined delegate as reference type. Now we can declare a reference variable of this delegate type. For example, MathFunction action; This statement will be declaration of delegate reference variable, action. (Look at the analogy of int x;). The delegate reference variable is still not initialized. We need a method to initialize this delegate reference variable. We will see it ahead. This will be encapsulation of method of class inside delegate. So, you can say that method encapsulation takes place when a delegate is initialized or you can say that method encapsulation is core objective of delegate. We will see it in forthcoming paragraphs.

Looking the previous example, MathFunction delegate can be delegated the task to execute the Sum and Product methods because both methods signatures and return type matches with the defined delegate. Note that a delegate can be passed the reference of static or not static method. To pass the reference of non-static method, we must first instantiate the class of the method. To pass the reference of static method, we directly use the class name of the method. 

The delegate type should not be static. Using static keyword with a delegate during its defintion is illegal. So, you cannot define the delegate as follows:
public static delegate double MathFunction(double number1, double number2);
Note that delegate is a type and can be defined independently, not necessarily inside Operations class. The Operations class or any other class can consume the defined delegate.

Different ways to initialize Delegates
Now, we see different ways to initialize a delegate (more appropriately, delegate reference variable).
  1. By using new operator
  2. Without using new operator, just by using method name
  3. Anonymous method
  4. Lambda Expression
These are four common ways to initialize a delegate. Now, we see it the context of MathFunction.
Let, MathFunction is referenced using action delegate reference variable:
MathFunction action;
Now, action can be initialized in following ways:
  1. action = new MathFunction(Operations.Sum);
  2. action = Operations.Sum;
  3. action = delegate(double x, double y) { return x + y; }
  4. action = (x,y)=>x+y;
Consuming Delegate:
A delegate can be consumed by a class in different ways:
  1. Delegate as field of class
  2. Delegate as property of class
  3. Delegate as parameter of method of class etc.
Example1. Delegate as field of class:
Suppose that there are two classes Class1 and Class2 which have some methods. Let, some of these methods can be encapsulated using a delegate. Now, as a developer, you can create delegate reference variable in Client class and pass the method reference to the delegate variable when you need to invoke any encapsulated method. But another design pattern can be to create delegate reference variable in each class - Class1 and Class2. These classes will use the delegate themselves and the Client class be relived from the burden of delegate initialization. Look at the following code, I have used Arithmetic and Calculus for Class1 and Class2 respectively:
namespace CSharp_Delegates.Example2;
public delegate int MyDelegate(int x, int y);
internal class DelegateAsField
{
    public static void Test()
    {
        Arithmetic arithmetic = new Arithmetic();
        Calculus calculus = new Calculus();
        Console.WriteLine("Sum:{0}",arithmetic.GetSum(20, 330));
        Console.WriteLine("Product:{0}",arithmetic.GetProduct(20, 30));
        Console.WriteLine("Multiply:{0}",calculus.GetMultiply(12, 12));
        Console.WriteLine("Divide:{0}",calculus.GetDivide(12, 4));
    }

}
class Arithmetic
{
    MyDelegate? _delegate;
    public int GetSum(int number1, int number2)
    {
        _delegate = this.Sum;
        return _delegate(number1, number2);
    }
    public int GetProduct(int number1, int number2)
    {
        _delegate = this.Product;
        return _delegate(number1, number2);
    }
    private int Sum(int x, int y)
    {
        return x + y;
    }
    private int Product(int x, int y)
    {
        return x * y;
    }
}

class Calculus
{
    MyDelegate? _delegate;
    public int GetDivide(int number1, int number2)
    {
        _delegate = this.Divide;
        return _delegate(number1, number2);
    }
    public int GetMultiply(int number1, int number2)
    {
        _delegate = this.Multiply;
        return _delegate(number1, number2);
    }
    private int Divide(int x, int y)
    {
        if (y!=0)
        {
            return x / y;
        }
        throw new DivideByZeroException("Zero denominator not allowed");
    }
    private int Multiply(int x, int y)
    {
        return x * y;
    }
}
Example2. Delegate as property of class:
Look at the following code. It is the same code as Example1 but delegate field is replaced by delegate property. Fields are usually private but properties are public in C#. It is on you to decide how you want to use delegate in consuming class.
namespace CSharp_Delegates.Example3;

public delegate int MyDelegate(int x, int y);
internal class DelegateAsProperty
{
    public static void Test()
    {
        Arithmetic arithmetic = new Arithmetic();
        Calculus calculus = new Calculus();
        Console.WriteLine("Sum:{0}", arithmetic.GetSum(120, 330));
        Console.WriteLine("Product:{0}", arithmetic.GetProduct(5, 30));
        Console.WriteLine("Multiply:{0}", calculus.GetMultiply(13, 13));
        Console.WriteLine("Divide:{0}", calculus.GetDivide(12, 6));
    }
}
class Arithmetic
{
    public MyDelegate? _delegate { get; set; }
    public int GetSum(int number1, int number2)
    {
        _delegate = this.Sum;
        return _delegate(number1, number2);
    }
    public int GetProduct(int number1, int number2)
    {
        _delegate = this.Product;
        return _delegate(number1, number2);
    }
    private int Sum(int x, int y)
    {
        return x + y;
    }
    private int Product(int x, int y)
    {
        return x * y;
    }
}
class Calculus
{
    public MyDelegate? _delegate{ get; set; }
    public int GetDivide(int number1, int number2)
    {
        _delegate = this.Divide;
        return _delegate(number1, number2);
    }
    public int GetMultiply(int number1, int number2)
    {
        _delegate = this.Multiply;
        return _delegate(number1, number2);
    }
    private int Divide(int x, int y)
    {
        if (y != 0)
        {
            return x / y;
        }
        throw new DivideByZeroException("Zero denominator not allowed");
    }
    private int Multiply(int x, int y)
    {
        return x * y;
    }
}
Example3. Delegate as parameter of method:
Passing delegate as parameter is very common application. Delegate can be used as callback. Look at the following simple code in which method is passed parameter of delegate type:
namespace CSharp_Delegates.Example1;
public delegate double MathFunction(double number1, double number2);
internal class Operations
{
    public static double Sum(double number1, double number2)
    {
        return number1 + number2;
    }
    public static double Product(double number1, double number2)
    {
        return number1 * number2;
    }
}
public class Client
{
    public static void DoMath()
    {
        DoSomeMath(Operations.Sum);
        DoSomeMath(Operations.Product);
    }
    public static void DoSomeMath(MathFunction action)
    {
        if (action != null)
        {
            double result = action.Invoke(2.0, 1.1);
            Console.WriteLine(result.ToString());
        }
    }
}
In the above code, Client class uses MathFunction delegate as parameter of DoSomeMath method. When this method is called inside DoMath method then, delegate reference variable, action, is passed the method reference (e.g. Operations.Sum).

Till now, what we learnt?
  • The delegate in itself does not tell what it can do. The developer has the responsibility to decide what action/functionality to perform with delegate. 
  • Delegate is just a reference type with method reference. Looking at delegate defintion, we can have idea what type of data will be passed as parameters to the method and what type of data will be returned but actual data can be observed only at runtime.
  • Delegate is initialized by associating/referencing it with some method at compile time.
  • When delegate is initialized then at runtime its associated/referenced method is invoked.
  • Delegate initialization is all about method encapsulation. It is similar to data encapsulation which occurs when a class is initialized.
Additional Notes:
A delegate can be defined inside a class also. It is not necessary that a delegate must be defined inside namespace as separate independent type.

This is first part of the article. It will be continued for other topics such as
  1. Array of delegates
  2. Delegate and Interface
  3. Delegate and Event
  4. Delegate with Generics
  5. Multicast
  6. Delegate and Callback
  7. Delegate and Asynchronous Task














Hot Topics