/*
  ICS WMI demo - C++Builder translation of the Delphi demo OverbyteIcsWmiTst1.pas (demos-delphi-vcl),
  ICS V9.8.

  Uses the OverbyteIcsWmi functions (Windows Management Instrumentation) on this or another computer:
  lists any WMI class, runs a single-property query, renames, reboots or powers down the computer,
  lists network adapters and reads or sets their IP addresses, and lists and edits the zones and
  records of a Windows DNS Server. The settings, including the login, are kept in the ICS ini file.

  How this C++ version differs from the Delphi original, apart from syntax:
  - The selected adapter number and name are form members (Delphi: unit-level variables).
  - After a DNS record change, a delete whose record is still there is reported as failed, and a
    failed check is reported as such (Delphi reports either as success, see the handler).
  - List Records is enabled again after a failed listing (Delphi leaves it disabled).
  - The rename confirmation names the computer being renamed, which may be remote (Delphi names
    this PC).
  - A zone type outside the known names is shown as its number (Delphi indexes past the table).
  - The empty Delphi FormShow handler is not converted, and its .dfm binding is removed.
*/

#include <vcl.h>
#pragma hdrstop

#include "OverbyteIcsWmiTst1.h"

#include <memory>

#pragma package(smart_init)
#pragma resource "*.dfm"

TWmiDemoForm *WmiDemoForm;

namespace {

const String SectionMainWindow = "MainWindow";
const String KeyTop = "Top";
const String KeyLeft = "Left";
const String KeyWidth = "Width";
const String KeyHeight = "Height";
const String SectionData = "Data";

// Disables a button and shows the hourglass for its lifetime; restores both on every exit path,
// as the Delphi try/finally does.
class TBusyButton
{
public:
    explicit TBusyButton(TButton *Button) : FButton(Button), FOldCursor(Screen->Cursor)
    {
        FButton->Enabled = false;
        Screen->Cursor = crHourGlass;
    }
    ~TBusyButton()
    {
        FButton->Enabled = true;
        Screen->Cursor = FOldCursor;
    }
    TBusyButton(const TBusyButton &) = delete;
    TBusyButton &operator=(const TBusyButton &) = delete;
private:
    TButton *FButton;
    TCursor FOldCursor;
};

}  // namespace

__fastcall TWmiDemoForm::TWmiDemoForm(TComponent *Owner)
    : TForm(Owner)
{
}

void __fastcall TWmiDemoForm::FormClose(TObject *Sender, TCloseAction &Action)
{
    std::unique_ptr<TIcsIniFile> IniFile(new TIcsIniFile(GetIcsIniFileName(), true));   // PreserveAnsi: Delphi default
    // form positions
    IniFile->WriteInteger(SectionMainWindow, KeyTop, Top);
    IniFile->WriteInteger(SectionMainWindow, KeyLeft, Left);
    IniFile->WriteInteger(SectionMainWindow, KeyWidth, Width);
    IniFile->WriteInteger(SectionMainWindow, KeyHeight, Height);
    IniFile->WriteString(SectionData, "WmiClass_Text", WmiClass->Text);
    IniFile->WriteString(SectionData, "WmiNamespace_Text", WmiNamespace->Text);
    IniFile->WriteString(SectionData, "WmiCommand_Text", WmiCommand->Text);
    IniFile->WriteString(SectionData, "WmiOneProp_Text", WmiOneProp->Text);
    IniFile->WriteString(SectionData, "WmiLogOutput_Checked", WmiLogOutput->Checked ? "True" : "False");
    IniFile->WriteString(SectionData, "NetComputer_Text", NetComputer->Text);
    IniFile->WriteString(SectionData, "NetUserName_Text", NetUserName->Text);
    IniFile->WriteString(SectionData, "NetPassword_Text", NetPassword->Text);
    IniFile->WriteString(SectionData, "DnsRecType_Text", DnsRecType->Text);
    IniFile->WriteString(SectionData, "DnsRecName_Text", DnsRecName->Text);
    IniFile->WriteString(SectionData, "DnsRecData_Text", DnsRecData->Text);
    IniFile->WriteString(SectionData, "DnsRecZone_Text", DnsRecZone->Text);
    IniFile->UpdateFile();
}

void __fastcall TWmiDemoForm::FormCreate(TObject *Sender)
{
    Caption = Caption + IcsVerLitSample;   // common ICS sample caption: version and date
    std::unique_ptr<TIcsIniFile> IniFile(new TIcsIniFile(GetIcsIniFileName(), true));
    // form positions
    Width = IniFile->ReadInteger(SectionMainWindow, KeyWidth, Width);
    Height = IniFile->ReadInteger(SectionMainWindow, KeyHeight, Height);
    Top = IniFile->ReadInteger(SectionMainWindow, KeyTop, (Screen->Height - Height) / 2);
    Left = IniFile->ReadInteger(SectionMainWindow, KeyLeft, (Screen->Width - Width) / 2);
    WmiClass->Text = IniFile->ReadString(SectionData, "WmiClass_Text", WmiClass->Text);
    WmiNamespace->Text = IniFile->ReadString(SectionData, "WmiNamespace_Text", WmiNamespace->Text);
    WmiCommand->Text = IniFile->ReadString(SectionData, "WmiCommand_Text", WmiCommand->Text);
    WmiOneProp->Text = IniFile->ReadString(SectionData, "WmiOneProp_Text", WmiOneProp->Text);
    WmiLogOutput->Checked = IniFile->ReadString(SectionData, "WmiLogOutput_Checked", "False") == "True";
    NetComputer->Text = IniFile->ReadString(SectionData, "NetComputer_Text", IcsGetCompName());
    NetUserName->Text = IniFile->ReadString(SectionData, "NetUserName_Text", "");
    NetPassword->Text = IniFile->ReadString(SectionData, "NetPassword_Text", "");
    DnsRecType->Text = IniFile->ReadString(SectionData, "DnsRecType_Text", "A");
    DnsRecName->Text = IniFile->ReadString(SectionData, "DnsRecName_Text", "");
    DnsRecData->Text = IniFile->ReadString(SectionData, "DnsRecData_Text", "");
    DnsRecZone->Text = IniFile->ReadString(SectionData, "DnsRecZone_Text", "");
    IniFile.reset();
    NewCompName->Text = IcsGetCompName();
    ListNetIPs->Cells[0][0] = "Static IP Address";
    ListNetIPs->Cells[1][0] = "Mask";
    ListNetGateways->Cells[0][0] = "Gateway IP Address";
    ListNetGateways->Cells[1][0] = "Cost Metric";
}

void TWmiDemoForm::AddLog(const String &S)
{
    if (S.Pos(IcsLF) > 0)
        LogWin->Lines->Text = LogWin->Lines->Text + IcsCRLF + S;
    else
        LogWin->Lines->Add(S);
}

bool TWmiDemoForm::Confirm(const String &Text, const String &Title)
{
    return Application->MessageBox(Text.c_str(), Title.c_str(), MB_OKCANCEL) == IDOK;
}

void __fastcall TWmiDemoForm::doExitClick(TObject *Sender)
{
    Close();
}

