新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机技术与应用『 C/C++编程思想 』 → 枚举本地-远程NT系统进程&网卡MAC地址获取[分享] 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 5878 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 枚举本地-远程NT系统进程&网卡MAC地址获取[分享] 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     一分之千 帅哥哟,离线,有人找我吗?射手座1984-11-30
      
      
      威望:1
      等级:研一(随老板参加了WWW大会还和Tim Berners-Lee合了影^_^)
      文章:632
      积分:4379
      门派:XML.ORG.CN
      注册:2006/12/31

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给一分之千发送一个短消息 把一分之千加入好友 查看一分之千的个人资料 搜索一分之千在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看一分之千的博客楼主
    发贴心情 枚举本地-远程NT系统进程&网卡MAC地址获取[分享]

    Windows2000中有个工具taskmgr.exe就可以比较详细的查看当前系统进程信息,但是那是Windows GUI程序,有时候是不是觉得命令行下的东西更方便呢?其实已经有不少命令行下的枚举系统进程的工具了,M$的Resource Kit中好象也有,但去了解他们是怎么实现的,自己动手做出来,是不是更有意思呢:)

      进程通常被定义为一个正在运行的程序的实例,它由两部分组成:

      <1>操作系统用来管理进程的内核对象。内核对象也是系统用来存放关于进程的统计信息的地方。

      <2>地址空间。它包含所有可执行模块或DLL模块的代码和数据。它还包含动态内存分配的空间,如线程的堆栈和堆分配空间。

      枚举系统进程的实现方法大概有四种,其中有一种可以用来枚举远程NT系统的进程,前提是有远程系统的管理员权限。

    <<第一部分:调用PSAPI函数枚举系统进程>>

      M$的Windows NT开发小组开发了自己Process Status函数,包含在PSAPI.DLL文件中,这些函数只能在高于NT4.0以后的版本中使用。PSAPI一共有14个函数[实际PSAPI.DLL输出函数有19个,但其中有5个函数有两个版本,分别是ANSI和Unicode版本],通过调用这些函数,我们可以很方便的取得系统进程的所有信息,例如进程名、进程ID、父进程ID、进程优先级、映射到进程空间的模块列表等等。为了方便起见,以下的例子程序只获取进程的名字和ID。

      简单的程序如下:

    /*************************************************************************

    Module:ps.c

    说明:调用PSAPI函数枚举系统进程名和ID,Only for NT/2000

    *************************************************************************/
    #include "psapi.h"
    #pragma comment(lib,"psapi.lib")
    void PrintProcessNameAndID( DWORD processID )
    {
      char szProcessName[MAX_PATH] = "unknown";
      //取得进程的句柄
      HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
                      PROCESS_VM_READ,
                      FALSE, processID );
      //取得进程名称
      if ( hProcess )
      {
        HMODULE hMod;
        DWORD cbNeeded;
        if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) )
          GetModuleBaseName( hProcess, hMod, szProcessName,
    sizeof(szProcessName) );
      }
      //回显进程名称和ID
      printf( "\n%-20s%-20d", szProcessName, processID );
      CloseHandle( hProcess );
    }

    void main( )
    {
      DWORD aProcesses[1024], cbNeeded, cProcesses;
      unsigned int i;
      //枚举系统进程ID列表
      if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
        return;
      // Calculate how many process identifiers were returned.
      //计算进程数量
      cProcesses = cbNeeded / sizeof(DWORD);
      // 输出每个进程的名称和ID
      for ( i = 0; i < cProcesses; i++ )
        PrintProcessNameAndID( aProcesses[i] );

      return;
    }


    <<第二部分:调用ToolHelp API枚举本地系统进程>>
      在第一部分提到的PSAPI函数只能枚举NT系统的进程,在Windows9x环境下我们可以通过调用ToolHelp API函数来达到枚举系统进程的目的。M$的Windows NT开发小组因为不喜欢ToolHelp函数,所以没有将这些函数添加给Windows NT,所以他们开发了自己的Process Status函数,就是第一部分提到的PSAPI了。但是后来M$已经将ToolHelp函数添加给了Windows 2000。ToolHelp共有12个函数,通过调用这些函数可以方面的取得本地系统进程的详细信息,以下这个简单的例子只调用了三个函数,获取我们所需要系统进程名字和进程ID。程序如下:
    /**********************************************************************

    Module:ps.c

    说明:调用ToolHelp函数枚举本地系统进程名和ID,Only for 9x/2000

    **********************************************************************/
    int main()
    {
      HANDLE     hProcessSnap = NULL;
      PROCESSENTRY32 pe32   = {0};
      hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
      if (hProcessSnap == (HANDLE)-1)
      {
        printf("\nCreateToolhelp32Snapshot() failed:%d",GetLastError());
      return 1;
    }

      pe32.dwSize = sizeof(PROCESSENTRY32);
      printf("\nProcessName     ProcessID");
      if (Process32First(hProcessSnap, &pe32))
      {
        do
        {
    printf("\n%-20s%d",pe32.szExeFile,pe32.th32ProcessID);
        }while (Process32Next(hProcessSnap, &pe32));
      }
      else
      {
        printf("\nProcess32Firstt() failed:%d",GetLastError());
      }

      CloseHandle (hProcessSnap);

    return 0;
    }


    <<第三部分:调用NTDLL.DLL中未公开API枚举本地系统进程>>

       第一部分和第二部分说的是调用MS公开的API来枚举系统进程,在NTDLL.DLL中其实有一个未公开API,也可以用来枚举系统进程。此方法是从别处看来的,我可没这本事自己发现哦,出处记不清楚了,好像是pwdump2 中的源代码中的一部分吧。
        OK!那个未公开API就是NtQuerySystemInformation,使用方法如下:
    ////////////////////////////////////////////////////////////////////////////////
    typedef unsigned long NTSTATUS;
    typedef unsigned short USHORT;
    typedef unsigned long ULONG;
    typedef unsigned long DWORD;
    typedef long LONG;
    typedef __int64 LONGLONG;
    typedef struct {
      USHORT Length;
      USHORT MaxLen;
      USHORT *Buffer;
    } UNICODE_STRING;


    struct process_info {
      ULONG NextEntryDelta;
      ULONG ThreadCount;
      ULONG Reserved1[6];
      LARGE_INTEGER CreateTime;
      LARGE_INTEGER UserTime;
      LARGE_INTEGER KernelTime;
      UNICODE_STRING ProcessName;
      ULONG BasePriority;
      ULONG ProcessId;
    };


    typedef NTSTATUS (__stdcall *NtQuerySystemInformation1)(
        IN ULONG SysInfoClass,
    IN OUT PVOID SystemInformation,
        IN ULONG SystemInformationLength,
        OUT PULONG RetLen
            );

    int main()
    {
      HINSTANCE hNtDll;
      NtQuerySystemInformation1 NtQuerySystemInformation;
      NTSTATUS rc;
      ULONG ulNeed = 0;
      void *buf = NULL;
      size_t len = 0;
      struct process_info *p ;
      int done;

      hNtDll = LoadLibrary ("NTDLL");
      if (!hNtDll)
        return 0;
      NtQuerySystemInformation = (NtQuerySystemInformation1)GetProcAddress (hNtDll, "NtQuerySystemInformation");
        if (!NtQuerySystemInformation)
          return 0;
      do {
        len += 0x1000;
        buf = realloc (buf, len);
        if (!buf)
          return 0;
        rc = NtQuerySystemInformation (5, buf, len, &ulNeed);
      } while (rc == 0xc0000004); // STATUS_INFO_LEN_MISMATCH

      if (rc <0) {
        free (buf);
        return 0;
      }

    printf("\nProcessName     ProcessID");
      p = (struct process_info *)buf;
      done = 0;

      while (!done) {
        if ((p->ProcessName.Buffer != 0))
        {
          printf("\n%-20S%d",p->ProcessName.Buffer,p->ProcessId);
        }
        done = p->NextEntryDelta == 0;
        p = (struct process_info *)(((char *)p) + p->NextEntryDelta);
      }
      free (buf);
      FreeLibrary (hNtDll);
      return 0;
    }


    <<第四部分:从PDH中取得本地/远程系统进程信息>>


      前面说的三种方法都只能枚举本地的系统进程,如何枚举远程系统的进程呢?目前我只知道从PDH中取得进程信息。

      OK!我先简单的说说PDH是什么东西,hoho~难的偶也不会。PDH是英文Performance Data Helper的缩写,Windows NT一直在更新这个称为Performance Data的数据库,这个数据库包含了大量的信息,例如CPU使用率,内存使用率,系统进程信息等等一大堆有用的信息,可以通过注册表函数来访问。注意哦,Windows 9x中并没有配置这个数据库。但是,这个数据库中的信息布局很复杂,很多人并不愿意使用它,包括我。而且刚开始的时候,它也没有自己特定的函数,只能通过现有的注册表函数来操作。后来,为了使该数据库的使用变得容易,MS开发了一组Performance Data Helper函数,包含在PDH.DLL文件中。

    Windows 2000默认是允许远程注册表操作的,所以我们就可以通过连接远程系统的注册表,从它的PDH中取得我们所需要的系统进程信息了,当然这需要远程系统的Admin权限。

    OK!我们下面所举的例子是直接利用注册表函数来从本地/远程系统的PDH数据库中取得我们所需要的数据的,我们并没有利用PDH API。

        程序代码如下:

    /**************************************************************************

    Module:ps.c

    Author:mikeblas@nwlink.com

    Modify:ey4s

    Http://www.ey4s.org

    Date:2001/6/23

    **************************************************************************/
    #define INITIAL_SIZE    51200
    #define EXTEND_SIZE     12800
    #define REGKEY_PERF     "software\\microsoft\\windows nt\\currentversion\\perflib"
    #define REGSUBKEY_COUNTERS "Counters"
    #define PROCESS_COUNTER   "process"
    #define PROCESSID_COUNTER  "id process"
    #define UNKNOWN_TASK    "unknown"
    #define MaxProcessNum      52//最大进程数量
    #pragma comment(lib,"mpr.lib")

    typedef struct ProcessInfo
    {
    char ProcessName[128];
    DWORD dwProcessID;
    }pi;

    void banner();
    int ConnIPC(char *,char *,char *);
    DWORD GetProcessInfo(pi *,char *,char *,char *);

    int main(int argc,char **argv)
    {
    int i,iRet;
    pi TaskList[MaxProcessNum];
    banner();
    if(argc==1)
    {
    iRet=GetProcessInfo(TaskList,NULL,NULL,NULL);
      printf("\nProcess Info for [LOCAL]:");
    }
    else if(argc==4)
    {
    iRet=GetProcessInfo(TaskList,argv[1],argv[2],argv[3]);
    printf("\nProcess Info for [%s]:",argv[1]);
    }

    else

    {

    printf("\nUsage:%s ",argv[0]);

    return 1;

    }

    if(iRet>0)   

    for(i=0,printf("\nProcessName     ProcessID");

    i
    printf("\n%-20s %d",TaskList[i].ProcessName,TaskList[i].dwProcessID),i++); 

      return 0;

    }


    DWORD GetProcessInfo(pi *ProList,char *ip,char *user,char *pass)

    {

      DWORD rc,dwType,dwSize,i,dwProcessIdTitle,dwProcessIdCounter,dwRet=-1;

      HKEY             hKeyNames;

      LPSTR            buf = NULL,p,p2;

      CHAR             szSubKey[1024],szProcessName[MAX_PATH];

      PPERF_DATA_BLOCK       pPerf;

      PPERF_OBJECT_TYPE      pObj;

      PPERF_INSTANCE_DEFINITION  pInst;

      PPERF_COUNTER_BLOCK     pCounter;

      PPERF_COUNTER_DEFINITION   pCounterDef;

      HKEY      ghPerfKey =NULL, // get perf data from this key

    ghMachineKey = NULL; // get title index from this key

      BOOL bRemote=FALSE;

      // Look for the list of counters. Always use the neutral
      // English version, regardless of the local language. We
      // are looking for some particular keys, and we are always
      // going to do our looking in English. We are not going
      // to show the user the counter names, so there is no need
      // to go find the corresponding name in the local language.

        __try
        {
           if((ip)&&(user)&&(pass))
           {
               if(ConnIPC(ip,user,pass)!=0)
               {
                  printf("\nConnect to %s failed.",ip);
                  __leave;
               }
               else
                  bRemote=TRUE;
          }
           //连接本地or远程注册表
           if(RegConnectRegistry(ip,HKEY_PERFORMANCE_DATA,
               &ghPerfKey)!=ERROR_SUCCESS)
           {
               printf("\nRegConnectRegistry() 1 failed:%d",GetLastError());
               __leave;
           }
       if(RegConnectRegistry(ip,HKEY_LOCAL_MACHINE,&ghMachineKey)!=ERROR_SUCCESS)
           {
               printf("\nRegConnectRegistry() 2 failed:%d",GetLastError());
               __leave;
           }

    sprintf( szSubKey, "%s\\%03x", REGKEY_PERF,MAKELANGID( LANG_ENGLISH, SUBLANG_NEUTRAL));
    if(RegOpenKeyEx(ghMachineKey,szSubKey,0,KEY_READ,&hKeyNames)!=ERROR_SUCCESS)
               __leave;

           // 从counter names取得需要的缓冲区大小
    if(RegQueryValueEx(hKeyNames,REGSUBKEY_COUNTERS,NULL,&dwType,NULL,&dwSize)!= ERROR_SUCCESS)
      __leave;
           //分配内存
           buf = (LPSTR) malloc( dwSize );
           if (buf == NULL)
               __leave;
           memset( buf, 0, dwSize );
           // read the counter names from the registry
    if(RegQueryValueEx(ghPerfKey,REGSUBKEY_COUNTERS,NULL,&dwType,(LPBYTE) buf,&dwSize)!= ERROR_SUCCESS)
               __leave;
           // now loop thru the counter names looking for the following counters:
           //   1. "Process"     process name
           //   2. "ID Process"    process id

           // the buffer contains multiple null terminated strings and then
           // finally null terminated at the end. the strings are in pairs of
           // counter number and counter name.

           p = buf;
           while (*p)
           {
               if (p>buf)
                 for( p2=p-2; isdigit(*p2); p2--) ;
               if (stricmp(p, PROCESS_COUNTER) == 0)
               {
                  // look backwards for the counter number
                 for( p2=p-2; isdigit(*p2); p2--) ;
                  strcpy( szSubKey, p2+1 );
               }
               else if (stricmp(p, PROCESSID_COUNTER) == 0)
               {
                  // look backwards for the counter number
                 for( p2=p-2; isdigit(*p2); p2--) ;
                  dwProcessIdTitle = atol( p2+1 );
               }
               // next string
               p += (strlen(p) + 1);
           }
           // free the counter names buffer
           free( buf );
           // allocate the initial buffer for the performance data
           dwSize = INITIAL_SIZE;
           buf = (LPSTR) malloc( dwSize );

           while (TRUE)
           {
               if (buf == NULL)
                  __leave;
               memset( buf, 0, dwSize );
               rc=RegQueryValueEx(ghPerfKey,szSubKey,NULL,&dwType,(LPBYTE) buf,&dwSize);
               pPerf = (PPERF_DATA_BLOCK) buf;
               // check for success and valid perf data block signature
               if ((rc == ERROR_SUCCESS) &&
                     (dwSize > 0) &&
                     (pPerf)->Signature[0] == (WCHAR)'P' &&
                     (pPerf)->Signature[1] == (WCHAR)'E' &&
                     (pPerf)->Signature[2] == (WCHAR)'R' &&
                     (pPerf)->Signature[3] == (WCHAR)'F' )
                  break;
               // if buffer is not big enough, reallocate and try again
               if (rc == ERROR_MORE_DATA)
               {
                  dwSize += EXTEND_SIZE;
                  buf = (LPSTR) realloc( buf, dwSize );
               }
               else __leave;
           }
           // set the perf_object_type pointer
           pObj = (PPERF_OBJECT_TYPE) ((DWORD)pPerf + pPerf->HeaderLength);
           //loop thru the performance counter definition records looking
           //for the process id counter and then save its offset

       pCounterDef = (PPERF_COUNTER_DEFINITION) ((DWORD)pObj + pObj->HeaderLength);

        for (i=0; i<(DWORD)pObj->NumCounters; i++)
           {
               if (pCounterDef->CounterNameTitleIndex == dwProcessIdTitle)
               {
                  dwProcessIdCounter = pCounterDef->CounterOffset;
                  break;
               }
               pCounterDef++;
           }

        pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pObj + pObj->DefinitionLength);
           // loop thru the performance instance data extracting each process name
           // and process id
          for (i=0; i < (DWORD)pObj->NumInstances-1 && i
           {
               // pointer to the process name
               p = (LPSTR) ((DWORD)pInst + pInst->NameOffset);
               // convert it to ascii
               rc = WideCharToMultiByte( CP_ACP,0,(LPCWSTR)p,-1,szProcessName,sizeof(szProcessName),NULL,NULL);

               // if we cant convert the string then use a default value
               if (!rc) strcpy( ProList[i].ProcessName, UNKNOWN_TASK );
               else strncpy(ProList[i].ProcessName, szProcessName,sizeof(ProList[i].ProcessName)-1);
               // get the process id
           pCounter = (PPERF_COUNTER_BLOCK) ((DWORD)pInst + pInst->ByteLength);
      ProList[i].dwProcessID = *((LPDWORD) ((DWORD)pCounter + dwProcessIdCounter));
               // next process

      pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pCounter + pCounter->ByteLength);

           }

           dwRet=i;

        }//end of try

        __finally

        {

           if (buf) free( buf );

           RegCloseKey( hKeyNames );

           RegCloseKey( HKEY_PERFORMANCE_DATA );

           if(bRemote)
           {
               char tmp[52],tmp2[96];

               strncpy(tmp,ip,sizeof(tmp)-1);

               wsprintf(tmp2,"\\\\%s\\ipc$",tmp);

               WNetCancelConnection2(tmp2,CONNECT_UPDATE_PROFILE,TRUE);
           }

        }
        return dwRet;
    }

    ////////////////////////////////////////////////////////////////////////////////
    int ConnIPC(char *RemoteName,char *User,char *Pass)

    {
        NETRESOURCE nr;
        char RN[50]="\\\\";

        strncat(RN,RemoteName,sizeof(RN)-11);
        strcat(RN,"\\ipc$");
        nr.dwType=RESOURCETYPE_ANY;
        nr.lpLocalName=NULL;
        nr.lpRemoteName=RN;
        nr.lpProvider=NULL;

        if(WNetAddConnection2(&nr,Pass,User,FALSE)==NO_ERROR)
           return 0;
        else
           return 1;
    }

    ////////////////////////////////////////////////////////////////////////////////

    void banner()

    {
        printf("\nPsList ==>Local and Remote process list"
    "\nPower by ey4s"
    "\nhttp://www.ey4s.org"
    "\n2001/6/22\n");
    }

      程序在Windows2000、VC++6.0环境下编译,运行良好。注意哦,远程机器要允许IPC连接和远程操作注册表才可以哦,并且需要Admin权限.


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    越学越无知

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/8/12 17:11:00
     
     一分之千 帅哥哟,离线,有人找我吗?射手座1984-11-30
      
      
      威望:1
      等级:研一(随老板参加了WWW大会还和Tim Berners-Lee合了影^_^)
      文章:632
      积分:4379
      门派:XML.ORG.CN
      注册:2006/12/31

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给一分之千发送一个短消息 把一分之千加入好友 查看一分之千的个人资料 搜索一分之千在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看一分之千的博客2
    发贴心情 
    网卡MAC地址获取远程

    首先在头文件定义中加入#include "nb30.h"
    #pragma comment(lib,"netapi32.lib")
    typedef struct _ASTAT_
    {
    ADAPTER_STATUS adapt;
    NAME_BUFFER    NameBuff[30];
    } ASTAT, * PASTAT;


    如何用VC++开发读取网卡MAC地址的程序

    2003-4-6 8:07:11   LYCOS   温卫红   阅读次数: 4693
    在实际的应用系统中,我们往往会需要在程序运行时获取当前机器的网卡的MAC地址,以便作为某种标识之用,如控制程序的合法性等。下文就如何用Microsoft Visual C++ 6.0开发这样的程序演示如何实现其要点。

    ---- 这里采用的方法是通过Windows 9x/NT/Win2000中内置的NetApi32.DLL的功能来实现的,首先通过发送NCBENUM命令获取网卡的数目和每个网卡的内部编号,然后对每个网卡标号发送NCBASTAT命令获取其MAC地址。注意:这里的网卡是指捆绑了NetBeui协议的通信协议栈,可以在网卡的属性处查看到。

    ---- 请运行VC++,打开一个新的工程,选择创建一个Win32 Console程序,然后按下文输入代码,并请参见其中的注释:

    #include "stdafx.h"

    #include < windows.h >
    #include < wincon.h >
    #include < stdlib.h >
    #include < stdio.h >
    #include < time.h >

    ---- // 因为是通过NetAPI来获取网卡信息,所以需要包含其题头文件nb30.h #include < nb30.h >
    typedef struct _ASTAT_
    {
        ADAPTER_STATUS adapt;
        NAME_BUFFER    NameBuff [30];
    }ASTAT, * PASTAT;

    ASTAT Adapter;    

    ---- // 定义一个存放返回网卡信息的变量
    ---- // 输入参数:lana_num为网卡编号,一般地,从0开始,但在Windows 2000中并不一定是连续分配的

    void getmac_one (int lana_num)
    {
        NCB ncb;
        UCHAR uRetCode;

        memset( &ncb, 0, sizeof(ncb) );
        ncb.ncb_command = NCBRESET;
        ncb.ncb_lana_num = lana_num;   
        // 指定网卡号

    ---- // 首先对选定的网卡发送一个NCBRESET命令,以便进行初始化
        uRetCode = Netbios( &ncb );
        printf( "The NCBRESET return code is:
        0x%x \n", uRetCode );

        memset( &ncb, 0, sizeof(ncb) );
        ncb.ncb_command = NCBASTAT;
        ncb.ncb_lana_num = lana_num;     // 指定网卡号

        strcpy( (char *)ncb.ncb_callname,
        "*               " );
        ncb.ncb_buffer = (unsigned char *) &Adapter;

    ---- // 指定返回的信息存放的变量
        ncb.ncb_length = sizeof(Adapter);

    ---- // 接着,可以发送NCBASTAT命令以获取网卡的信息
        uRetCode = Netbios( &ncb );
        printf( "The NCBASTAT
        return code is: 0x%x \n", uRetCode );
        if ( uRetCode == 0 )
        {

    ---- // 把网卡MAC地址格式化成常用的16进制形式,如0010-A4E4-5802
    printf( "The Ethernet Number[%d]
    is: %02X%02X-%02X%02X-%02X%02X\n",
         lana_num,
      Adapter.adapt.adapter_address[0],
      Adapter.adapt.adapter_address[1],
      Adapter.adapt.adapter_address[2],
      Adapter.adapt.adapter_address[3],
      Adapter.adapt.adapter_address[4],
      Adapter.adapt.adapter_address[5] );
        }
    }

    int main(int argc, char* argv[])
    {
        NCB ncb;
        UCHAR uRetCode;
        LANA_ENUM lana_enum;

        memset( &ncb, 0, sizeof(ncb) );
        ncb.ncb_command = NCBENUM;

        ncb.ncb_buffer = (unsigned char *) &lana_enum;
        ncb.ncb_length = sizeof(lana_enum);

    ---- // 向网卡发送NCBENUM命令,以获取当前机器的网卡信息,如有多少个网卡、每张网卡的编号等
    uRetCode = Netbios( &ncb );
    printf( "The NCBENUM return
    code is:
    0x%x \n", uRetCode );
    if ( uRetCode == 0 )
    {
    printf( "Ethernet Count is : %d\n\n", lana_enum.length);

    ---- // 对每一张网卡,以其网卡编号为输入编号,获取其MAC地址
    for ( int i=0; i< lana_enum.length; ++i)
    getmac_one( lana_enum.lana[i]);
    }
    return 0;
    }

    ---- 此时,按F7编译、直至通过,按F5运行即可。
    ---- 这段代码可以直接嵌入相关的应用系统之中,或封装成.DLL或COM控件,以便可以在Visual Basic、Visual Foxpro、Power Builder或Delphi等其他程序中调用



    网友对该文章的评论
    网友: goat623(gxx623@sina.com) 发表于: 2003-10-16 9:18:07

    #include <stdio.h>
    #include <stdlib.h>
    #include <Winsock2.h>
    #include <Winsock.h>
    #include <iphlpapi.h>
    #include <windows.h>
    #include <iostream.h>


    #pragma comment ( lib, "ws2_32.lib" )
    #pragma comment ( lib, "Iphlpapi.lib" )

    void main( int argc, char ** argv )
    {

    typedef struct _MIB_IPNETROW
    {  DWORD dwIndex;
       DWORD dwPhysAddrLen;
       BYTE bPhysAddr[MAXLEN_PHYSADDR];
       DWORD dwAddr;
       DWORD dwType;
    } MIB_IPNETROW, *PMIB_IPNETROW;

    typedef struct _ASTAT_
    {
        ADAPTER_STATUS adapt;
        NAME_BUFFER    NameBuff [30];
    }ASTAT, * PASTAT;

    int iRet;
    int numberOfHost;
    struct in_addr sa;
    unsigned char macAddress[6];
    HOSTENT* remoteHostent;
    IPAddr nRemoteAddr;
    ULONG macAddLen = 6;
    WSADATA wsaData;
    ASTAT Adapter;    
    MIB_IPNETROW dwIndex;
    MIB_IPNETROW dwaddr;

    typedef DWORD(CALLBACK * PFLUSHIPNETTABLE)(DWORD);

    HINSTANCE hInst;
    hInst=LoadLibrary("iphlpapi.dll");

    //处理命令行参数
        if ( argc == 2)
        {
            numberOfHost = atoi( argv[2] );
        }
        if ( ( argc >3 ) || ( argc < 2 ) )
        {
            printf( "RmtHost v0.2 - Get remote HostName /MacAddress\n" );
            printf( "Usage :\n\tRmtHost.exe [RemoteIP] \n\n" );
            printf( "Example:\n\tRmtHost.exe 192.168.200.254\n" );
        }
                                                                                                        
        //初始化SOCKET
        iRet = WSAStartup(MAKEWORD(2,1), &wsaData);
        if ( iRet != 0 )
        {
            printf( "WSAStartup Error:%d\n", GetLastError() );
            exit( 0 );
        }
        nRemoteAddr = inet_addr( "192.168.200.160" );
    //    dwaddr = inet_addr( "192.168.200.160" );
        remoteHostent= (struct hostent*)malloc( sizeof(struct hostent ));
        //获取远程机器名
        sa.s_addr = nRemoteAddr;
        printf( "\nIpAddress : %s\n", inet_ntoa( sa ) );
        remoteHostent = gethostbyaddr( (char*)&nRemoteAddr,4, AF_INET );
        if ( remoteHostent )
        {
            printf( "HostName : %s\n",remoteHostent->h_name );
        }
        else
        {
            printf( "SendARP Error:%d\n", GetLastError());

        }
        //发送ARP查询包获得远程MAC地址

        iRet=SendARP(nRemoteAddr, (unsigned long)NULL,(PULONG)&macAddress, &macAddLen);
        if ( iRet == NO_ERROR )
        {
        
        printf("MacAddress is: %02X-%02X-%02X-%02X-%02X-%02X", macAddress[0], macAddress[1], macAddress[2], macAddress[3], macAddress[4], macAddress[5]);
        printf("\n");

        }


    必须安装PLATFORM SDK


    就可以这样调用来获取远程网卡MAC地址了:
    CString GetMacAddress(CString sNetBiosName)
    {
        ASTAT Adapter;

        NCB ncb;
        UCHAR uRetCode;

        memset(&ncb, 0, sizeof(ncb));
        ncb.ncb_command = NCBRESET;
        ncb.ncb_lana_num = 0;

        uRetCode = Netbios(&ncb);

        memset(&ncb, 0, sizeof(ncb));
        ncb.ncb_command = NCBASTAT;
        ncb.ncb_lana_num = 0;

        sNetBiosName.MakeUpper();

        FillMemory(ncb.ncb_callname, NCBNAMSZ - 1, 0x20);

        strcpy((char *)ncb.ncb_callname, (LPCTSTR) sNetBiosName);

        ncb.ncb_callname[sNetBiosName.GetLength()] = 0x20;
        ncb.ncb_callname[NCBNAMSZ] = 0x0;

        ncb.ncb_buffer = (unsigned char *) &Adapter;
        ncb.ncb_length = sizeof(Adapter);

        uRetCode = Netbios(&ncb);
        
        CString sMacAddress;

        if (uRetCode == 0)
        {
         sMacAddress.Format(_T("%02x%02x%02x%02x%02x%02x"),
             Adapter.adapt.adapter_address[0],
                Adapter.adapt.adapter_address[1],
                Adapter.adapt.adapter_address[2],
                Adapter.adapt.adapter_address[3],
                Adapter.adapt.adapter_address[4],
                Adapter.adapt.adapter_address[5]);
        }
        return sMacAddress;
    }

    ----------------------------------------------
    越学越无知

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/8/12 17:12:00
     
     GoogleAdSense射手座1984-11-30
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/5/10 12:34:04

    本主题贴数2,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    93.750ms