Pages

Sunday, July 19, 2026

Replicate the local db

 In this article, we will discuss about replicate the local db






BacpacReplicaService.cs

-------------------------------------

using Microsoft.SqlServer.Dac;


namespace QaLocalDbReplica;


public sealed class BacpacReplicaService

{

    public event EventHandler<string>? StatusChanged;

    public event EventHandler<int>? ProgressChanged;


    public async Task<string> CreateReplicaAsync(

        ReplicaRequest request,

        CancellationToken cancellationToken)

    {

        ValidateRequest(request);


        await LocalDbService.EnsureLocalDbAvailableAsync(cancellationToken);


        string tempDirectory = Path.Combine(

            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),

            "QaLocalDbReplica",

            "Bacpac");


        Directory.CreateDirectory(tempDirectory);


        string bacpacPath = Path.Combine(

            tempDirectory,

            $"{SanitizeFileName(request.SourceDatabase)}_{DateTime.Now:yyyyMMdd_HHmmss}.bacpac");


        string sourceConnectionString =

            ConnectionStringFactory.BuildSource(

                request.SourceServer,

                request.SourceDatabase,

                request.UseWindowsAuthentication,

                request.UserName,

                request.Password);


        try

        {

            ReportStatus("Exporting the selected QA database to BACPAC...");

            ReportProgress(0);


            await Task.Run(

                () => ExportBacpac(

                    sourceConnectionString,

                    request.SourceDatabase,

                    bacpacPath,

                    cancellationToken),

                cancellationToken);


            ReportProgress(50);


            bool exists = await LocalDbService.DatabaseExistsAsync(

                request.DestinationDatabase,

                cancellationToken);


            if (exists && !request.ReplaceExistingDestination)

            {

                throw new InvalidOperationException(

                    $"LocalDB database '{request.DestinationDatabase}' already exists.");

            }


            if (exists)

            {

                ReportStatus(

                    $"Removing existing LocalDB database '{request.DestinationDatabase}'...");


                await LocalDbService.DropDatabaseIfExistsAsync(

                    request.DestinationDatabase,

                    cancellationToken);

            }


            ReportStatus("Importing BACPAC into LocalDB...");


            await Task.Run(

                () => ImportBacpac(

                    request.DestinationDatabase,

                    bacpacPath,

                    cancellationToken),

                cancellationToken);


            ReportProgress(100);

            ReportStatus(

                $"Replica '{request.DestinationDatabase}' was created successfully.");


            return bacpacPath;

        }

        finally

        {

            if (request.DeleteTemporaryBacpac)

            {

                TryDeleteFile(bacpacPath);

            }

        }

    }


    private void ExportBacpac(

        string sourceConnectionString,

        string sourceDatabase,

        string bacpacPath,

        CancellationToken cancellationToken)

    {

        if (File.Exists(bacpacPath))

            File.Delete(bacpacPath);


        // Try to fix permissions issue proactively

        TryFixAzureSqlPermissions(sourceConnectionString);


        var services = new DacServices(sourceConnectionString);


        services.Message += (_, e) =>

            ReportStatus($"Export: {e.Message.Message}");


        services.ProgressChanged += (_, e) =>

        {

            int mapped = Math.Clamp((int)e.Status / 2, 0, 50);

            ReportProgress(mapped);


            if (!string.IsNullOrWhiteSpace(e.Message))

                ReportStatus($"Export: {e.Message}");

        };


        var options = new DacExportOptions

        {

            CommandTimeout = 0,

            VerifyExtraction = false,

            Storage = DacSchemaModelStorageType.Memory

        };


        services.ExportBacpac(

            bacpacPath,

            sourceDatabase,

            options,

            tables: null,

            cancellationToken);

    }


    private void TryFixAzureSqlPermissions(string connectionString)

    {

        try

        {

            using var connection = new Microsoft.Data.SqlClient.SqlConnection(connectionString);

            connection.Open();


            ReportStatus("Checking database compatibility settings...");


            // Try to revoke the problematic CONNECT permission from guest user

            try

            {

                string fixSql = "REVOKE CONNECT FROM guest;";

                using var command = new Microsoft.Data.SqlClient.SqlCommand(fixSql, connection);

                command.CommandTimeout = 10;

                command.ExecuteNonQuery();

                ReportStatus("Revoked CONNECT permission from guest user.");

            }

            catch (Exception ex)

            {

                ReportStatus($"Could not revoke guest CONNECT permission: {ex.Message}");

            }

        }

        catch (Exception ex)

        {

            ReportStatus($"Warning: Permission check failed: {ex.Message}");

        }

    }


    private void ImportBacpac(

        string destinationDatabase,

        string bacpacPath,

        CancellationToken cancellationToken)

    {

        var services =

            new DacServices(ConnectionStringFactory.BuildLocalMaster());


        services.Message += (_, e) =>

            ReportStatus($"Import: {e.Message.Message}");


        services.ProgressChanged += (_, e) =>

        {

            int mapped = 50 + Math.Clamp((int)e.Status / 2, 0, 50);

            ReportProgress(mapped);


            if (!string.IsNullOrWhiteSpace(e.Message))

                ReportStatus($"Import: {e.Message}");

        };


        using BacPackage package = BacPackage.Load(bacpacPath);


        var options = new DacImportOptions

        {

            CommandTimeout = 0

        };


        services.ImportBacpac(

            package,

            destinationDatabase,

            options,

            cancellationToken);

    }


    private static void ValidateRequest(ReplicaRequest request)

    {

        if (string.IsNullOrWhiteSpace(request.SourceServer))

            throw new ArgumentException("Source server is required.");


        if (string.IsNullOrWhiteSpace(request.SourceDatabase))

            throw new ArgumentException("Source database is required.");


        LocalDbService.ValidateDatabaseName(request.DestinationDatabase);


        if (!request.UseWindowsAuthentication)

        {

            if (string.IsNullOrWhiteSpace(request.UserName))

                throw new ArgumentException("SQL username is required.");


            if (string.IsNullOrWhiteSpace(request.Password))

                throw new ArgumentException("SQL password is required.");

        }

    }


    private static string SanitizeFileName(string value)

    {

        foreach (char invalid in Path.GetInvalidFileNameChars())

            value = value.Replace(invalid, '_');


        return value;

    }


    private static void TryDeleteFile(string path)

    {

        try

        {

            if (File.Exists(path))

                File.Delete(path);

        }

        catch

        {

            // Cleanup failure should not hide the real export/import result.

        }

    }


    private void ReportStatus(string message) =>

        StatusChanged?.Invoke(this, message);


    private void ReportProgress(int percentage) =>

        ProgressChanged?.Invoke(this, Math.Clamp(percentage, 0, 100));

}




-----------------------------------------------------------------------------

ConnectionStringFactory.cs
------------------------------------
using Microsoft.Data.SqlClient;

namespace QaLocalDbReplica;

public static class ConnectionStringFactory
{
    public const string LocalDbInstance = @"(localdb)\MSSQLLocalDB";

    public static string BuildSource(
        string server,
        string database,
        bool windowsAuthentication,
        string? userName,
        string? password)
    {
        var builder = new SqlConnectionStringBuilder
        {
            DataSource = server.Trim(),
            InitialCatalog = database,
            IntegratedSecurity = windowsAuthentication,
            Encrypt = false,
            TrustServerCertificate = true,
            ConnectTimeout = 30,
            ApplicationName = "QA LocalDB Replica"
        };

        if (!windowsAuthentication)
        {
            builder.UserID = userName?.Trim() ?? string.Empty;
            builder.Password = password ?? string.Empty;
        }

        return builder.ConnectionString;
    }

    public static string BuildSourceMaster(
        string server,
        bool windowsAuthentication,
        string? userName,
        string? password) =>
        BuildSource(server, "master", windowsAuthentication, userName, password);

    public static string BuildLocalMaster()
    {
        return new SqlConnectionStringBuilder
        {
            DataSource = LocalDbInstance,
            InitialCatalog = "master",
            IntegratedSecurity = true,
            Encrypt = false,
            TrustServerCertificate = true,
            ConnectTimeout = 30,
            ApplicationName = "QA LocalDB Replica"
        }.ConnectionString;
    }

    public static string BuildLocalDatabase(string database)
    {
        return new SqlConnectionStringBuilder
        {
            DataSource = LocalDbInstance,
            InitialCatalog = database,
            IntegratedSecurity = true,
            Encrypt = false,
            TrustServerCertificate = true,
            ConnectTimeout = 30,
            ApplicationName = "QA LocalDB Re.csplica"
        }.ConnectionString;
    }
}


-------------------------------------------------------------------------------------------

DatabaseListItem.cs
---------------------------------
namespace QaLocalDbReplica;

public sealed class DatabaseListItem
{
    public string Name { get; init; } = string.Empty;

    public override string ToString() => Name;
}


----------------------------------------------------------------------------------------------------
LocalDbService.cs
----------------------------
using Microsoft.Data.SqlClient;
using System.Text.RegularExpressions;

namespace QaLocalDbReplica;

public static class LocalDbService
{
    private static readonly Regex ValidDatabaseName =
        new(@"^[A-Za-z0-9_]+$", RegexOptions.Compiled);

    public static void ValidateDatabaseName(string databaseName)
    {
        if (string.IsNullOrWhiteSpace(databaseName))
            throw new ArgumentException("Destination database name is required.");

        if (!ValidDatabaseName.IsMatch(databaseName))
        {
            throw new ArgumentException(
                "Destination database name can contain only letters, numbers, and underscore.");
        }
    }

    public static async Task EnsureLocalDbAvailableAsync(
        CancellationToken cancellationToken)
    {
        await using var connection =
            new SqlConnection(ConnectionStringFactory.BuildLocalMaster());

        await connection.OpenAsync(cancellationToken);

        await using var command =
            new SqlCommand("SELECT CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(50));", connection);

        _ = await command.ExecuteScalarAsync(cancellationToken);
    }

    public static async Task<bool> DatabaseExistsAsync(
        string databaseName,
        CancellationToken cancellationToken)
    {
        await using var connection =
            new SqlConnection(ConnectionStringFactory.BuildLocalMaster());

        await connection.OpenAsync(cancellationToken);

        await using var command =
            new SqlCommand("SELECT CASE WHEN DB_ID(@name) IS NULL THEN 0 ELSE 1 END;", connection);

        command.Parameters.AddWithValue("@name", databaseName);

        return Convert.ToInt32(
            await command.ExecuteScalarAsync(cancellationToken)) == 1;
    }

    public static async Task DropDatabaseIfExistsAsync(
        string databaseName,
        CancellationToken cancellationToken)
    {
        ValidateDatabaseName(databaseName);

        string quotedName = QuoteIdentifier(databaseName);

        string sql = $"""
IF DB_ID(@databaseName) IS NOT NULL
BEGIN
    ALTER DATABASE {quotedName}
        SET SINGLE_USER
        WITH ROLLBACK IMMEDIATE;

    DROP DATABASE {quotedName};
END;
""";

        await using var connection =
            new SqlConnection(ConnectionStringFactory.BuildLocalMaster());

        await connection.OpenAsync(cancellationToken);

        await using var command = new SqlCommand(sql, connection)
        {
            CommandTimeout = 0
        };

        command.Parameters.AddWithValue("@databaseName", databaseName);

        await command.ExecuteNonQueryAsync(cancellationToken);
    }

    private static string QuoteIdentifier(string value) =>
        "[" + value.Replace("]", "]]") + "]";
}



----------------------------------------------------------------------------------------------------
MainForm.cs
-------------------------
namespace QaLocalDbReplica;

public partial class MainForm : Form
{
    private CancellationTokenSource? _operationCancellation;

    public MainForm()
    {
        InitializeComponent();

        cmbAuthentication.SelectedIndex = 0;
        txtDestinationDatabase.Text = "QA_Local";
        UpdateAuthenticationControls();
    }

    private async void btnLoadDatabases_Click(object sender, EventArgs e)
    {
        try
        {
            SetBusy(true);
            ClearLog();

            ValidateSourceInput(requireDatabase: false);

            Log("Connecting to source SQL Server...");
            lblStatus.Text = "Loading source databases...";

            using var cancellation = new CancellationTokenSource();

            IReadOnlyList<DatabaseListItem> databases =
                await SourceDatabaseService.GetDatabasesAsync(
                    txtSourceServer.Text.Trim(),
                    UseWindowsAuthentication,
                    txtUserName.Text.Trim(),
                    txtPassword.Text,
                    cancellation.Token);

            cmbSourceDatabase.DataSource = databases.ToList();

            Log($"Loaded {databases.Count} database(s).");
            lblStatus.Text = "Select the QA database.";
        }
        catch (Exception ex)
        {
            ShowError("Unable to load databases", ex);
        }
        finally
        {
            SetBusy(false);
        }
    }

    private async void btnSubmit_Click(object sender, EventArgs e)
    {
        try
        {
            ValidateSourceInput(requireDatabase: true);
            LocalDbService.ValidateDatabaseName(txtDestinationDatabase.Text.Trim());

            SetBusy(true);
            btnCancel.Enabled = true;
            ClearLog();
            progressBar.Value = 0;

            _operationCancellation = new CancellationTokenSource();

            var request = new ReplicaRequest
            {
                SourceServer = txtSourceServer.Text.Trim(),
                SourceDatabase =
                    ((DatabaseListItem)cmbSourceDatabase.SelectedItem!).Name,
                DestinationDatabase = txtDestinationDatabase.Text.Trim(),
                UseWindowsAuthentication = UseWindowsAuthentication,
                UserName = txtUserName.Text.Trim(),
                Password = txtPassword.Text,
                ReplaceExistingDestination = chkReplaceExisting.Checked,
                DeleteTemporaryBacpac = chkDeleteBacpac.Checked
            };

            var service = new BacpacReplicaService();

            service.StatusChanged += (_, message) =>
                SafeUi(() =>
                {
                    lblStatus.Text = message;
                    Log(message);
                });

            service.ProgressChanged += (_, percentage) =>
                SafeUi(() => progressBar.Value = percentage);

            string bacpacPath =
                await service.CreateReplicaAsync(
                    request,
                    _operationCancellation.Token);

            string localConnection =
                ConnectionStringFactory.BuildLocalDatabase(
                    request.DestinationDatabase);

            string message = request.DeleteTemporaryBacpac
                ? $"LocalDB replica '{request.DestinationDatabase}' was created successfully."
                : $"LocalDB replica was created successfully.\n\nBACPAC: {bacpacPath}";

            MessageBox.Show(
                message +
                $"\n\nConnection string:\n{localConnection}",
                "Completed",
                MessageBoxButtons.OK,
                MessageBoxIcon.Information);
        }
        catch (OperationCanceledException)
        {
            lblStatus.Text = "Operation cancelled.";
            Log("Operation cancelled.");
        }
        catch (Exception ex)
        {
            ShowError("Replica creation failed", ex);
        }
        finally
        {
            _operationCancellation?.Dispose();
            _operationCancellation = null;

            btnCancel.Enabled = false;
            SetBusy(false);
        }
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        btnCancel.Enabled = false;
        lblStatus.Text = "Cancellation requested...";
        Log("Cancellation requested...");
        _operationCancellation?.Cancel();
    }

    private void cmbAuthentication_SelectedIndexChanged(
        object sender,
        EventArgs e)
    {
        UpdateAuthenticationControls();
    }

    private bool UseWindowsAuthentication =>
        cmbAuthentication.SelectedIndex == 0;

    private void UpdateAuthenticationControls()
    {
        bool sqlAuthentication = !UseWindowsAuthentication;

        txtUserName.Enabled = sqlAuthentication;
        txtPassword.Enabled = sqlAuthentication;
    }

    private void ValidateSourceInput(bool requireDatabase)
    {
        if (string.IsNullOrWhiteSpace(txtSourceServer.Text))
            throw new InvalidOperationException("Enter the source SQL Server name.");

        if (!UseWindowsAuthentication)
        {
            if (string.IsNullOrWhiteSpace(txtUserName.Text))
                throw new InvalidOperationException("Enter the SQL username.");

            if (string.IsNullOrWhiteSpace(txtPassword.Text))
                throw new InvalidOperationException("Enter the SQL password.");
        }

        if (requireDatabase && cmbSourceDatabase.SelectedItem is null)
            throw new InvalidOperationException("Select the source QA database.");
    }

    private void SetBusy(bool busy)
    {
        btnLoadDatabases.Enabled = !busy;
        btnSubmit.Enabled = !busy;
        txtSourceServer.Enabled = !busy;
        cmbAuthentication.Enabled = !busy;
        cmbSourceDatabase.Enabled = !busy;
        txtDestinationDatabase.Enabled = !busy;
        chkReplaceExisting.Enabled = !busy;
        chkDeleteBacpac.Enabled = !busy;

        if (!busy)
            UpdateAuthenticationControls();
        else
        {
            txtUserName.Enabled = false;
            txtPassword.Enabled = false;
        }

        UseWaitCursor = busy;
    }

    private void Log(string message)
    {
        txtLog.AppendText(
            $"{DateTime.Now:HH:mm:ss}  {message}{Environment.NewLine}");
    }

    private void ClearLog()
    {
        txtLog.Clear();
        lblStatus.Text = "Ready";
        progressBar.Value = 0;
    }

    private void ShowError(string title, Exception exception)
    {
        lblStatus.Text = title;
        Log(exception.ToString());

        MessageBox.Show(
            exception.Message,
            title,
            MessageBoxButtons.OK,
            MessageBoxIcon.Error);
    }

    private void SafeUi(Action action)
    {
        if (IsDisposed)
            return;

        if (InvokeRequired)
            BeginInvoke(action);
        else
            action();
    }
}


-----------------------------------------------------------------------
MainForm.Designer.cs
-------------------------------------
namespace QaLocalDbReplica;

partial class MainForm
{
    private System.ComponentModel.IContainer? components = null;

    private Label lblSourceServer;
    private TextBox txtSourceServer;
    private Label lblAuthentication;
    private ComboBox cmbAuthentication;
    private Label lblUserName;
    private TextBox txtUserName;
    private Label lblPassword;
    private TextBox txtPassword;
    private Button btnLoadDatabases;
    private Label lblSourceDatabase;
    private ComboBox cmbSourceDatabase;
    private Label lblDestinationDatabase;
    private TextBox txtDestinationDatabase;
    private CheckBox chkReplaceExisting;
    private CheckBox chkDeleteBacpac;
    private Button btnSubmit;
    private Button btnCancel;
    private ProgressBar progressBar;
    private Label lblStatus;
    private TextBox txtLog;

    protected override void Dispose(bool disposing)
    {
        if (disposing)
            components?.Dispose();

        base.Dispose(disposing);
    }

    private void InitializeComponent()
    {
        lblSourceServer = new Label();
        txtSourceServer = new TextBox();
        lblAuthentication = new Label();
        cmbAuthentication = new ComboBox();
        lblUserName = new Label();
        txtUserName = new TextBox();
        lblPassword = new Label();
        txtPassword = new TextBox();
        btnLoadDatabases = new Button();
        lblSourceDatabase = new Label();
        cmbSourceDatabase = new ComboBox();
        lblDestinationDatabase = new Label();
        txtDestinationDatabase = new TextBox();
        chkReplaceExisting = new CheckBox();
        chkDeleteBacpac = new CheckBox();
        btnSubmit = new Button();
        btnCancel = new Button();
        progressBar = new ProgressBar();
        lblStatus = new Label();
        txtLog = new TextBox();
        SuspendLayout();

        lblSourceServer.AutoSize = true;
        lblSourceServer.Location = new Point(24, 25);
        lblSourceServer.Text = "Source SQL Server";

        txtSourceServer.Location = new Point(190, 21);
        txtSourceServer.Size = new Size(420, 27);
        txtSourceServer.PlaceholderText = @"Example: QA-SERVER or QA-SERVER\INSTANCE";

        lblAuthentication.AutoSize = true;
        lblAuthentication.Location = new Point(24, 66);
        lblAuthentication.Text = "Authentication";

        cmbAuthentication.DropDownStyle = ComboBoxStyle.DropDownList;
        cmbAuthentication.Items.AddRange(
            ["Windows Authentication", "SQL Server Authentication"]);
        cmbAuthentication.Location = new Point(190, 62);
        cmbAuthentication.Size = new Size(260, 28);
        cmbAuthentication.SelectedIndexChanged +=
            cmbAuthentication_SelectedIndexChanged;

        lblUserName.AutoSize = true;
        lblUserName.Location = new Point(24, 107);
        lblUserName.Text = "SQL username";

        txtUserName.Location = new Point(190, 103);
        txtUserName.Size = new Size(260, 27);

        lblPassword.AutoSize = true;
        lblPassword.Location = new Point(24, 148);
        lblPassword.Text = "SQL password";

        txtPassword.Location = new Point(190, 144);
        txtPassword.Size = new Size(260, 27);
        txtPassword.UseSystemPasswordChar = true;

        btnLoadDatabases.Location = new Point(470, 102);
        btnLoadDatabases.Size = new Size(140, 69);
        btnLoadDatabases.Text = "Load Databases";
        btnLoadDatabases.UseVisualStyleBackColor = true;
        btnLoadDatabases.Click += btnLoadDatabases_Click;

        lblSourceDatabase.AutoSize = true;
        lblSourceDatabase.Location = new Point(24, 192);
        lblSourceDatabase.Text = "Source database";

        cmbSourceDatabase.DropDownStyle = ComboBoxStyle.DropDownList;
        cmbSourceDatabase.Location = new Point(190, 188);
        cmbSourceDatabase.Size = new Size(420, 28);

        lblDestinationDatabase.AutoSize = true;
        lblDestinationDatabase.Location = new Point(24, 233);
        lblDestinationDatabase.Text = "LocalDB database";

        txtDestinationDatabase.Location = new Point(190, 229);
        txtDestinationDatabase.Size = new Size(420, 27);

        chkReplaceExisting.AutoSize = true;
        chkReplaceExisting.Checked = true;
        chkReplaceExisting.CheckState = CheckState.Checked;
        chkReplaceExisting.Location = new Point(190, 273);
        chkReplaceExisting.Text = "Replace destination database when it already exists";

        chkDeleteBacpac.AutoSize = true;
        chkDeleteBacpac.Checked = true;
        chkDeleteBacpac.CheckState = CheckState.Checked;
        chkDeleteBacpac.Location = new Point(190, 307);
        chkDeleteBacpac.Text = "Delete temporary BACPAC after successful/failed operation";

        btnSubmit.Location = new Point(190, 350);
        btnSubmit.Size = new Size(160, 42);
        btnSubmit.Text = "Create Replica";
        btnSubmit.UseVisualStyleBackColor = true;
        btnSubmit.Click += btnSubmit_Click;

        btnCancel.Enabled = false;
        btnCancel.Location = new Point(370, 350);
        btnCancel.Size = new Size(120, 42);
        btnCancel.Text = "Cancel";
        btnCancel.UseVisualStyleBackColor = true;
        btnCancel.Click += btnCancel_Click;

        progressBar.Location = new Point(24, 414);
        progressBar.Size = new Size(586, 25);

        lblStatus.AutoEllipsis = true;
        lblStatus.Location = new Point(24, 450);
        lblStatus.Size = new Size(586, 42);
        lblStatus.Text = "Ready";

        txtLog.Location = new Point(24, 500);
        txtLog.Multiline = true;
        txtLog.ReadOnly = true;
        txtLog.ScrollBars = ScrollBars.Both;
        txtLog.Size = new Size(586, 180);
        txtLog.WordWrap = false;

        AutoScaleDimensions = new SizeF(8F, 20F);
        AutoScaleMode = AutoScaleMode.Font;
        ClientSize = new Size(638, 704);
        Controls.Add(txtLog);
        Controls.Add(lblStatus);
        Controls.Add(progressBar);
        Controls.Add(btnCancel);
        Controls.Add(btnSubmit);
        Controls.Add(chkDeleteBacpac);
        Controls.Add(chkReplaceExisting);
        Controls.Add(txtDestinationDatabase);
        Controls.Add(lblDestinationDatabase);
        Controls.Add(cmbSourceDatabase);
        Controls.Add(lblSourceDatabase);
        Controls.Add(btnLoadDatabases);
        Controls.Add(txtPassword);
        Controls.Add(lblPassword);
        Controls.Add(txtUserName);
        Controls.Add(lblUserName);
        Controls.Add(cmbAuthentication);
        Controls.Add(lblAuthentication);
        Controls.Add(txtSourceServer);
        Controls.Add(lblSourceServer);
        FormBorderStyle = FormBorderStyle.FixedDialog;
        MaximizeBox = false;
        StartPosition = FormStartPosition.CenterScreen;
        Text = "QA to LocalDB Replica";
        ResumeLayout(false);
        PerformLayout();
    }
}


--------------------------------------------------------------------------------------------------------
Program.cs
-----------------------
namespace QaLocalDbReplica
{
    internal static class Program
    {
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // To customize application configuration such as set high DPI settings or default font,
            // see https://aka.ms/applicationconfiguration.
            ApplicationConfiguration.Initialize();
            Application.Run(new MainForm());
        }
    }
}


----------------------------------------------------------------------------------------------------------------------
ReplicaRequest.cs
----------------------------
namespace QaLocalDbReplica;

public sealed class ReplicaRequest
{
    public required string SourceServer { get; init; }
    public required string SourceDatabase { get; init; }
    public required string DestinationDatabase { get; init; }

    public bool UseWindowsAuthentication { get; init; }
    public string? UserName { get; init; }
    public string? Password { get; init; }

    public bool ReplaceExistingDestination { get; init; } = true;
    public bool DeleteTemporaryBacpac { get; init; } = true;
}


-----------------------------------------------------------------------------------------------------------------
SourceDatabaseService.cs
--------------------------------------

using Microsoft.Data.SqlClient;

namespace QaLocalDbReplica;

public static class SourceDatabaseService
{
    public static async Task<IReadOnlyList<DatabaseListItem>> GetDatabasesAsync(
        string server,
        bool windowsAuthentication,
        string? userName,
        string? password,
        CancellationToken cancellationToken)
    {
        string connectionString =
            ConnectionStringFactory.BuildSourceMaster(
                server,
                windowsAuthentication,
                userName,
                password);

        const string sql = """
SELECT name
FROM sys.databases
ORDER BY name;
""";

        var result = new List<DatabaseListItem>();

        await using var connection = new SqlConnection(connectionString);
        await connection.OpenAsync(cancellationToken);

        await using var command = new SqlCommand(sql, connection)
        {
            CommandTimeout = 60
        };

        await using var reader =
            await command.ExecuteReaderAsync(cancellationToken);

        while (await reader.ReadAsync(cancellationToken))
        {
            result.Add(new DatabaseListItem
            {
                Name = reader.GetString(0)
            });
        }

        return result;
    }
}
















Sunday, July 5, 2026

Create Angular Project

 In this Article, we will discuss about creating Angular project.


FormMain.cs

--------------------------

using System;

using System.Diagnostics;

using System.IO;

using System.Threading.Tasks;

using System.Windows.Forms;


namespace AngularProjectWizard

{

    public partial class FormMain : Form

    {

        public FormMain()

        {

            InitializeComponent();

            // Defaults

            txtNodePath.Text = GuessNodePath();

            txtAngularVersion.Text = "latest";

            chkStandalone.Checked = true;

            chkDefaults.Checked = true;

            chkBuildAfterCreate.Checked = true;

            txtAngularCliBase.Text = "npx --package @angular/cli";

        }


        private static string GuessNodePath()

