首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

用 C++Builder 實作 Windows 2000 Messenger:多執行緒、網路列舉與系統整合

     編輯:VC 教學

前言

Windows 2000 內建 Messenger 服務提供區域網路即時訊息傳遞。本文示範以 C++Builder 開發類似功能的客戶端,涵蓋多執行緒防死結、網路使用者列舉、Unicode 轉換、不規則視窗、自動啟動與系統托盤整合等關鍵技術。

核心技術架構

技術用途關鍵點
多執行緒收發訊息、網路列舉主執行緒專司 UI,背景執行緒處理封包,Synchronize 更新介面
NetServerEnum / NetUserEnum列舉線上電腦/使用者需連結 Netapi32.lib,處理分頁與緩衝區
Unicode 轉換AnsiString ↔ UnicodeWideString、MultiByteToWideChar、WideCharToMultiByte
不規則視窗自訂外觀SetWindowRgn + 區域建立
自動啟動登錄 Run 鍵HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
系統托盤常駐背景、右鍵選單Shell_NotifyIcon (NIM_ADD/MODIFY/DELETE)

介面元件配置

  • TListView:線上使用者清單(詳細檢視)
  • TTreeView:網域/工作群組階層
  • TMemo:訊息輸入區
  • TCheckBox:匿名發送、要求回執
  • TButton:發送鈕
  • TStatusBar:狀態列
  • TMainMenu、TPopupMenu、TrayIcon

關鍵程式碼片段

1. 發送訊息 (ButtonSendClick)

void __fastcall TFormMain::ButtonSendClick(TObject* Sender) {
    AnsiString Message = Memo1->Text.Trim();
    if (Message.IsEmpty()) { ShowMessage("請輸入訊息內容"); return; }

    AnsiString UserName, FromName;
    if (CheckBoxAnony->Checked) FromName = EditAnony->Text;
    else FromName = "";

    TListItem* Item;
    if (!ListView1->SelCount) {
        // 從 TreeView 選取
        if (!TreeView1->Selected) { ShowMessage("請選擇接收對象"); return; }
        UserName = TreeView1->Selected->Text;
        if (TreeView1->Selected->Level == 1) UserName += "*"; // 使用者節點
        new NetMessageSend(false, UserName, FromName, Message, CheckBoxGetRet->Checked);
        return;
    }

    // 從 ListView 多選
    Item = ListView1->Selected;
    UserName = Item->Caption;
    if (TreeView1->Selected->Level == 0) UserName += "*"; // 電腦節點
    while (UserName[1] == '\\') UserName = UserName.SubString(2, UserName.Length() - 1);
    new NetMessageSend(false, UserName, FromName, Message, CheckBoxGetRet->Checked);

    for (int i = 1; i < ListView1->SelCount; ++i) {
        Item = ListView1->GetNextItem(Item, sdAll, TItemStates() << isSelected);
        UserName = Item->Caption;
        if (TreeView1->Selected->Level == 0) UserName += "*";
        while (UserName[1] == '\\') UserName = UserName.SubString(2, UserName.Length() - 1);
        new NetMessageSend(false, UserName, FromName, Message, CheckBoxGetRet->Checked);
    }
}

2. 網路節點列舉執行緒 (NetEnumThread)

class NetEnumThread : public TThread {
protected:
    void __fastcall Execute() {
        // 1. 列舉網域/工作群組
        // NetServerEnum(NULL, 100, ... SV_TYPE_DOMAIN_ENUM ...)
        // 2. 對每個網域列舉伺服器
        // NetServerEnum(domain, 100, ... SV_TYPE_SERVER ...)
        // 3. Synchronize 更新 TreeView/ListView
        Synchronize(&UpdateUI);
    }
};

3. 系統托盤整合

// 建立圖示資料
NOTIFYICONDATA nid = {0};
nid.cbSize = sizeof(nid);
nid.hWnd = Handle;
nid.uID = 1;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_USER + 100; // 自訂訊息
nid.hIcon = Application->Icon->Handle;
StrCopy(nid.szTip, "My Messenger");
Shell_NotifyIcon(NIM_ADD, &nid);

// 訊息處理
BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(WM_USER + 100, TMessage, OnTrayIcon)
END_MESSAGE_MAP(TForm)

void __fastcall TFormMain::OnTrayIcon(TMessage& Msg) {
    if (Msg.LParam == WM_RBUTTONUP) {
        POINT pt; GetCursorPos(&pt);
        PopupMenu1->Popup(pt.x, pt.y);
    } else if (Msg.LParam == WM_LBUTTONDBLCLK) {
        Show(); WindowState = wsNormal;
    }
}

4. 自動啟動註冊

void RegisterAutoStart(bool enable) {
    TRegistry* reg = new TRegistry();
    reg->RootKey = HKEY_CURRENT_USER;
    if (reg->OpenKey("\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", true)) {
        if (enable)
            reg->WriteString("MyMessenger", Application->ExeName);
        else
            reg->DeleteValue("MyMessenger");
    }
    delete reg;
}

NetMessageSend 執行緒架構

class NetMessageSend : public TThread {
    AnsiString FUser, FFrom, FMsg;
    bool FNeedReceipt;
public:
    __fastcall NetMessageSend(bool CreateSuspended,
                              AnsiString User, AnsiString From,
                              AnsiString Msg, bool NeedReceipt)
        : TThread(CreateSuspended), FUser(User), FFrom(From),
          FMsg(Msg), FNeedReceipt(NeedReceipt) {
        FreeOnTerminate = true;
    }
protected:
    void __fastcall Execute() {
        // 1. 開啟 MAILSLOT 或 Named Pipe
        // 2. 組封包 (Unicode 轉換)
        // 3. WriteFile 發送
        // 4. 若需回執,ReadFile 等待回應
        // 5. Synchronize 更新 UI 狀態
    }
};

注意事項與現代化建議

  • Messenger 服務自 Windows Vista 起預設停用,現代環境建議改用 SignalR / WebSocket / gRPC 實作即時通訊
  • Unicode 轉換請統一使用 WideString 或 std::wstring,避免 ANSI 頁面碼問題
  • 網路操作務必設定逾時,避免執行緒永久阻塞
  • 介面更新嚴格透過 Synchronize 或 TThread::Queue (非阻塞)
  • 錯誤處理:GetLastError()、記錄日誌、使用者友善提示

結語

此專案展示了 C++Builder 開發系統級網路應用的完整技術棧。雖然 Messenger 協定已過時,但多執行緒架構、網路列舉、系統整合(托盤、自動啟動、不規則視窗)等技術在現代 Windows 桌面開發中依然適用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved