LoginSignup
0
2

More than 5 years have passed since last update.

Link > C++ Builder XE4 > 自分のNICのMACアドレスを取得する > v0.1-v0.3

Last updated at Posted at 2018-11-12
動作環境
C++ Builder XE4

注意

(追記 2018/11/14)

以下で使用しているZeroMemoryは最適化で吹き飛ぶため、SecureZeroMemory()の使用が推奨されます。

情報

情報感謝です。

実装 > v0.1, v0.2

山本様の実装をXE4用インクルードなどに変更しました (ソース内のv0.2コメント参照)。

Unit1.h
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE で管理されるコンポーネント
    TMemo *Memo1;
    TButton *Button1;
    void __fastcall Button1Click(TObject *Sender);
private:    // ユーザー宣言
    void __fastcall showMacAddress(void);
public:     // ユーザー宣言
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

//#include <tchar.h>
//#include <windows.h>
//#include <assert.h>
//#include <stdio.h>
#include "Nb30.h"
//
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    Memo1->Lines->Clear();
}
//---------------------------------------------------------------------------

/*
v0.2
    - ZeroMemory()を::ZeroMemory()に変更 (グローバルスコープを明示)
    - refactor > 変数名の変更: ローカル変数、ループ変数など
    - assert()の使用停止。代わりにearly returnとTMemo出力へ
    - インクルードファイルを[C++ Builder XE4]用に変更
v0.1
   - 右記からforkした [ http://www.gesource.jp/programming/bcb/83.html ]
     Acknowledgement to Takashi YAMAMOTO (山本隆 様)
*/

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    showMacAddress();
}

//---------------------------------------------------------------------------
// MACアドレス関連処理
//
// { MACアドレス取得用構造体
typedef struct {
    ADAPTER_STATUS status;
    NAME_BUFFER buffer[30];
} ASTAT_t;
// } MACアドレス取得用構造体

void __fastcall TForm1::showMacAddress(void)
{
    NCB ancb; // netbios()にて使用
    LANA_ENUM lenum; // LANA: LAN Adapterのenum

    // NICの数を取得
    ::ZeroMemory(&ancb, sizeof(ancb));
    ancb.ncb_command = NCBENUM;
    ancb.ncb_buffer = (UCHAR*)&lenum;
    ancb.ncb_length = sizeof(lenum);
    Netbios(&ancb);

    //
    for(int idx = 0; idx < lenum.length; idx++) {  // NICごとの処理
        // 1. リセット
        ::ZeroMemory(&ancb, sizeof(ancb));
        ancb.ncb_command = NCBRESET;
        ancb.ncb_lana_num = lenum.lana[idx];
        UCHAR retCode = Netbios(&ancb);
        //assert(retCode == 0);  // >> early returnを代わりに使用
        if (retCode != 0) {
            Memo1->Lines->Add(L"ERROR: Netbios() failed");
            return;
        }

        // 2. MACアドレスの取得
        ASTAT_t adpt; // アダプタ情報取得用バッファ
        //
        ::ZeroMemory(&ancb, sizeof(ancb));
        ancb.ncb_command = NCBASTAT;
        ancb.ncb_lana_num = lenum.lana[idx];
        strcpy(ancb.ncb_callname, "*");
        ancb.ncb_buffer = (UCHAR*)&adpt;
        ancb.ncb_length = sizeof(adpt);
        retCode = Netbios(&ancb);
        //assert(retCode == 0);  // >> early returnを代わりに使用
        if (retCode != 0) {
            Memo1->Lines->Add(L"ERROR: Netbios() failed");
            return;
        }

        // 3. Output to TMemo
        String msg = String().sprintf(L"%02X-%02X-%02X-%02X-%02X-%02X",
        adpt.status.adapter_address[0],
        adpt.status.adapter_address[1],
        adpt.status.adapter_address[2],
        adpt.status.adapter_address[3],
        adpt.status.adapter_address[4],
        adpt.status.adapter_address[5]);
        Memo1->Lines->Add(msg);
    }
}
//---------------------------------------------------------------------------

動作

  • ボタンを押すとNICのMACアドレスがMemo1に表示される
  • 複数のNICを持つ場合、複数のMACアドレスが表示される

関連

実装 v0.3 > assignMacAddress()の追加

プロダクトコードで使えるようにさらに変更した。

Unit1.h
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE で管理されるコンポーネント
    TMemo *Memo1;
    TButton *Button1;
    void __fastcall Button1Click(TObject *Sender);
private:    // ユーザー宣言
    void __fastcall showMacAddress(void);
    bool __fastcall assignMacAddress(TStringList *dstPtr);
public:     // ユーザー宣言
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

//#include <tchar.h>
//#include <windows.h>
//#include <assert.h>
//#include <stdio.h>
#include "Nb30.h"
//
#include <memory>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    Memo1->Lines->Clear();
}
//---------------------------------------------------------------------------

/*
v0.3
    - assignMacAddress()を追加
            - showMacAddress()の処理をこちらに移行
    - unique_ptr()使用
v0.2
    - ZeroMemory()を::ZeroMemory()に変更 (グローバルスコープを明示)
    - refactor > 変数名の変更: ローカル変数、ループ変数など
    - assert()の使用停止。代わりにearly returnとTMemo出力へ
    - インクルードファイルを[C++ Builder XE4]用に変更
v0.1
   - 右記からforkした [ http://www.gesource.jp/programming/bcb/83.html ]
     Acknowledgement to Takashi YAMAMOTO (山本隆 様)
*/

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    showMacAddress();
}

//---------------------------------------------------------------------------
// MACアドレス関連処理
//
// { MACアドレス取得用構造体
typedef struct {
    ADAPTER_STATUS status;
    NAME_BUFFER buffer[30];
} ASTAT_t;
// } MACアドレス取得用構造体

void __fastcall TForm1::showMacAddress(void)
{
    std::unique_ptr<TStringList> wrkSL(new TStringList);
    assignMacAddress(wrkSL.get());

    for(int idx=0; idx < wrkSL->Count; idx++) {
        Memo1->Lines->Add(wrkSL->Strings[idx]);
    }
}

bool __fastcall TForm1::assignMacAddress(TStringList *dstPtr)
{
    if (dstPtr == NULL) {
        return false; // error
    }

    NCB ancb; // netbios()にて使用
    LANA_ENUM lenum; // LANA: LAN Adapterのenum

    // NICの数を取得
    ::ZeroMemory(&ancb, sizeof(ancb));
    ancb.ncb_command = NCBENUM;
    ancb.ncb_buffer = (UCHAR*)&lenum;
    ancb.ncb_length = sizeof(lenum);
    Netbios(&ancb);

    //
    for(int idx = 0; idx < lenum.length; idx++) {  // NICごとの処理
        // 1. リセット
        ::ZeroMemory(&ancb, sizeof(ancb));
        ancb.ncb_command = NCBRESET;
        ancb.ncb_lana_num = lenum.lana[idx];
        UCHAR retCode = Netbios(&ancb);
        //assert(retCode == 0);  // >> early returnを代わりに使用
        if (retCode != 0) {
            //Memo1->Lines->Add(L"ERROR: Netbios() failed");
            return false;
        }

        // 2. MACアドレスの取得
        ASTAT_t adpt; // アダプタ情報取得用バッファ
        //
        ::ZeroMemory(&ancb, sizeof(ancb));
        ancb.ncb_command = NCBASTAT;
        ancb.ncb_lana_num = lenum.lana[idx];
        strcpy(ancb.ncb_callname, "*");
        ancb.ncb_buffer = (UCHAR*)&adpt;
        ancb.ncb_length = sizeof(adpt);
        retCode = Netbios(&ancb);
        //assert(retCode == 0);  // >> early returnを代わりに使用
        if (retCode != 0) {
            //Memo1->Lines->Add(L"ERROR: Netbios() failed");
            return false;
        }

        // 3. Add to list
        String msg = String().sprintf(L"%02X-%02X-%02X-%02X-%02X-%02X",
        adpt.status.adapter_address[0],
        adpt.status.adapter_address[1],
        adpt.status.adapter_address[2],
        adpt.status.adapter_address[3],
        adpt.status.adapter_address[4],
        adpt.status.adapter_address[5]);
        //Memo1->Lines->Add(msg);
        dstPtr->Add(msg);
    }

    return true;
}
//---------------------------------------------------------------------------
0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2