void __fastcall TWmiDemoForm::doGetClassClick(TObject *Sender)
{
    TBusyButton Busy(doGetClass);
    WmiListView->Items->Clear();
    for (int i = 0; i < WmiListView->Columns->Count; i++)
        WmiListView->Columns->Items[i]->Width = 150;

    // WmiResults[0][Row] is the property name, WmiResults[Instance][Row] its value; row 0 holds the headings.
    T2DimStrArray WmiResults;
    int Instances = 0;
    String ErrStr;
    const int Rows = IcsWmiGetInfoEx(NetComputer->Text, WmiNamespace->Text, NetUserName->Text, NetPassword->Text,
                                     WmiClass->Text, WmiResults, Instances, ErrStr);

    // fill listview
    if (Rows > 0) {
        LabelStatus->Caption = WmiClass->Text + ", instance: " + IntToStr(Instances) + ", Items: " + IntToStr(Rows);
        int Cols = Instances;
        if (Cols >= WmiListView->Columns->Count)
            Cols = WmiListView->Columns->Count - 1;
        for (int j = 0; j <= Cols; j++)
            WmiListView->Columns->Items[j]->Caption = WmiResults[j][0];
        for (int i = 1; i <= Rows; i++) {
            TListItem *Item = WmiListView->Items->Add();
            Item->Caption = WmiResults[0][i];   // name
            for (int j = 1; j <= Cols; j++)
                Item->SubItems->Add(WmiResults[j][i]);   // value
        }
    }
    else if (Rows == -1)
        LabelStatus->Caption = WmiClass->Text + ", Error: " + ErrStr;
    else
        LabelStatus->Caption = WmiClass->Text + ", instances: None";

    // log output as well
    if (WmiLogOutput->Checked) {
        AddLog(LabelStatus->Caption);
        if (Rows > 0) {
            for (int j = 1; j <= Instances; j++) {
                AddLog(WmiClass->Text + ", instance " + IntToStr(j) + " of " + IntToStr(Instances));
                for (int i = 1; i <= Rows; i++)
                    AddLog(WmiResults[0][i] + " = " + WmiResults[j][i]);
                AddLog("");
            }
        }
    }
}

void __fastcall TWmiDemoForm::doGetOnePropClick(TObject *Sender)
{
    doGetOneProp->Enabled = false;
    String Res, Errinfo;
    if (IcsWmiGetOneQ(WmiCommand->Text, WmiOneProp->Text, Res, Errinfo) > 0) {
        AddLog("Command: " + WmiCommand->Text + " ( " + WmiOneProp->Text + ")");
        AddLog("Result: " + Res);
    }
    else
        AddLog("Command Failed: " + Errinfo);
    doGetOneProp->Enabled = true;
}

void __fastcall TWmiDemoForm::doRebootClick(TObject *Sender)
{
    if (!Confirm("Confirm Reboot PC " + NetComputer->Text + " Now", "WMI - Reboot PC"))
        return;
    String Errinfo;
    if (IcsWmiCloseWin(NetComputer->Text, NetUserName->Text, NetPassword->Text, true, Errinfo) == 0)
        Errinfo = "PC Reboot Accepted";
    AddLog(Errinfo);
}

void __fastcall TWmiDemoForm::doCloseDownClick(TObject *Sender)
{
    if (!Confirm("Confirm Power Down PC " + NetComputer->Text + " Now", "WMI - Power Down PC"))
        return;
    String Errinfo;
    if (IcsWmiCloseWin(NetComputer->Text, NetUserName->Text, NetPassword->Text, false, Errinfo) == 0)
        Errinfo = "PC Power Down Accepted";
    AddLog(Errinfo);
}

void __fastcall TWmiDemoForm::doRenameCompClick(TObject *Sender)
{
    if (NewCompName->Text == IcsGetCompName())
        return;
    if (NewCompName->Text == "")
        return;
    // Delphi says "Rename This PC from <this PC's name>", but the rename goes to NetComputer.
    if (!Confirm("Confirm Rename Computer " + NetComputer->Text + " to " + NewCompName->Text,
                 "WMI - Rename Computer"))
        return;
    // note, ignore domain controller login
    String Errinfo;
    const int Res = IcsWmiRenameComp(NetComputer->Text, NetUserName->Text, NetPassword->Text, NewCompName->Text,
                                     "", "", Errinfo);
    if (Res == 0)
        AddLog("Rename Computer OK, Must Reboot Now");
    else
        AddLog("Rename Computer Failed: " + Errinfo);
}

void __fastcall TWmiDemoForm::LogWinDblClick(TObject *Sender)
{
    LogWin->Lines->Clear();
}

void __fastcall TWmiDemoForm::doGetAdaptorsClick(TObject *Sender)
{
    doGetAdaptors->Enabled = false;
    ListNetAdaptors->Items->Clear();
    T2DimStrArray AdapterList;   // per adapter: index, name, connection name
    String Errinfo;
    const int Tot = IcsWmiListAdaptors(NetComputer->Text, NetUserName->Text, NetPassword->Text, AdapterList,
                                       Errinfo, false);   // false: all adapters, not only enabled ones
    if (Tot == 0) {
        AddLog("Can Not Find Any Network Adapters: " + Errinfo);
        doGetAdaptors->Enabled = true;
        return;
    }
    for (int i = 0; i < Tot; i++) {
        TListItem *Item = ListNetAdaptors->Items->Add();
        Item->Caption = AdapterList[i][0];
        Item->SubItems->Add(AdapterList[i][1]);
        Item->SubItems->Add(AdapterList[i][2]);
    }
    AddLog("Listed " + IntToStr(Tot) + " Network Adapters");
    doGetAdaptors->Enabled = true;
}

void TWmiDemoForm::ClearGrid(TStringGrid *MyGrid)
{
    for (int Row = 1; Row < MyGrid->RowCount; Row++) {
        for (int Col = 0; Col < MyGrid->ColCount; Col++)
            MyGrid->Cells[Col][Row] = "";
    }
}

void __fastcall TWmiDemoForm::DnsRecDataDblClick(TObject *Sender)
{
    DnsRecData->Text = "";
}

void __fastcall TWmiDemoForm::doGetAddressesClick(TObject *Sender)
{
    const int Idx = ListNetAdaptors->ItemIndex;
    if (Idx < 0) {
        AddLog("Must Select a Network Adapter First");
        return;
    }
    FAdptNr = Icsatoi(ListNetAdaptors->Items->Item[Idx]->Caption);
    FAdptName = ListNetAdaptors->Items->Item[Idx]->SubItems->Strings[0];
    ClearGrid(ListNetIPs);
    ClearGrid(ListNetGateways);
    bool DhcpFlag = false;
    TWmiAddrs WmiAddrs;
    TWmiGateways WmiGateways;
    String Errinfo;
    const int TotAddr = IcsWmiGetAddresses(NetComputer->Text, NetUserName->Text, NetPassword->Text, FAdptNr,
                                           DhcpFlag, WmiAddrs, WmiGateways, Errinfo);
    const int TotGate = WmiGateways.Length;
    NetUseDhcp->Checked = DhcpFlag;
    if (DhcpFlag) {
        ListNetIPs->Cells[0][1] = "DHCP";
        AddLog(FAdptName + ": Set for DHCP");
        return;
    }
    if (TotAddr <= 0) {
        AddLog(FAdptName + ": Can Not Find Any IP Addresses: " + Errinfo);
        return;
    }
    AddLog(FAdptName + ": Found " + IntToStr(TotAddr) + " IP Addresses");
    ListNetIPs->RowCount = TotAddr + 7;   // spare rows for new addresses
    for (int i = 0; i < TotAddr; i++) {
        ListNetIPs->Cells[0][i + 1] = WmiAddrs[i].IpAddr;
        ListNetIPs->Cells[1][i + 1] = WmiAddrs[i].Mask;
        AddLog("Address: " + WmiAddrs[i].IpAddr + ", Mask: " + WmiAddrs[i].Mask);
    }
    if (TotGate > 0) {
        ListNetGateways->RowCount = TotGate + 3;
        AddLog(FAdptName + ": Found " + IntToStr(TotGate) + " Gateways");
        for (int i = 0; i < TotGate; i++) {
            ListNetGateways->Cells[0][i + 1] = WmiGateways[i].IpAddr;
            ListNetGateways->Cells[1][i + 1] = WmiGateways[i].Cost;
            AddLog("Gateway: " + WmiGateways[i].IpAddr + ", Cost: " + WmiGateways[i].Cost);
        }
    }
}

void __fastcall TWmiDemoForm::ListNetAdaptorsDblClick(TObject *Sender)
{
    doGetAddressesClick(this);
}

