我的Office Outlook插件開發之旅(二)

来源:https://www.cnblogs.com/heirem/p/17788638.html
-Advertisement-
Play Games

下麵將完成的展示,使用MAPI介面操作Outlook完成通訊錄更新。 using Microsoft.Office.Interop.Outlook; using Microsoft.VisualBasic; using System; using System.Collections; using ...


下麵將完成的展示,使用MAPI介面操作Outlook完成通訊錄更新。

using Microsoft.Office.Interop.Outlook;
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AddressBookTool2
{
    class Program
    {
        static void Main(string[] args)
        {
            Process current = Process.GetCurrentProcess();
            Process[] processes = Process.GetProcessesByName(current.ProcessName);

            bool isAlreadyRunning = false;
            foreach (Process process in processes)
            {
                if (process.Id != current.Id)
                {
                    // 檢查路徑以確保是同一個可執行文件的另一個實例
                    if (process.MainModule.FileName == current.MainModule.FileName)
                    {
                        isAlreadyRunning = true;
                        break;
                    }
                }
            }

            if (isAlreadyRunning)
            {

            }
            else
            {
                while (true)
                {
                    Action();
                    Thread.Sleep(1000 * 60 * 15);
                }
            }
        }
        const string conn = "Server=192.168.100.99;Database=帆軟報表;uid=sa;pwd=dsc";

        /// <summary>
        /// 動作
        /// </summary>
        public static void Action()
        {
            string ipAddress = "192.168.100.99";
            Ping ping = new Ping();
            PingReply pingReply = ping.Send(ipAddress);
            if (pingReply.Status != IPStatus.Success) return;
            UpdateClient();
            const string sql = "SELECT Guid,應用名稱,版本,備註 FROM 帆軟報表.dbo.版本控制 WHERE 應用名稱 = N'集團通訊錄'";
            List<Dictionary<string, object>> list = SelectList(sql, conn);
            if (list.Count > 0)
            {
                string version = list[0]["版本"].ToString();
                if (string.IsNullOrEmpty(version)) return;
                string path = $"{Environment.CurrentDirectory}\\Version.conf";
                if (!File.Exists(path))
                {
                    UpdateAddressBook();
                    File.WriteAllText(path, version.Trim());
                }
                else
                {
                    string content = "";
                    foreach (string item in File.ReadLines(path))
                    {
                        content += item;
                    }
                    if (content.Trim() != version.Trim())
                    {
                        UpdateAddressBook();
                        File.WriteAllText(path, version.Trim());
                    }
                }
            }
        }

        /// <summary>
        /// 更新客戶端
        /// </summary>
        public static void UpdateClient()
        {
            string ipAddress = "192.168.100.18";
            Ping ping = new Ping();
            PingReply pingReply = ping.Send(ipAddress);
            if (pingReply.Status != IPStatus.Success) return;

            const string sql = "SELECT Guid,應用名稱,版本,備註 FROM 帆軟報表.dbo.版本控制 WHERE 應用名稱 = N'集團通訊錄客戶端'";
            List<Dictionary<string, object>> list = SelectList(sql, conn);
            if (list.Count > 0)
            {
                string version = list[0]["版本"].ToString();
                string path = $"{Environment.CurrentDirectory}\\ClientVersion.conf";
                if (!File.Exists(path))
                {
                    File.WriteAllText(path, version.Trim());
                    UpdateClientAction();
                    Environment.Exit(0);
                }
                else
                {
                    string content = "";
                    foreach (string item in File.ReadLines(path))
                    {
                        content += item;
                    }
                    if (content.Trim() != version.Trim())
                    {
                        File.WriteAllText(path, version.Trim());
                        UpdateClientAction();
                        Environment.Exit(0);
                    }
                }
            }
        }

        /// <summary>
        /// 更新客戶端行動
        /// </summary>
        public static void UpdateClientAction()
        {
            string batPath = $"{Environment.CurrentDirectory}\\temp.bat";
            string cmdText = $"@echo off{Environment.NewLine}timeout /t 3 /nobreak >nul{Environment.NewLine}start {Environment.CurrentDirectory}\\updater.bat \"{Environment.CurrentDirectory}\" \"{Environment.CurrentDirectory}\\AddressBookTool2.exe\"{Environment.NewLine}eixt";
            File.WriteAllText(batPath, cmdText, Encoding.UTF8);
            ProcessStartInfo psi = new ProcessStartInfo()
            {
                FileName = batPath,
                CreateNoWindow = true,
                RedirectStandardError = true,
                UseShellExecute = false
            };
            using (Process process = new Process())
            {
                process.StartInfo = psi;
                process.Start();
            }
        }

        /// <summary>
        /// 更新通訊錄
        /// </summary>
        public static void UpdateAddressBook()
        {
            const string sql = "SELECT 郵箱地址 AS 'emailAddress',姓氏 AS 'firstName',姓名 AS 'lastName', 群組 AS 'group' FROM [帆軟報表].[dbo].[集團郵箱通訊錄] WHERE 郵箱地址 IS NOT NULL AND (姓氏 IS NOT NULL OR 姓名 IS NOT NULL)";
            List<Dictionary<string, object>> list = SelectList(sql, conn);
            List<Contact> contacts = new List<Contact>();
            list.ForEach(it =>
            {
                string firstName = it["firstName"].ToString()?.Trim();
                string lastName = it["lastName"].ToString()?.Trim();
                string emailAddress = it["emailAddress"].ToString()?.Trim();
                string group = it["group"].ToString()?.Trim();
                int index = group.IndexOf(",");
                if (index >= 0)
                {
                    string[] groupList = group.Split(',');
                    groupList.ToList().ForEach(g =>
                    {
                        Contact contact = new Contact()
                        {
                            FirstName = firstName,
                            LastName = lastName,
                            EmailAddress = emailAddress,
                            Group = g
                        };
                        contacts.Add(contact);
                    });
                }
                else
                {
                    Contact contact = new Contact()
                    {
                        FirstName = firstName,
                        LastName = lastName,
                        EmailAddress = emailAddress,
                        Group = group
                    };
                    contacts.Add(contact);
                }
            });

            if (contacts.Count == 0) return;
            GeneractionStroe(contacts, false, "通訊錄", true, "湯石集團通訊錄");
            GeneractionStroe(contacts, false, "通訊錄", false, "湯石集團通訊錄");
        }



        public static void GeneractionStroe(List<Contact> contacts, bool order, string fileName, bool CH_zh, string addressBookName)
        {
            // 繁簡轉換
            contacts = ContactsLang(contacts, CH_zh);

            // 創建Store,也就是PST檔
            Microsoft.Office.Interop.Outlook.Application outlookApp = new Microsoft.Office.Interop.Outlook.Application();
            NameSpace session = outlookApp.GetNamespace("MAPI");
            string path = $"{Environment.CurrentDirectory}\\{fileName}.pst";
            Store store = GetStore(session, path, 5);

            MAPIFolder contactFolder = GetAddressBookFolder(store, addressBookName);
            // 移除就的聯繫人
            int count = contactFolder.Items.Count;
            for (int i = 0; i < count; i++)
            {
                contactFolder.Items.Remove(1);
            }
            MAPIFolder deteledItems = store.GetDefaultFolder(OlDefaultFolders.olFolderDeletedItems);
            count = deteledItems.Items.Count;
            for (int i = 0; i < count; i++)
            {
                deteledItems.Items.Remove(1);
            }

            // 新增聯繫人
            contacts.Distinct(new ContactEqualityComparer()).ToList().ForEach(contact =>
            {
                if (!string.IsNullOrEmpty(contact.FirstName) && !string.IsNullOrEmpty(contact.LastName))
                {
                    ContactItem newContact = contactFolder.Items.Add(OlItemType.olContactItem);
                    OrderContactItem(contact.FirstName, contact.LastName, order, newContact);
                    newContact.Email1Address = contact.EmailAddress;
                    newContact.Save();
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(newContact);
                    newContact = null;
                }
            });

            // 新增群組
            contacts.GroupBy(it => it.Group).Select(it => new
            ContactGroup()
            {
                Group = it.Key,
                Contacts = it.ToList()
            }).ToList().ForEach(it =>
            {
                if (!string.IsNullOrEmpty(it.Group))
                {
                    DistListItem dist = contactFolder.Items.Add(OlItemType.olDistributionListItem);
                    it.Contacts.ForEach(contact =>
                    {
                        Recipient recipient = outlookApp.Session.CreateRecipient(contact.FirstName + contact.LastName + "(" + contact.EmailAddress + ")");
                        if (recipient.Resolve())
                        {
                            dist.AddMember(recipient);
                        }
                    });
                    dist.DLName = it.Group;
                    dist.Save();
                    // 確保所有項已從新創建的PST中釋放
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(dist);
                    dist = null;
                }
            });

            // 清理Outlook對象,避免記憶體泄漏
            System.Runtime.InteropServices.Marshal.ReleaseComObject(session);
            System.Runtime.InteropServices.Marshal.ReleaseComObject(outlookApp);
            outlookApp = null;
            session = null;
        }


        /// <summary>
        /// 獲取Store
        /// </summary>
        /// <param name="session">命名控制項</param>
        /// <param name="target">目標pst檔</param>
        /// <param name="count">最大遞歸次數</param>
        /// <returns></returns>
        public static Store GetStore(NameSpace session, string target, int count)
        {
            Store store = null;
            foreach (Store it in session.Stores)
            {
                if (it.FilePath == target)
                {
                    store = it;
                    break;
                }
            }
            if (store == null && count > 0)
            {
                session.AddStore(target);
                return GetStore(session, target, count--);
            }
            return store;
        }

        /// <summary>
        /// 獲取聯繫人文件夾
        /// </summary>
        /// <param name="store">Store實例</param>
        /// <param name="name">文件夾名稱</param>
        /// <returns></returns>
        public static MAPIFolder GetAddressBookFolder(Store store, string name)
        {
            MAPIFolder folder = null;
            Folders folders = store.GetDefaultFolder(OlDefaultFolders.olFolderContacts).Folders;
            foreach (MAPIFolder item in folders)
            {
                if (item.Name == name)
                {
                    folder = item;
                    break;
                }
            }
            if (folder == null)
            {
                folder = store.GetDefaultFolder(OlDefaultFolders.olFolderContacts).Folders.Add(name);
                folder.ShowAsOutlookAB = true;// 設置成聯繫人
            }
            return folder;
        }

        /// <summary>
        /// 轉換語言,簡體轉繁體
        /// </summary>
        /// <param name="contacts">聯繫人信息集合</param>
        /// <param name="lang">是否轉繁體</param>
        /// <returns></returns>
        public static List<Contact> ContactsLang(List<Contact> contacts, bool lang)
        {
            List<Contact> result = new List<Contact>();
            if (lang)
            {
                return contacts;
            }
            else
            {
                contacts.ForEach(it =>
                {
                    it.FirstName = Strings.StrConv(it.FirstName, VbStrConv.TraditionalChinese);
                    it.LastName = Strings.StrConv(it.LastName, VbStrConv.TraditionalChinese);
                    it.Group = Strings.StrConv(it.Group, VbStrConv.TraditionalChinese);
                    result.Add(it);
                });
            }

            return result;
        }

        /// <summary>
        /// 轉換聯繫人的姓與名位置
        /// </summary>
        /// <param name="firstName">姓氏</param>
        /// <param name="lastName">名字</param>
        /// <param name="order">順序</param>
        /// <param name="contact">聯繫人實例</param>
        public static void OrderContactItem(string firstName, string lastName, bool order, ContactItem contact)
        {
            if (order)
            {
                contact.FirstName = firstName;
                contact.LastName = lastName;
            }
            else
            {
                contact.LastName = firstName;
                contact.FirstName = lastName;
            }
        }

        public struct Contact
        {
            public string FirstName;
            public string LastName;
            public string EmailAddress;
            public string Group;
        }

        public struct ContactGroup
        {
            public string Group;
            public List<Contact> Contacts;
        }

        public class ContactEqualityComparer : IEqualityComparer<Contact>
        {
            public bool Equals(Contact x, Contact y)
            {
                return x.FirstName == y.FirstName && x.LastName == y.LastName && x.EmailAddress == y.EmailAddress;
            }

            public int GetHashCode(Contact obj)
            {
                return obj.FirstName.GetHashCode() ^ obj.LastName.GetHashCode() ^ obj.EmailAddress.GetHashCode();
            }
        }

        /// <summary>
        /// 執行select語句
        /// </summary>
        /// <param name="sql">select語句</param>
        /// <param name="connection">資料庫鏈接語句</param>
        /// <returns>List的結果</returns>
        /// <exception cref="System.Exception"></exception>
        public static List<Dictionary<string, object>> SelectList(string sql, string connection)
        {
            if (sql == null || connection == null || sql == "" || connection == "")
                throw new System.Exception("未傳入SQL語句或者Connection鏈接語句");
            List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
            SqlConnection conn = new SqlConnection(connection);
            SqlCommand cmd = new SqlCommand(sql, conn);
            try
            {
                conn.Open();
                SqlDataReader sqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                while (sqlDataReader.Read())
                {
                    int count = sqlDataReader.FieldCount;
                    if (count <= 0) continue;
                    Dictionary<string, object> map = new Dictionary<string, object>();
                    for (int i = 0; i < count; i++)
                    {
                        string name = sqlDataReader.GetName(i);
                        object value = sqlDataReader.GetValue(i);
                        map.Add(name, value);
                    }
                    list.Add(map);
                }
                conn.Close();
                return list;
            }
            catch (System.Exception)
            {
                conn.Close();
                return null;
            }
        }
    }
}

updater.bat 更新用的

@echo off
set "source=\\192.168.100.18\mis\21.email-plugin\AddressBookTool"

:: 使用Robocopy複製除了version.conf之外的所有文件和目錄
robocopy "%source%" "%1%" /E /XD Version.conf ClientVersion.conf

:: 檢查並有條件地複製version.conf
if not exist "%1%\Version.conf" (
    copy /Y "%source%\Version.conf" "%1%"
)

:: 啟動程式
cd /d "%1%"
start "" "%2%"

exit

setup.bat 安裝用

@echo off
set "REG_PATH=HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\AddressBookTool"
set "client_bat=C:\TONS\AddressBookTool\start.bat"
set "folder=C:\TONS\AddressBookTool"
set "source=\\192.168.100.18\mis\21.email-plugin\AddressBookTool"

:: 使用Robocopy複製除了version.conf之外的所有文件和目錄
robocopy "%source%" "%folder%" /E /XD version.conf

:: 檢查並有條件地複製version.conf
if not exist "%folder%\version.conf" (
    copy /Y "%source%\version.conf" "%folder%"
)

:: 配置環境變數
reg query %REG_PATH% >nul 2>nul&&goto A||goto B
:B
reg add "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v AddressBookTool /t REG_SZ /d %client_bat% /f
:A
start %client_bat%
exit