        {

            string[] candidates = new[]

            {

                @"C:\Program Files\nodejs\node.exe",

                @"C:\Program Files (x86)\nodejs\node.exe"

            };

            foreach (var c in candidates)

            {

                if (File.Exists(c)) return c;

            }

            try

            {

                var p = new Process

                {

                    StartInfo = new ProcessStartInfo

                    {

                        FileName = "where",

                        Arguments = "node",

                        RedirectStandardOutput = true,

                        UseShellExecute = false,

                        CreateNoWindow = true

                    }

                };

                p.Start();

                var line = p.StandardOutput.ReadLine();

                p.WaitForExit(1500);

                if (!string.IsNullOrWhiteSpace(line) && File.Exists(line))

                    return line;

            }

            catch { }

            return string.Empty;

        }


        private void btnBrowseLocation_Click(object sender, EventArgs e)

        {

            using var fbd = new FolderBrowserDialog { Description = "Choose the folder that will contain the new Angular app" };

            if (fbd.ShowDialog() == DialogResult.OK)

            {

                txtLocation.Text = fbd.SelectedPath;

                if (string.IsNullOrWhiteSpace(txtProjectName.Text)) txtProjectName.Text = "AngularApp";

            }

        }


        private void btnBrowseNode_Click(object sender, EventArgs e)

        {

            using var ofd = new OpenFileDialog { Filter = "node.exe|node.exe|All files|*.*", Title = "Select Node interpreter (node.exe)" };

            if (ofd.ShowDialog() == DialogResult.OK) txtNodePath.Text = ofd.FileName;

        }


        private async void btnCreate_Click(object sender, EventArgs e)

        {

            var nodePath = txtNodePath.Text.Trim();

            var baseCli = txtAngularCliBase.Text.Trim();

            var version = txtAngularVersion.Text.Trim();

            var location = txtLocation.Text.Trim();

            var name = txtProjectName.Text.Trim();


            if (string.IsNullOrWhiteSpace(location) || !Directory.Exists(location))

            {

                MessageBox.Show("Please choose a valid target folder.", "Validation", MessageBoxButtons.OK, MessageBoxIcon.Warning);

                return;

            }

            if (string.IsNullOrWhiteSpace(name))

            {

                MessageBox.Show("Please enter a project name.", "Validation", MessageBoxButtons.OK, MessageBoxIcon.Warning);

                return;

            }


            string fileName = "npx";

            if (!string.IsNullOrWhiteSpace(nodePath) && File.Exists(nodePath))

            {

                var npxFromNode = nodePath.Replace("node.exe", "npx.cmd");

                if (File.Exists(npxFromNode)) fileName = $"\"{npxFromNode}\"";

            }


            var cliPkg = string.IsNullOrWhiteSpace(version) ? "@angular/cli" : $"@angular/cli@{version}";

            var args = $"--yes --package {cliPkg} ng new {name} --no-interactive";


            if (chkDefaults.Checked) args += " --defaults";

            if (chkStandalone.Checked) args += " --standalone=true";


            ToggleUi(false);

            txtOutput.Clear();

            WriteLine(">>> Working directory: " + location);

            WriteLine($">>> Running: {fileName} {args}");

            progress.Style = ProgressBarStyle.Marquee;


            try

            {

                var exit = await RunProcessAsync(fileName, args, location, (line) => WriteLine(line));

                progress.Style = ProgressBarStyle.Blocks;

                if (exit == 0)

                {

                    WriteLine(" Project generation completed.");

                    btnOpenFolder.Enabled = true;


                    if (chkDisableAnalytics.Checked)

                    {

                        string projectPath = Path.Combine(location, name);

                        string ngCmd = Path.Combine(projectPath, "node_modules", ".bin", "ng.cmd");

                        if (!File.Exists(ngCmd)) ngCmd = "ng";

                        WriteLine(">>> Disabling Angular analytics...");

                        await RunProcessAsync(ngCmd, "analytics off --global", projectPath, (line) => WriteLine(line));

                    }


                    if (chkBuildAfterCreate.Checked)

                    {

                        string projectPath = Path.Combine(location, name);

                        WriteLine(">>> Starting Angular build...");

                        string ngPath = Path.Combine(projectPath, "node_modules", ".bin", "ng.cmd");

                        int buildExit;

                        if (File.Exists(ngPath))

                            buildExit = await RunProcessAsync(ngPath, "build --no-interactive", projectPath, (line) => WriteLine(line));

                        else

                            buildExit = await RunProcessAsync("cmd.exe", "/c ng build --no-interactive", projectPath, (line) => WriteLine(line));


                        if (buildExit == 0) WriteLine("🏁 Angular build completed successfully.");

                        else WriteLine($"⚠️ Build exited with code {buildExit}.");

                    }

                }

                else

                {

                    WriteLine($"❌ Process exited with code {exit}.");

                }

            }

            catch (Exception ex)

            {

                progress.Style = ProgressBarStyle.Blocks;

                WriteLine("❌ Error: " + ex.Message);

            }

            finally

            {

                ToggleUi(true);

            }

        }


        private void ToggleUi(bool enabled)

        {

            foreach (Control c in this.Controls) c.Enabled = enabled;

            btnOpenFolder.Enabled = false;

        }


        private void WriteLine(string? text)

        {

            if (string.IsNullOrEmpty(text)) return;

            if (txtOutput.InvokeRequired) txtOutput.Invoke(new Action(() => txtOutput.AppendText(text + Environment.NewLine)));

            else txtOutput.AppendText(text + Environment.NewLine);

        }


        private static Task<int> RunProcessAsync(string fileName, string arguments, string workingDir, Action<string?> onData)

        {

            var tcs = new TaskCompletionSource<int>();

            var p = new Process

            {

                StartInfo = new ProcessStartInfo

                {

                    FileName = fileName,

                    Arguments = arguments,

                    WorkingDirectory = workingDir,

                    RedirectStandardOutput = true,

                    RedirectStandardError = true,

                    UseShellExecute = false,

                    CreateNoWindow = true

                },

                EnableRaisingEvents = true

            };

            p.OutputDataReceived += (s, e) => onData(e.Data);

            p.ErrorDataReceived += (s, e) => onData(e.Data);

            p.Exited += (s, e) => { tcs.TrySetResult(p.ExitCode); p.Dispose(); };

            try

            {

                p.Start();

                p.BeginOutputReadLine();

                p.BeginErrorReadLine();

            }

            catch (Exception ex)

            {

                tcs.TrySetException(ex);

            }

            return tcs.Task;

        }


        private void btnOpenFolder_Click(object sender, EventArgs e)

        {

            var target = Path.Combine(txtLocation.Text.Trim(), txtProjectName.Text.Trim());

            if (Directory.Exists(target))

            {

                Process.Start(new ProcessStartInfo { FileName = target, UseShellExecute = true });

            }

        }

    }

}



FormMain.Designer.cs

--------------------------------------

namespace AngularProjectWizard

{

    partial class FormMain

    {

        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)

        {

            if (disposing && (components != null)) components.Dispose();

            base.Dispose(disposing);

        }


        #region Windows Form Designer generated code

        private void InitializeComponent()

        {

            this.lblHeader = new System.Windows.Forms.Label();

            this.lblLocation = new System.Windows.Forms.Label();

            this.txtLocation = new System.Windows.Forms.TextBox();

            this.btnBrowseLocation = new System.Windows.Forms.Button();

            this.lblProjectName = new System.Windows.Forms.Label();

            this.txtProjectName = new System.Windows.Forms.TextBox();

            this.lblNode = new System.Windows.Forms.Label();

            this.txtNodePath = new System.Windows.Forms.TextBox();

            this.btnBrowseNode = new System.Windows.Forms.Button();

            this.lblCli = new System.Windows.Forms.Label();

            this.txtAngularCliBase = new System.Windows.Forms.TextBox();

            this.lblVersion = new System.Windows.Forms.Label();

            this.txtAngularVersion = new System.Windows.Forms.TextBox();

            this.chkStandalone = new System.Windows.Forms.CheckBox();

            this.chkDefaults = new System.Windows.Forms.CheckBox();

            this.chkBuildAfterCreate = new System.Windows.Forms.CheckBox();

            this.chkDisableAnalytics = new System.Windows.Forms.CheckBox();

            this.btnCreate = new System.Windows.Forms.Button();

            this.txtOutput = new System.Windows.Forms.RichTextBox();

            this.progress = new System.Windows.Forms.ProgressBar();

            this.btnOpenFolder = new System.Windows.Forms.Button();

            this.SuspendLayout();

            // 

            // lblHeader

            // 

            this.lblHeader.AutoSize = true;

            this.lblHeader.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold);

            this.lblHeader.Location = new System.Drawing.Point(16, 12);

            this.lblHeader.Name = "lblHeader";

            this.lblHeader.Size = new System.Drawing.Size(203, 21);

            this.lblHeader.TabIndex = 0;

            this.lblHeader.Text = "New Angular CLI Project";

            // 

            // lblLocation

            // 

            this.lblLocation.AutoSize = true;

            this.lblLocation.Location = new System.Drawing.Point(18, 50);

            this.lblLocation.Name = "lblLocation";

            this.lblLocation.Size = new System.Drawing.Size(53, 15);

            this.lblLocation.TabIndex = 1;

            this.lblLocation.Text = "Location";

            // 

            // txtLocation

            // 

            this.txtLocation.Location = new System.Drawing.Point(21, 68);

            this.txtLocation.Name = "txtLocation";

            this.txtLocation.Size = new System.Drawing.Size(560, 23);

            this.txtLocation.TabIndex = 2;

            // 

            // btnBrowseLocation

            // 

            this.btnBrowseLocation.Location = new System.Drawing.Point(587, 68);

            this.btnBrowseLocation.Name = "btnBrowseLocation";

            this.btnBrowseLocation.Size = new System.Drawing.Size(75, 23);

            this.btnBrowseLocation.TabIndex = 3;

            this.btnBrowseLocation.Text = "Browse...";

            this.btnBrowseLocation.UseVisualStyleBackColor = true;

            this.btnBrowseLocation.Click += new System.EventHandler(this.btnBrowseLocation_Click);

            // 

            // lblProjectName

            // 

            this.lblProjectName.AutoSize = true;

            this.lblProjectName.Location = new System.Drawing.Point(18, 99);

            this.lblProjectName.Name = "lblProjectName";

            this.lblProjectName.Size = new System.Drawing.Size(80, 15);

            this.lblProjectName.TabIndex = 4;

            this.lblProjectName.Text = "Project Name";

            // 

            // txtProjectName

            // 

            this.txtProjectName.Location = new System.Drawing.Point(21, 117);

            this.txtProjectName.Name = "txtProjectName";

            this.txtProjectName.Size = new System.Drawing.Size(220, 23);

            this.txtProjectName.TabIndex = 5;

            // 

            // lblNode

            // 

            this.lblNode.AutoSize = true;

            this.lblNode.Location = new System.Drawing.Point(18, 151);

            this.lblNode.Name = "lblNode";

            this.lblNode.Size = new System.Drawing.Size(94, 15);

            this.lblNode.TabIndex = 6;

            this.lblNode.Text = "Node interpreter";

            // 

            // txtNodePath

            // 

            this.txtNodePath.Location = new System.Drawing.Point(21, 169);

            this.txtNodePath.Name = "txtNodePath";

            this.txtNodePath.Size = new System.Drawing.Size(560, 23);

            this.txtNodePath.TabIndex = 7;

            // 

            // btnBrowseNode

            // 

            this.btnBrowseNode.Location = new System.Drawing.Point(587, 169);

            this.btnBrowseNode.Name = "btnBrowseNode";

            this.btnBrowseNode.Size = new System.Drawing.Size(75, 23);

            this.btnBrowseNode.TabIndex = 8;

            this.btnBrowseNode.Text = "Browse...";

            this.btnBrowseNode.UseVisualStyleBackColor = true;

            this.btnBrowseNode.Click += new System.EventHandler(this.btnBrowseNode_Click);

            // 

            // lblCli

            // 

            this.lblCli.AutoSize = true;

            this.lblCli.Location = new System.Drawing.Point(18, 203);

            this.lblCli.Name = "lblCli";

            this.lblCli.Size = new System.Drawing.Size(69, 15);

            this.lblCli.TabIndex = 9;

            this.lblCli.Text = "Angular CLI";

            // 

            // txtAngularCliBase

            // 

            this.txtAngularCliBase.Location = new System.Drawing.Point(21, 221);

            this.txtAngularCliBase.Name = "txtAngularCliBase";

            this.txtAngularCliBase.PlaceholderText = "npx --package @angular/cli";

            this.txtAngularCliBase.ReadOnly = true;

            this.txtAngularCliBase.Size = new System.Drawing.Size(329, 23);

            this.txtAngularCliBase.TabIndex = 10;

            this.txtAngularCliBase.Text = "npx --package @angular/cli";

            // 

            // lblVersion

            // 

            this.lblVersion.AutoSize = true;

            this.lblVersion.Location = new System.Drawing.Point(364, 203);

            this.lblVersion.Name = "lblVersion";

            this.lblVersion.Size = new System.Drawing.Size(94, 15);

            this.lblVersion.TabIndex = 11;

            this.lblVersion.Text = "Angular CLI ver.";

            // 

            // txtAngularVersion

            // 

            this.txtAngularVersion.Location = new System.Drawing.Point(367, 221);

            this.txtAngularVersion.Name = "txtAngularVersion";

            this.txtAngularVersion.PlaceholderText = "latest or 20.3.4";

            this.txtAngularVersion.Size = new System.Drawing.Size(214, 23);

            this.txtAngularVersion.TabIndex = 12;

            // 

            // chkStandalone

            // 

            this.chkStandalone.AutoSize = true;

            this.chkStandalone.Location = new System.Drawing.Point(21, 259);

            this.chkStandalone.Name = "chkStandalone";

            this.chkStandalone.Size = new System.Drawing.Size(221, 19);

            this.chkStandalone.TabIndex = 13;

            this.chkStandalone.Text = "Create new project with standalone";

            this.chkStandalone.UseVisualStyleBackColor = true;

            // 

            // chkDefaults

            // 

            this.chkDefaults.AutoSize = true;

            this.chkDefaults.Location = new System.Drawing.Point(21, 284);

            this.chkDefaults.Name = "chkDefaults";

            this.chkDefaults.Size = new System.Drawing.Size(171, 19);

            this.chkDefaults.TabIndex = 14;

            this.chkDefaults.Text = "Use the default project setup";

            this.chkDefaults.UseVisualStyleBackColor = true;

            // 

            // chkBuildAfterCreate

            // 

            this.chkBuildAfterCreate.AutoSize = true;

            this.chkBuildAfterCreate.Location = new System.Drawing.Point(21, 309);

            this.chkBuildAfterCreate.Name = "chkBuildAfterCreate";

            this.chkBuildAfterCreate.Size = new System.Drawing.Size(174, 19);

            this.chkBuildAfterCreate.TabIndex = 19;

            this.chkBuildAfterCreate.Text = "Run \"ng build\" after creation";

            this.chkBuildAfterCreate.UseVisualStyleBackColor = true;

            // 

            // chkDisableAnalytics

            // 

            this.chkDisableAnalytics.AutoSize = true;

            this.chkDisableAnalytics.Location = new System.Drawing.Point(21, 334);

            this.chkDisableAnalytics.Name = "chkDisableAnalytics";

            this.chkDisableAnalytics.Size = new System.Drawing.Size(206, 19);

            this.chkDisableAnalytics.TabIndex = 20;

            this.chkDisableAnalytics.Text = "Disable Angular analytics (global)";

            this.chkDisableAnalytics.UseVisualStyleBackColor = true;

            // 

            // btnCreate

            // 

            this.btnCreate.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);

            this.btnCreate.Location = new System.Drawing.Point(587, 361);

            this.btnCreate.Name = "btnCreate";

            this.btnCreate.Size = new System.Drawing.Size(75, 30);

            this.btnCreate.TabIndex = 15;

            this.btnCreate.Text = "Create";

            this.btnCreate.UseVisualStyleBackColor = true;

            this.btnCreate.Click += new System.EventHandler(this.btnCreate_Click);

            // 

            // txtOutput

            // 

            this.txtOutput.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;

            this.txtOutput.Font = new System.Drawing.Font("Consolas", 9F);

            this.txtOutput.Location = new System.Drawing.Point(21, 407);

            this.txtOutput.Name = "txtOutput";

            this.txtOutput.ReadOnly = true;

            this.txtOutput.Size = new System.Drawing.Size(641, 190);

            this.txtOutput.TabIndex = 16;

            this.txtOutput.Text = "";

            // 

            // progress

            // 

            this.progress.Location = new System.Drawing.Point(21, 361);

            this.progress.Name = "progress";

            this.progress.Size = new System.Drawing.Size(481, 8);

            this.progress.TabIndex = 17;

            // 

            // btnOpenFolder

            // 

            this.btnOpenFolder.Location = new System.Drawing.Point(508, 361);

            this.btnOpenFolder.Name = "btnOpenFolder";

            this.btnOpenFolder.Size = new System.Drawing.Size(73, 30);

            this.btnOpenFolder.TabIndex = 18;

            this.btnOpenFolder.Text = "Open";

            this.btnOpenFolder.UseVisualStyleBackColor = true;

            this.btnOpenFolder.Click += new System.EventHandler(this.btnOpenFolder_Click);

            // 

            // FormMain

            // 

            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);

            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

            this.ClientSize = new System.Drawing.Size(684, 611);

            this.Controls.Add(this.btnOpenFolder);

            this.Controls.Add(this.progress);

            this.Controls.Add(this.txtOutput);

            this.Controls.Add(this.btnCreate);

            this.Controls.Add(this.chkDisableAnalytics);

            this.Controls.Add(this.chkBuildAfterCreate);

            this.Controls.Add(this.chkDefaults);

            this.Controls.Add(this.chkStandalone);

            this.Controls.Add(this.txtAngularVersion);

            this.Controls.Add(this.lblVersion);

            this.Controls.Add(this.txtAngularCliBase);

            this.Controls.Add(this.lblCli);

            this.Controls.Add(this.btnBrowseNode);

            this.Controls.Add(this.txtNodePath);

            this.Controls.Add(this.lblNode);

            this.Controls.Add(this.txtProjectName);

            this.Controls.Add(this.lblProjectName);

            this.Controls.Add(this.btnBrowseLocation);

            this.Controls.Add(this.txtLocation);

            this.Controls.Add(this.lblLocation);

            this.Controls.Add(this.lblHeader);

            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;

            this.MaximizeBox = false;

            this.Name = "FormMain";

            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;

            this.Text = "Angular CLI Project Wizard";

            this.ResumeLayout(false);

            this.PerformLayout();

        }

        #endregion


        private System.Windows.Forms.Label lblHeader;

        private System.Windows.Forms.Label lblLocation;

        private System.Windows.Forms.TextBox txtLocation;

        private System.Windows.Forms.Button btnBrowseLocation;

        private System.Windows.Forms.Label lblProjectName;

        private System.Windows.Forms.TextBox txtProjectName;

        private System.Windows.Forms.Label lblNode;

        private System.Windows.Forms.TextBox txtNodePath;

        private System.Windows.Forms.Button btnBrowseNode;

        private System.Windows.Forms.Label lblCli;

        private System.Windows.Forms.TextBox txtAngularCliBase;

        private System.Windows.Forms.Label lblVersion;

        private System.Windows.Forms.TextBox txtAngularVersion;

        private System.Windows.Forms.CheckBox chkStandalone;

        private System.Windows.Forms.CheckBox chkDefaults;

        private System.Windows.Forms.Button btnCreate;

        private System.Windows.Forms.RichTextBox txtOutput;

        private System.Windows.Forms.ProgressBar progress;

        private System.Windows.Forms.Button btnOpenFolder;

        private System.Windows.Forms.CheckBox chkBuildAfterCreate;

        private System.Windows.Forms.CheckBox chkDisableAnalytics;

    }

}



Program.cs

-----------------------

using System;

using System.Windows.Forms;


namespace AngularProjectWizard

{

    internal static class Program

    {

        [STAThread]

        static void Main()

        {

            ApplicationConfiguration.Initialize();

            Application.Run(new FormMain());

        }

    }

}



Saturday, July 4, 2026

PDF generation

 In this article, we will discuss about PDF generation



MainForm.cs

------------------------


using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Drawing;

using System.Drawing.Imaging;

using System.IO;

using System.Linq;

using System.Runtime.InteropServices;

using System.Security.Cryptography;

using System.Text.RegularExpressions;

using System.Windows.Forms;

using iTextSharp.text;

using iTextSharp.text.pdf;

using Org.BouncyCastle.Asn1.Cmp;

using Org.BouncyCastle.Asn1.X509;

using Org.BouncyCastle.Bcpg.OpenPgp;

using Org.BouncyCastle.Utilities;

using Rectangle = System.Drawing.Rectangle;


namespace AutoRegionScreenshotPDFV2

{


    public partial class MainForm : Form

    {

        private Rectangle selectedRegion;

        private bool regionSelected = false;

        private bool capturing = false;

        private string screenshotFolder;

        private int screenshotCount = 0;

        private NotifyIcon trayIcon;

        private ContextMenuStrip trayMenu;


        // Import Windows API functions for always on top

        private const int SWP_NOSIZE = 0x0001;

        private const int SWP_NOMOVE = 0x0002;

        private const int SWP_NOACTIVATE = 0x0010;

        private const int HWND_TOPMOST = -1;

        private const int HWND_NOTOPMOST = -2;


        [DllImport("user32.dll")]

        private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);


        public MainForm()

        {

            InitializeComponent();

            this.KeyPreview = true;

            this.KeyDown += Form1_KeyDown;


            // Define folder path

            screenshotFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Screenshots");

            Directory.CreateDirectory(screenshotFolder);


            // Initialize tray icon

            InitializeTrayIcon();


            // Set window to be always on top

            SetAlwaysOnTop(true);

        }


        private void SetAlwaysOnTop(bool onTop)