void __fastcall TWmiDemoForm::doSetAddressesClick(TObject *Sender)
{
    if (FAdptNr < 0 || (ListNetIPs->Cells[0][1] == "" && !NetUseDhcp->Checked)) {
        AddLog("Must Select a Network Adapter and IP Addresses First");
        return;
    }
    if (!Confirm("Confirm Update " + FAdptName + " Network Adaptor IP Addresses", "WMI - Update RIP Addresses"))
        return;
    TWmiAddrs WmiAddrs;
    TWmiGateways WmiGateways;
    int TotAddr = 0;
    int TotGate = 0;
    doSetAddresses->Enabled = false;
    if (!NetUseDhcp->Checked) {
        // only rows with both columns filled in are used
        WmiAddrs.Length = ListNetIPs->RowCount;
        WmiGateways.Length = ListNetGateways->RowCount;
        for (int Row = 1; Row < ListNetIPs->RowCount; Row++) {
            WmiAddrs[TotAddr].IpAddr = IcsTrim(ListNetIPs->Cells[0][Row]);
            WmiAddrs[TotAddr].Mask = IcsTrim(ListNetIPs->Cells[1][Row]);
            if (WmiAddrs[TotAddr].IpAddr != "" && WmiAddrs[TotAddr].Mask != "")
                TotAddr++;
        }
        for (int Row = 1; Row < ListNetGateways->RowCount; Row++) {
            WmiGateways[TotGate].IpAddr = IcsTrim(ListNetGateways->Cells[0][Row]);
            WmiGateways[TotGate].Cost = IcsTrim(ListNetGateways->Cells[1][Row]);
            if (WmiGateways[TotGate].IpAddr != "" && WmiGateways[TotGate].Cost != "")
                TotGate++;
        }
        if (TotAddr == 0) {
            AddLog("Must Specify IP Addresses and Masks First");
            doSetAddresses->Enabled = true;
            return;
        }
    }
    WmiAddrs.Length = TotAddr;
    WmiGateways.Length = TotGate;
    String Errinfo;
    const unsigned Res = IcsWmiSetAddresses(NetComputer->Text, NetUserName->Text, NetPassword->Text, FAdptNr,
                                            NetUseDhcp->Checked, WmiAddrs, WmiGateways, Errinfo);
    if (Errinfo != "")
        AddLog(FAdptName + ": Set IP Addressses Failed: " + Errinfo);
    else if (Res > 0x80000000u)   // an HRESULT-style error code reads better in hex
        AddLog(FAdptName + ": Set IP Addressses WMI Result: $" + IntToHex(static_cast<__int64>(Res), 8));
    else
        AddLog(FAdptName + ": Set IP Addressses WMI Result: " + IntToStr(static_cast<__int64>(Res)));
    doSetAddresses->Enabled = true;
}

void __fastcall TWmiDemoForm::doCheckDnsSrvClick(TObject *Sender)
{
    doCheckDnsSrv->Enabled = false;
    String IpAddrs, Errinfo;
    const String SrvName = IcsWmiChkDnsSrv(NetComputer->Text, NetUserName->Text, NetPassword->Text, IpAddrs, Errinfo);
    doCheckDnsSrv->Enabled = true;
    if (SrvName == "")
        LabelDnsStatus->Caption = "Can Not Find DNS Server: " + Errinfo;
    else
        LabelDnsStatus->Caption = "DNS Server Name: " + SrvName + ", IP Addresses: " + IpAddrs;
    AddLog(LabelDnsStatus->Caption);
}

void TWmiDemoForm::SetDnsRecButtons(bool Enable)
{
    doDnsRecUpd->Enabled = Enable;
    doDnsRecAdd->Enabled = Enable;
    doDnsRecDel->Enabled = Enable;
}

void __fastcall TWmiDemoForm::doListZonesClick(TObject *Sender)
{
    SetDnsRecButtons(false);
    doListZones->Enabled = false;
    ListZones->Items->Clear();
    TWmiDnsZones WmiDnsZones;
    String Errinfo;
    const int Tot = IcsWmiListDnsZones(NetComputer->Text, NetUserName->Text, NetPassword->Text, WmiDnsZones, Errinfo);
    if (Tot == 0) {
        LabelDnsStatus->Caption = "Can Not Find Any DNS Zones: " + Errinfo;
        AddLog(LabelDnsStatus->Caption);
        doListZones->Enabled = true;
        return;
    }
    LabelDnsStatus->Caption = "Total Domain Zones " + IntToStr(Tot);
    AddLog(LabelDnsStatus->Caption);
    for (int i = 0; i < Tot; i++) {
        const int ZoneType = WmiDnsZones[i].ZoneType;
        const String ZType = (ZoneType >= 0 && ZoneType < static_cast<int>(ZoneTypeLits.size()))
                                 ? ZoneTypeLits[ZoneType]
                                 : IntToStr(ZoneType);   // Delphi indexes the table unchecked
        const String ZRev = WmiDnsZones[i].Reverse ? "Reverse" : "Forward";
        TListItem *Item = ListZones->Items->Add();
        Item->Caption = WmiDnsZones[i].ZoneName;
        Item->SubItems->Add(ZType);
        Item->SubItems->Add(ZRev);
        AddLog("Zone Name: " + WmiDnsZones[i].ZoneName + ", Type: " + ZType + ": " + ZRev);
    }
    doListZones->Enabled = true;
}

void __fastcall TWmiDemoForm::ListZonesDblClick(TObject *Sender)
{
    doListRecsClick(this);
}

void __fastcall TWmiDemoForm::doListRecsClick(TObject *Sender)
{
    SetDnsRecButtons(false);
    const int Idx = ListZones->ItemIndex;
    if (Idx < 0 && DnsRecZone->Text == "") {
        LabelDnsStatus->Caption = "Must Select a DNS Zone First";
        AddLog(LabelDnsStatus->Caption);
        return;
    }
    if (Idx >= 0)
        DnsRecZone->Text = ListZones->Items->Item[Idx]->Caption;
    doListRecs->Enabled = false;
    ListRecords->Items->Clear();
    TWmiDnsRecs WmiDnsRecs;
    String Errinfo;
    const int Tot = IcsWmiListDnsRecs(NetComputer->Text, NetUserName->Text, NetPassword->Text, DnsRecZone->Text, "",
                                      WmiDnsRecs, Errinfo);
    if (Errinfo != "") {
        LabelDnsStatus->Caption = "Get DNS Records Failed: " + Errinfo;
        AddLog(LabelDnsStatus->Caption);
        doListRecs->Enabled = true;   // Delphi leaves List Records disabled here
        return;
    }
    if (Tot == 0) {
        LabelDnsStatus->Caption = "Can Not Find Any DNS Records for Zone: " + DnsRecZone->Text;
        AddLog(LabelDnsStatus->Caption);
        doListRecs->Enabled = true;
        return;
    }
    LabelDnsStatus->Caption = "Total Domain Zone Records " + IntToStr(Tot);
    AddLog(LabelDnsStatus->Caption);
    for (int i = 0; i < Tot; i++) {
        TListItem *Item = ListRecords->Items->Add();
        Item->Caption = WmiDnsRecs[i].HostName;
        Item->SubItems->Add(WmiDnsRecs[i].RecType);
        Item->SubItems->Add(WmiDnsRecs[i].RecData);
        Item->SubItems->Add(IntToStr(WmiDnsRecs[i].Instance));
        Item->SubItems->Add(WmiDnsRecs[i].TextRep);
        AddLog("Host Name: " + WmiDnsRecs[i].HostName + ", Type: " + WmiDnsRecs[i].RecType + ", Data: " +
               WmiDnsRecs[i].RecData + ", Instance " + IntToStr(WmiDnsRecs[i].Instance));
    }
    doListRecs->Enabled = true;
    doDnsRecAdd->Enabled = true;
}

// Shared by the Update, Add and Delete buttons; Sender says which.
void __fastcall TWmiDemoForm::doDnsUpdateRec(TObject *Sender)
{
    TWmiEdtFunc WmiEdtFunc;
    if (Sender == doDnsRecUpd)
        WmiEdtFunc = EdtFuncUpd;
    else if (Sender == doDnsRecAdd)
        WmiEdtFunc = EdtFuncAdd;
    else if (Sender == doDnsRecDel)
        WmiEdtFunc = EdtFuncDel;
    else
        return;
    if (DnsRecZone->Text == "") {
        AddLog("Must Select a DNS Zone First");
        return;
    }
    SetDnsRecButtons(false);
    LabelDnsStatus->Caption = "(Updating DNS Server)";
    AddLog(LabelDnsStatus->Caption);
    TWmiDnsRec WmiDnsRec;
    WmiDnsRec.RecType = DnsRecType->Text;
    WmiDnsRec.HostName = DnsRecName->Text;
    WmiDnsRec.RecData = Trim(DnsRecData->Text);
    String Errinfo;
    const int Res = IcsWmiUpdDnsRec(NetComputer->Text, NetUserName->Text, NetPassword->Text, DnsRecZone->Text,
                                    WmiDnsRec, WmiEdtFunc, Errinfo);
    if (Res == 0) {
        // check it worked: IcsWmiChkDnsRec is true when the record now exists. Delphi reports a delete
        // that left the record as "Updated OK", and a failed check after a delete as "Deleted OK".
        String CheckErr;
        const bool Found = IcsWmiChkDnsRec(NetComputer->Text, NetUserName->Text, NetPassword->Text,
                                           DnsRecZone->Text, WmiDnsRec, CheckErr);
        if (CheckErr != "")
            Errinfo = "DNS Resource Record Changed, Could Not Check Result: " + CheckErr;
        else if (WmiEdtFunc == EdtFuncDel)
            Errinfo = Found ? "DNS Resource Record Delete Failed: Record Still Exists: " + DnsRecZone->Text + ": " +
                                  WmiDnsRec.HostName
                            : "DNS Resource Record Deleted OK: " + DnsRecZone->Text + ": " + WmiDnsRec.HostName;
        else
            Errinfo = Found ? "DNS Resource Record Updated OK: " + DnsRecZone->Text + ": " + WmiDnsRec.RecData
                            : "DNS Resource Record Failed: Can Not Find New RR Records: " + WmiDnsRec.RecData;
        doListRecsClick(this);
    }
    else
        Errinfo = "Set DNS Resource Record Failed: " + Errinfo + " for " + DnsRecZone->Text;
    LabelDnsStatus->Caption = Errinfo;
    AddLog(Errinfo);
    SetDnsRecButtons(true);
}

void __fastcall TWmiDemoForm::ListRecordsClick(TObject *Sender)
{
    const int Idx = ListRecords->ItemIndex;
    if (Idx < 0)
        return;
    DnsRecName->Text = ListRecords->Items->Item[Idx]->Caption;
    DnsRecType->Text = ListRecords->Items->Item[Idx]->SubItems->Strings[0];
    DnsRecData->Text = ListRecords->Items->Item[Idx]->SubItems->Strings[1];
    doDnsRecUpd->Enabled = true;
    doDnsRecDel->Enabled = true;
}

void __fastcall TWmiDemoForm::ListRecordsDblClick(TObject *Sender)
{
    const int Idx = ListRecords->ItemIndex;
    if (Idx < 0)
        return;
    TWmiDnsRec WmiDnsRec;
    WmiDnsRec.HostName = ListRecords->Items->Item[Idx]->Caption;
    WmiDnsRec.RecType = ListRecords->Items->Item[Idx]->SubItems->Strings[0];
    WmiDnsRec.RecData = ListRecords->Items->Item[Idx]->SubItems->Strings[1];
    if (!Confirm("Confirm Delete DNS  " + WmiDnsRec.RecType + " record " + WmiDnsRec.HostName, "WMI - DNS Server"))
        return;
    String Errinfo;
    const int Res = IcsWmiUpdDnsRec(NetComputer->Text, NetUserName->Text, NetPassword->Text, DnsRecZone->Text,
                                    WmiDnsRec, EdtFuncDel, Errinfo);
    if (Res == 0) {
        doListRecsClick(this);
        Errinfo = "DNS Resource Record Deleted OK: " + DnsRecZone->Text + ": " + WmiDnsRec.HostName;
    }
    else
        Errinfo = DnsRecZone->Text + ": Set DNS Resource Record Failed: " + Errinfo;
    LabelDnsStatus->Caption = Errinfo;
    AddLog(Errinfo);
}