start.bat 啟動用

@echo off
set "environment=C:\TONS\AddressBookTool"
set "client=C:\TONS\AddressBookTool\AddressBookTool2.exe"

:: 啟動程式
cd /d "%environment%"
start "" "%client%"
exit

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 正文 21 日正是周五,夏至。全年當中,白天時長最長的一天。而恰好那天也是銀行扣息的日子。所以很忙,我差點沒能走掉。 所幸最終還是有驚無險。 到斯的家裡,是晚上 9 點鐘。比我想得要早。這個周周四,他過生日。但是那天因為上班,所以移到了周末。不是法定節假日,很普通的一個周末。全年有很多個這樣的周末。 ...
  • 大模型在一定程度上去改變了我們生活生工作的思考的方式,然後也越來越多的個人還有企業在思考如何將大模型去應用到更加實際的呃生產生活中去,希望大語言模型能夠呃有一些更多企業級別生產落地的實踐,然後去幫助我們解決一些業務上的問題。目前 1 LLM的問題 1.1 幻覺 LLM因為是一個預訓練模型,它已有一些 ...
  • SingleStringMathTex是Mobjects分類中用來顯示數學公式的class。manim中有3個可以用來顯示數學公式的class,還有兩個是MathTex和Tex,後續再介紹。 從SingleStringMathTex的名稱中也可以看出,它是用來顯示只有一行的簡單公式。SingleSt ...
  • 1 模型 來看兩種不同類型的模型--LLM 和聊天模型。然後,它將介紹如何使用提示模板來格式化這些模型的輸入,以及如何使用輸出解析器來處理輸出。 LangChain 中的語言模型有兩種類型: 1.1 Chat Models 聊天模型通常由 LLM 支持,但專門針對會話進行了調整。提供者 API 使用 ...
  • 今天我們還講講Consumer、Supplier、Predicate、Function這幾個介面的用法,在 Java8 的用法當中,這幾個介面雖然沒有明目張膽的使用,但是,卻是潤物細無聲的。為什麼這麼說呢?這幾個介面都在 java.util.function 包下的,分別是Consumer(消費型) ...
  • pip install --upgrade langchain==0.0.279 -i https://pypi.org/simple 1 創建一個LLM 自有算力平臺+開源大模型(需要有龐大的GPU資源)企業自己訓練數據 第三方大模型API(openai/百度文心/阿裡通義千問...)數據無所謂 ...
  • LLM大模型與AI應用的粘合劑。 1 langchain是什麼以及發展過程 LangChain是一個開源框架,旨在簡化使用大型語言模型構建端到端應用程式的過程,也是ReAct(reason+act)論文的落地實現。 2022年10月25日開源 54K+ star 種子輪一周1000萬美金,A輪250 ...
  • 1.創建一個文件夾HCJV_01 2.vscode打開該文件夾,打開終端。 3.使用vite安裝,選擇vue,選擇JavaScript,項目名稱demo01 cnpm create vite@latest 4.跳轉demo01目錄下 cd demo01 5.安裝cnpm cnpm install 嘗 ...