        {

            SetWindowPos(this.Handle,

                        onTop ? (IntPtr)HWND_TOPMOST : (IntPtr)HWND_NOTOPMOST,

                        0, 0, 0, 0,

                        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

        }


        private void InitializeTrayIcon()

        {

            trayMenu = new ContextMenuStrip();

            trayMenu.Items.Add("Restore", null, (s, e) => RestoreFromTray());

            trayMenu.Items.Add("Toggle Always On Top", null, (s, e) => ToggleAlwaysOnTop());

            trayMenu.Items.Add("Exit", null, (s, e) => Application.Exit());


            trayIcon = new NotifyIcon

            {

                Text = "Screenshot Region to PDF",

                Icon = SystemIcons.Application,

                ContextMenuStrip = trayMenu,

                Visible = true

            };


            trayIcon.DoubleClick += (s, e) => RestoreFromTray();

        }


        private void ToggleAlwaysOnTop()

        {

            bool isCurrentlyOnTop = GetIsAlwaysOnTop();

            SetAlwaysOnTop(!isCurrentlyOnTop);


            if (this.Visible)

            {

                MessageBox.Show($"Always on top is now {(!isCurrentlyOnTop ? "enabled" : "disabled")}",

                              "Always On Top",

                              MessageBoxButtons.OK,

                              MessageBoxIcon.Information);

            }

        }


        // Get the current window style

        const int GWL_EXSTYLE = -20;

        const int WS_EX_TOPMOST = 0x00000008;

        [DllImport("user32.dll")]

        static extern int GetWindowLong(IntPtr hWnd, int nIndex);


        private bool GetIsAlwaysOnTop()

        {

           


            int style = GetWindowLong(this.Handle, GWL_EXSTYLE);

            return (style & WS_EX_TOPMOST) != 0;

        }


        private void RestoreFromTray()

        {

            this.Show();

            this.WindowState = FormWindowState.Normal;

            this.ShowInTaskbar = true;

            this.Activate();

        }


        protected override void OnResize(EventArgs e)

        {

            base.OnResize(e);


            if (this.WindowState == FormWindowState.Minimized)

            {

                this.Hide();

                this.ShowInTaskbar = false;

                trayIcon.ShowBalloonTip(1000, "Still running", "The application is still running in the background", ToolTipIcon.Info);

            }

        }


        protected override void OnFormClosing(FormClosingEventArgs e)

        {

            base.OnFormClosing(e);


            // Clean up tray icon

            if (e.CloseReason == CloseReason.UserClosing)

            {

                e.Cancel = true;

                this.WindowState = FormWindowState.Minimized;

            }

            else

            {

                trayIcon.Visible = false;

                trayIcon.Dispose();

            }

        }


        private void MainForm_Load(object sender, EventArgs e)

        {

            lblStatus.Text = "No region selected.";

        }


        private void btnSelectRegion_Click(object sender, EventArgs e)

        {

            // Temporarily disable always on top for region selection

            SetAlwaysOnTop(false);


            using (var selector = new RegionSelector2())

            {

                if (selector.ShowDialog() == DialogResult.OK)

                {

                    selectedRegion = selector.SelectedRegion;

                    regionSelected = true;

                    lblStatus.Text = $"Region selected: {selectedRegion.Width}x{selectedRegion.Height}";

                }

            }


            // Restore always on top

            SetAlwaysOnTop(true);

        }


        private void btnStart_Click(object sender, EventArgs e)

        {

            if (!regionSelected)

            {

                MessageBox.Show("Please select a region first.");

                return;

            }


            capturing = true;

            screenshotCount = 0;

            lblStatus.Text = "Started. Press 'P' to capture screenshots.";

        }


        private void Form1_KeyDown(object sender, KeyEventArgs e)

        {

            if (!capturing || !regionSelected) return;


            if (e.KeyCode == Keys.P)

            {

                CaptureScreenshot();

            }

        }


        private void CaptureScreenshot()

        {

            string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmssfff");

            string fileName = $"Screenshot_{timestamp}.png";

            string filePath = Path.Combine(screenshotFolder, fileName);


            using (Bitmap bmp = new Bitmap(selectedRegion.Width, selectedRegion.Height))

            {

                using (Graphics g = Graphics.FromImage(bmp))

                {

                    g.CopyFromScreen(selectedRegion.Location, Point.Empty, selectedRegion.Size);

                }

                bmp.Save(filePath, ImageFormat.Png);

            }


            screenshotCount++;

            lblStatus.Text = $"Captured: {fileName} | Total: {screenshotCount}";


            // Show balloon tip when minimized

            if (this.WindowState == FormWindowState.Minimized)

            {

                trayIcon.ShowBalloonTip(1000, "Screenshot Captured", fileName, ToolTipIcon.Info);

            }

        }


        private void btnStopSave_Click(object sender, EventArgs e)

        {

            CreatePdfFromImages(screenshotFolder);

        }


        private void CreatePdfFromImages(string screenshotsFolder)

        {

            try

            {

                string[] imageFiles = Directory.GetFiles(screenshotsFolder, "Screenshot_*.png");

                if (imageFiles.Length == 0)

                {

                    MessageBox.Show("No screenshots found to create PDF", "Warning",

                                  MessageBoxButtons.OK, MessageBoxIcon.Warning);

                    return;

                }


                // Sort files by timestamp in filename

                Array.Sort(imageFiles, (a, b) =>

                {

                    try

                    {

                        // Extract timestamp parts from filename (format: Screenshot_yyyyMMdd_HHmmssfff)

                        string filenameA = Path.GetFileNameWithoutExtension(a);

                        string filenameB = Path.GetFileNameWithoutExtension(b);


                        // Combine date and time parts (after first underscore)

                        string timeStringA = filenameA.Substring(filenameA.IndexOf('_') + 1).Replace("_", "");

                        string timeStringB = filenameB.Substring(filenameB.IndexOf('_') + 1).Replace("_", "");


                        return DateTime.ParseExact(timeStringA, "yyyyMMddHHmmssfff", null)

                            .CompareTo(DateTime.ParseExact(timeStringB, "yyyyMMddHHmmssfff", null));

                    }

                    catch (Exception ex)

                    {

                        MessageBox.Show($"Error parsing screenshot timestamps:\n{ex.Message}\nFilename A: {a}\nFilename B: {b}", "Error",

                                      MessageBoxButtons.OK, MessageBoxIcon.Error);

                        return 0; // Default sort if parsing fails

                    }

                });


                string pdfFilename = $"Screenshots_{DateTime.Now:yyyyMMdd_HHmmss}.pdf";

                string pdfPath = Path.Combine(screenshotsFolder, pdfFilename);


                using (FileStream fs = new FileStream(pdfPath, FileMode.Create))

                {

                    Document document = new Document(PageSize.A4.Rotate());

                    PdfWriter writer = PdfWriter.GetInstance(document, fs);

                    document.Open();


                    foreach (string imageFile in imageFiles)

                    {

                        try

                        {

                            using (var imgStream = new FileStream(imageFile, FileMode.Open))

                            {

                                iTextSharp.text.Image pdfImg = iTextSharp.text.Image.GetInstance(imgStream);

                                pdfImg.ScaleToFit(document.PageSize.Width - 50, document.PageSize.Height - 50);

                                pdfImg.Alignment = Element.ALIGN_CENTER;

                                document.Add(pdfImg);

                                document.NewPage();

                            }

                        }

                        catch (Exception ex)

                        {

                            MessageBox.Show($"Error processing image {imageFile}:\n{ex.Message}", "Error",

                                          MessageBoxButtons.OK, MessageBoxIcon.Error);

                        }

                    }

                    document.Close();

                }



                DeleteImageFiles(pdfPath, imageFiles);


                MessageBox.Show($"PDF successfully saved to:\n{pdfPath}", "Success",

                              MessageBoxButtons.OK, MessageBoxIcon.Information);

            }

            catch (Exception ex)

            {

                MessageBox.Show($"Failed to save PDF:\n{ex.Message}", "Error",

                              MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

        }


        private void DeleteImageFiles(string pdfPath, string[] imageFiles)

        {

            // DELETE IMAGES ONLY AFTER PDF IS SUCCESSFULLY CREATED

            if (File.Exists(pdfPath))

            {

                foreach (var imageFile in imageFiles)

                {

                    try

                    {

                        File.Delete(imageFile);

                    }

                    catch (Exception ex)

                    {

                        // Optional: log instead of showing popup

                        Console.WriteLine($"Failed to delete {imageFile}: {ex.Message}");

                    }

                }

            }


        }

    }


    public class RegionSelector2 : Form

    {

        private Point startPoint;

        private Point endPoint;

        private Rectangle selectedRect;

        private bool selecting = false;


        public Rectangle SelectedRegion => selectedRect;


        public RegionSelector2()

        {

            this.FormBorderStyle = FormBorderStyle.None;

            this.WindowState = FormWindowState.Maximized;

            this.Opacity = 0.3;

            this.BackColor = Color.Black;

            this.TopMost = true;

            this.Cursor = Cursors.Cross;

            this.DoubleBuffered = true;


            this.MouseDown += RegionSelector_MouseDown;

            this.MouseMove += RegionSelector_MouseMove;

            this.MouseUp += RegionSelector_MouseUp;

            this.Paint += RegionSelector_Paint;

            this.KeyDown += (s, e) => { if (e.KeyCode == Keys.Escape) this.DialogResult = DialogResult.Cancel; };

        }


        private void RegionSelector_MouseDown(object sender, MouseEventArgs e)

        {

            selecting = true;

            startPoint = e.Location;

            endPoint = e.Location;

            Invalidate();

        }


        private void RegionSelector_MouseMove(object sender, MouseEventArgs e)

        {

            if (selecting)

            {

                endPoint = e.Location;

                Invalidate();

            }

        }


        private void RegionSelector_MouseUp(object sender, MouseEventArgs e)

        {

            selecting = false;

            selectedRect = GetRectangle(startPoint, endPoint);

            this.DialogResult = DialogResult.OK;

            this.Close();

        }


        private void RegionSelector_Paint(object sender, PaintEventArgs e)

        {

            if (selecting)

            {

                Rectangle rect = GetRectangle(startPoint, endPoint);

                using (Pen pen = new Pen(Color.Red, 2))

                {

                    e.Graphics.DrawRectangle(pen, rect);

                }

            }

        }


        private Rectangle GetRectangle(Point p1, Point p2)

        {

            return new Rectangle(

                Math.Min(p1.X, p2.X),

                Math.Min(p1.Y, p2.Y),

                Math.Abs(p1.X - p2.X),

                Math.Abs(p1.Y - p2.Y));

        }

    }

}


MainForm.Designer.cs

-------------------------------------

using System.Drawing;

using System;

using System.Windows.Forms;


namespace AutoRegionScreenshotPDFV2

{


    partial class MainForm

    {

        private System.ComponentModel.IContainer components = null;

        private System.Windows.Forms.Button btnSelectRegion;

        private System.Windows.Forms.Button btnStart;

        private System.Windows.Forms.Button btnStopSave;

        private System.Windows.Forms.Label lblStatus;


        protected override void Dispose(bool disposing)

        {

            if (disposing && (components != null))

            {

                components.Dispose();

            }

            base.Dispose(disposing);

        }


        private void InitializeComponent()

        {

            this.btnSelectRegion = new System.Windows.Forms.Button();

            this.btnStart = new System.Windows.Forms.Button();

            this.btnStopSave = new System.Windows.Forms.Button();

            this.lblStatus = new System.Windows.Forms.Label();

            this.SuspendLayout();

            // 

            // btnSelectRegion

            // 

            this.btnSelectRegion.Location = new System.Drawing.Point(12, 12);

            this.btnSelectRegion.Name = "btnSelectRegion";

            this.btnSelectRegion.Size = new System.Drawing.Size(103, 35);

            this.btnSelectRegion.TabIndex = 0;

            this.btnSelectRegion.Text = "Select Region";

            this.btnSelectRegion.UseVisualStyleBackColor = true;

            this.btnSelectRegion.Click += new System.EventHandler(this.btnSelectRegion_Click);

            // 

            // btnStart

            // 

            this.btnStart.Location = new System.Drawing.Point(15, 65);

            this.btnStart.Name = "btnStart";

            this.btnStart.Size = new System.Drawing.Size(100, 35);

            this.btnStart.TabIndex = 1;

            this.btnStart.Text = "Start";

            this.btnStart.UseVisualStyleBackColor = true;

            this.btnStart.Click += new System.EventHandler(this.btnStart_Click);

            // 

            // btnStopSave

            // 

            this.btnStopSave.Location = new System.Drawing.Point(15, 116);

            this.btnStopSave.Name = "btnStopSave";

            this.btnStopSave.Size = new System.Drawing.Size(100, 35);

            this.btnStopSave.TabIndex = 2;

            this.btnStopSave.Text = "Stop and Save";

            this.btnStopSave.UseVisualStyleBackColor = true;

            this.btnStopSave.Click += new System.EventHandler(this.btnStopSave_Click);

            // 

            // lblStatus

            // 

            this.lblStatus.Location = new System.Drawing.Point(9, 171);

            this.lblStatus.Name = "lblStatus";

            this.lblStatus.Size = new System.Drawing.Size(110, 75);

            this.lblStatus.TabIndex = 3;

            this.lblStatus.Text = "Status goes here";

            // 

            // MainForm

            // 

            this.ClientSize = new System.Drawing.Size(131, 255);

            this.Controls.Add(this.lblStatus);

            this.Controls.Add(this.btnStopSave);

            this.Controls.Add(this.btnStart);

            this.Controls.Add(this.btnSelectRegion);

            this.Name = "MainForm";

            this.Text = "Screenshot Region to PDF";

            this.Load += new System.EventHandler(this.MainForm_Load);

            this.ResumeLayout(false);


        }

    }

}



MainForm2.cs

----------------------------

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Drawing.Imaging;

using System.IO;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;

using iTextSharp.text.pdf;

using iTextSharp.text;

using Rectangle = System.Drawing.Rectangle;


namespace AutoRegionScreenshotPDFV2

{

    public partial class MainForm2 : Form

    {

        private Rectangle selectedRegion;

        private bool regionSelected = false;

        private bool capturing = false;

        private string screenshotFolder;

        private int screenshotCount = 0;


        public MainForm2()

        {

            InitializeComponent();

            this.KeyPreview = true;

            this.KeyDown += Form1_KeyDown;


            // Define folder path

            screenshotFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Screenshots");

            Directory.CreateDirectory(screenshotFolder);

        }


        private void MainForm_Load(object sender, EventArgs e)

        {

            lblStatus.Text = "No region selected.";

        }


        private void btnSelectRegion_Click(object sender, EventArgs e)

        {

            using (var selector = new RegionSelector())

            {

                if (selector.ShowDialog() == DialogResult.OK)

                {

                    selectedRegion = selector.SelectedRegion;

                    regionSelected = true;

                    lblStatus.Text = $"Region selected: {selectedRegion.Width}x{selectedRegion.Height}";

                }

            }

        }


        private void btnStart_Click(object sender, EventArgs e)

        {

            if (!regionSelected)

            {

                MessageBox.Show("Please select a region first.");

                return;

            }


            capturing = true;

            screenshotCount = 0;

            lblStatus.Text = "Started. Press 'P' to capture screenshots.";

        }


        private void Form1_KeyDown(object sender, KeyEventArgs e)

        {

            if (!capturing || !regionSelected) return;


            if (e.KeyCode == Keys.P)

            {

                string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmssfff");

                string fileName = $"Screenshot_{timestamp}.png";

                string filePath = Path.Combine(screenshotFolder, fileName);


                using (Bitmap bmp = new Bitmap(selectedRegion.Width, selectedRegion.Height))

                {

                    using (Graphics g = Graphics.FromImage(bmp))

                    {

                        g.CopyFromScreen(selectedRegion.Location, Point.Empty, selectedRegion.Size);

                    }

                    bmp.Save(filePath, ImageFormat.Png);

                }


                screenshotCount++;

                lblStatus.Text = $"Captured: {fileName} | Total: {screenshotCount}";

            }

        }


        private void btnStopSave_Click(object sender, EventArgs e)

        {

            var imageFiles = Directory.GetFiles(screenshotFolder, "*.png")

                .OrderBy(f => f) // Ensures sequential order by filename

                .ToList();


            CreatePdfFromImages(screenshotFolder);


            //if (imageFiles.Count == 0)

            //{

            //    MessageBox.Show("No screenshots found to save.");

            //    return;

            //}


            //SaveFileDialog saveDialog = new SaveFileDialog

            //{

            //    Filter = "PDF files (*.pdf)|*.pdf",

            //    Title = "Save PDF"

            //};


            //if (saveDialog.ShowDialog() == DialogResult.OK)

            //{

            //    using (FileStream fs = new FileStream(saveDialog.FileName, FileMode.Create))

            //    {

            //        using (Document doc = new Document())

            //        {

            //            PdfWriter.GetInstance(doc, fs);

            //            doc.Open();


            //            foreach (var imgPath in imageFiles)

            //            {

            //                var img = iTextSharp.text.Image.GetInstance(imgPath);

            //                img.ScaleToFit(doc.PageSize.Width - 20, doc.PageSize.Height - 20);

            //                img.Alignment = Element.ALIGN_CENTER;

            //                doc.Add(img);

            //                doc.NewPage();

            //            }


            //            doc.Close();

            //        }

            //    }


            //    MessageBox.Show("PDF created successfully.");

            //    lblStatus.Text = "PDF saved.";

            //    capturing = false;

            //}

        }



        private void CreatePdfFromImages(string screenshotsFolder)

        {

            try

            {

                string[] imageFiles = Directory.GetFiles(screenshotsFolder, "Screenshot_*.png");

                if (imageFiles.Length == 0)

                {

                    MessageBox.Show("No screenshots found to create PDF", "Warning",

                                  MessageBoxButtons.OK, MessageBoxIcon.Warning);

                    return;

                }


                // Sort files numerically

                Array.Sort(imageFiles, (a, b) =>

                {

                    int numA = int.Parse(Path.GetFileNameWithoutExtension(a).Split('_')[1]);

                    int numB = int.Parse(Path.GetFileNameWithoutExtension(b).Split('_')[1]);

                    return numA.CompareTo(numB);

                });


                string pdfFilename = $"Screenshots_{DateTime.Now:yyyyMMdd_HHmmss}.pdf";

                string pdfPath = Path.Combine(screenshotsFolder, pdfFilename);


                using (FileStream fs = new FileStream(pdfPath, FileMode.Create))

                {

                    Document document = new Document(PageSize.A4.Rotate());

                    PdfWriter writer = PdfWriter.GetInstance(document, fs);

                    document.Open();


                    foreach (string imageFile in imageFiles)

                    {

                        using (var imgStream = new FileStream(imageFile, FileMode.Open))

                        {

                            iTextSharp.text.Image pdfImg = iTextSharp.text.Image.GetInstance(imgStream);

                            pdfImg.ScaleToFit(document.PageSize.Width - 50, document.PageSize.Height - 50);

                            pdfImg.Alignment = Element.ALIGN_CENTER;

                            document.Add(pdfImg);

                            document.NewPage();

                        }

                    }

                    document.Close();

                }


                // Show success message with PDF path

                MessageBox.Show($"PDF successfully saved to:\n{pdfPath}", "Success",

                              MessageBoxButtons.OK, MessageBoxIcon.Information);

            }

            catch (Exception ex)

            {

                // Show error message

                MessageBox.Show($"Failed to save PDF:\n{ex.Message}", "Error",

                              MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

        }

    }



    public class RegionSelector : Form

    {

        private Point startPoint;

        private Point endPoint;

        private Rectangle selectedRect;

        private bool selecting = false;


        public Rectangle SelectedRegion => selectedRect;


        public RegionSelector()

        {

            this.FormBorderStyle = FormBorderStyle.None;

            this.WindowState = FormWindowState.Maximized;

            this.Opacity = 0.3;

            this.BackColor = Color.Black;

            this.TopMost = true;

            this.Cursor = Cursors.Cross;

            this.DoubleBuffered = true;


            this.MouseDown += RegionSelector_MouseDown;

            this.MouseMove += RegionSelector_MouseMove;

            this.MouseUp += RegionSelector_MouseUp;

            this.Paint += RegionSelector_Paint;

            this.KeyDown += (s, e) => { if (e.KeyCode == Keys.Escape) this.DialogResult = DialogResult.Cancel; };

        }


        private void RegionSelector_MouseDown(object sender, MouseEventArgs e)

        {

            selecting = true;

            startPoint = e.Location;

            endPoint = e.Location;

            Invalidate();

        }


        private void RegionSelector_MouseMove(object sender, MouseEventArgs e)

        {

            if (selecting)

            {

                endPoint = e.Location;

                Invalidate();

            }

        }


        private void RegionSelector_MouseUp(object sender, MouseEventArgs e)

        {

            selecting = false;

            selectedRect = GetRectangle(startPoint, endPoint);

            this.DialogResult = DialogResult.OK;

            this.Close();

        }


        private void RegionSelector_Paint(object sender, PaintEventArgs e)

        {

            if (selecting)

            {

                Rectangle rect = GetRectangle(startPoint, endPoint);

                using (Pen pen = new Pen(Color.Red, 2))

                {

                    e.Graphics.DrawRectangle(pen, rect);

                }

            }

        }


        private Rectangle GetRectangle(Point p1, Point p2)

        {

            return new Rectangle(

                Math.Min(p1.X, p2.X),

                Math.Min(p1.Y, p2.Y),

                Math.Abs(p1.X - p2.X),

                Math.Abs(p1.Y - p2.Y));

        }

    }

}



MainForm2.Designer.cs
------------------------------------
namespace AutoRegionScreenshotPDFV2
{
    partial class MainForm2
    {
        private System.ComponentModel.IContainer components = null;
        private System.Windows.Forms.Button btnSelectRegion;
        private System.Windows.Forms.Button btnStart;
        private System.Windows.Forms.Button btnStopSave;
        private System.Windows.Forms.Label lblStatus;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null)) components.Dispose();
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            this.btnSelectRegion = new System.Windows.Forms.Button();
            this.btnStart = new System.Windows.Forms.Button();
            this.btnStopSave = new System.Windows.Forms.Button();
            this.lblStatus = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // btnSelectRegion
            // 
            this.btnSelectRegion.Location = new System.Drawing.Point(12, 12);
            this.btnSelectRegion.Name = "btnSelectRegion";
            this.btnSelectRegion.Size = new System.Drawing.Size(120, 35);
            this.btnSelectRegion.TabIndex = 0;
            this.btnSelectRegion.Text = "Select Region";
            this.btnSelectRegion.UseVisualStyleBackColor = true;
            this.btnSelectRegion.Click += new System.EventHandler(this.btnSelectRegion_Click);
            // 
            // btnStart
            // 
            this.btnStart.Location = new System.Drawing.Point(138, 12);
            this.btnStart.Name = "btnStart";
            this.btnStart.Size = new System.Drawing.Size(100, 35);
            this.btnStart.TabIndex = 1;
            this.btnStart.Text = "Start";
            this.btnStart.UseVisualStyleBackColor = true;
            this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
            // 
            // btnStopSave
            // 
            this.btnStopSave.Location = new System.Drawing.Point(244, 12);
            this.btnStopSave.Name = "btnStopSave";
            this.btnStopSave.Size = new System.Drawing.Size(130, 35);
            this.btnStopSave.TabIndex = 2;
            this.btnStopSave.Text = "Stop and Save";
            this.btnStopSave.UseVisualStyleBackColor = true;
            this.btnStopSave.Click += new System.EventHandler(this.btnStopSave_Click);
            // 
            // lblStatus
            // 
            this.lblStatus.Location = new System.Drawing.Point(12, 60);
            this.lblStatus.Name = "lblStatus";
            this.lblStatus.Size = new System.Drawing.Size(362, 23);
            this.lblStatus.TabIndex = 3;
            this.lblStatus.Text = "Status goes here";
            // 
            // Form1
            // 
            this.ClientSize = new System.Drawing.Size(390, 100);
            this.Controls.Add(this.lblStatus);
            this.Controls.Add(this.btnStopSave);
            this.Controls.Add(this.btnStart);
            this.Controls.Add(this.btnSelectRegion);
            this.Name = "Form1";
            this.Text = "Screenshot Region to PDF";
            this.Load += new System.EventHandler(this.MainForm_Load);
            this.ResumeLayout(false);
        }
    }
}


Program.cs
-------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AutoRegionScreenshotPDFV2
{
    internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            //ApplicationConfiguration.Initialize();

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }
}