一周排行
    -Advertisement-
    Play Games
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他們的程式會偶發性的卡死一段時間,然後又好了,讓我幫忙看下怎麼回事?窗體類的程式解決起來相對來說比較簡單,讓朋友用procdump自動抓一個卡死時的dump,拿到dump之後,上 windbg 說話。 二:WinDbg 分析 1. 主線程在做什麼 要想 ...
  • 功能說明 使用ListView時,希望可以在單元格顯示圖片或其他控制項,發現原生的ListView不支持,於是通過拓展,實現ListView可以顯示任意控制項的功能,效果如下: 實現方法 本來想著在單元格裡面實現控制項的自繪的,但是沒找到辦法,最後是通過在單元格的錶面顯示對應控制項的,浮於錶面達到目的。 實 ...
  • 由於.NET Framework 4.0 是比較古老的版本,只有New Relic 7.0以下的版本才會支持.NET Framework 4.0的引用程式。 Technical support for .NET Framework 4.0 or lower 你可以參考這個官方Install New ...
  • 前言 隨著 DEV24.1.3 的發佈,XAF Blazor 中的屬性編輯器(PropertyEditor)也進行了很大的改動,在使用體驗上也更接近 WinForm 了,由於進行了大量的封裝,理解上沒有 WinForm 直觀,所以本文通過對屬性編輯器的原理進行解析,並對比新舊版本中的變化,使大家能夠 ...
  • OPC基金會提供了OPC UA .NET標準庫以及示常式序,但官方文檔過於簡單,光看官方文檔和示常式序很難弄懂OPC UA .NET標準庫怎麼用,花了不少時間摸索才略微弄懂如何使用,以下記錄如何從一個控制台程式開發一個OPC UA伺服器。 安裝Nuget包 安裝OPCFoundation.NetSt ...
  • 今天在技術群里,石頭哥向大家提了個問題:"如何在一個以System身份運行的.NET程式(Windows Services)中,以其它活動的用戶身份啟動可互動式進程(桌面應用程式、控制台程式、等帶有UI和互動式體驗的程式)"? 我以前有過類似的需求,是在GitLab流水線中運行帶有UI的自動化測試程 ...
  • .Net 中提供了一系列的管理對象集合的類型,數組、可變列表、字典等。從類型安全上集合分為兩類,泛型集合 和 非泛型集合,傳統的非泛型集合存儲為Object,需要類型轉。而泛型集合提供了更好的性能、編譯時類型安全,推薦使用。 ...
  • 在以前我做程式的時候,一般在登錄視窗裡面顯示程式名稱,登錄視窗一般設置一張背景圖片,由於程式的名稱一般都是確定的,所以也不存在太大的問題,不過如果客戶定製不同的系統的時候,需要使用Photoshop修改下圖層的文字,再生成圖片,然後替換一下也可以了。不過本著減少客戶使用繁瑣性,也可以使用空白名稱的通... ...
  • 一:背景 1. 講故事 在dump分析的過程中經常會看到很多線程卡在Monitor.Wait方法上,曾經也有不少人問我為什麼用 !syncblk 看不到 Monitor.Wait 上的鎖信息,剛好昨天有時間我就來研究一下。 二:Monitor.Wait 底層怎麼玩的 1. 案例演示 為了方便講述,先 ...
  • 目錄前言學習參考過程總結: 前言 做個自由仔。 學習參考 ChatGpt; https://www.cnblogs.com/zhili/p/DesignPatternSummery.html(大佬的,看了好多次) 過程 原由: 一開始只是想查查鏈式調用原理,以為是要繼承什麼介面,實現什麼方法才可以實 ...