从德尔福程序发出Netsh命令



我正在尝试捕获AirCard的设备ID。 我使用以下代码的目的是将结果存储在我存储在 Temp 文件夹中的文本文件 (imei.txt) 中,并循环浏览内容,查找设备 ID。

问题是它只将"找不到以下命令:mbn show interface"写入文件。

我已经从命令行测试了 Netsh 命令,它返回了我所期望的。

    xs1 := CreateOleObject('WSCript.Shell');
    xs1.run('%comspec% /c netsh mbn show interface > "' + IMEIFileName +
      '"', 0, true);

它无法正确处理 NetSh 命令。 我是否正确通过Comspec传递它? 它似乎没有运行"NetSh"命令,就像我从命令提示符运行"mbn"一样。

谢谢

unit uMain;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Win.ComObj, ShlObj,     Vcl.StdCtrls;
type
  TfrmMain = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    procedure GetAirCardInformation;
    { Private declarations }
  public
    { Public declarations }
    IMEI: string;
    PhoneNumber: string;
  end;
var
  frmMain: TfrmMain;
implementation
{$R *.dfm}
procedure TfrmMain.Button1Click(Sender: TObject);
begin
  GetAirCardInformation;
end;
procedure TfrmMain.GetAirCardInformation;
var
  xs1 : OleVariant;
  IMEIFileName: String;
  IMEIStrings: TStringList;
  I: Integer;
  function GetSpecialFolder(const CSIDL: Integer): string;
  var
    RecPath: PWideChar;
  begin
    RecPath := StrAlloc(MAX_PATH);
    try
      FillChar(RecPath^, MAX_PATH, 0);
      if SHGetSpecialFolderPath(0, RecPath, CSIDL, false) then
        result := RecPath
      else
        result := '';
    finally
      StrDispose(RecPath);
    end;
  end;
begin
  IMEI := '';
  IMEIFileName := GetSpecialFolder(CSIDL_LOCAL_APPDATA) + 'Tempimei.txt';
  Memo1.Lines.Add('IMEIFileName: ' + IMEIFileName);
  try
    if FileExists(IMEIFileName) then
      DeleteFile(IMEIFileName);
    xs1 := CreateOleObject('WSCript.Shell');
    xs1.run('%comspec% /c netsh mbn show interface > "' + IMEIFileName +
      '"', 0, true);
    if FileExists(IMEIFileName) then
    begin
      IMEIStrings := TStringList.Create;
      IMEIStrings.LoadFromFile(IMEIFileName);
      IMEIStrings.NameValueSeparator := ':';
      Memo1.Lines.Add('IMEIStrings Count: ' + intToStr(IMEIStrings.Count));
      for I := 0 to IMEIStrings.Count - 1 do
      begin
        Memo1.Lines.Add(IMEIStrings.text);
        if (Uppercase(Trim(IMEIStrings.Names[I])) = 'DEVICE ID') then
        begin
          IMEI := Trim(IMEIStrings.Values[IMEIStrings.Names[I]]);
          Memo1.Lines.Add('IMEI:' + IMEI);
          break;
        end;
      end;
    end;
  except
    IMEI := '';
  end;
  Memo1.Lines.Add('process complete');
end;
end.

您不应该使用 WShell COM 对象来运行cmd.exe 。 这是矫枉过正。 您可以改用CreateProcess()。 但是,以编程方式运行cmd.exe时,不能使用 > 运算符重定向其输出,该运算符仅在实际命令窗口中有效。 您可以改用 STARTUPINFO 结构将输出重定向到使用 CreatePipe() 创建的匿名管道,然后可以使用 ReadFile() 从该管道读取数据。 根本不需要使用临时文件。 MSDN 有一篇关于此主题的文章:

创建具有重定向输入和输出的子进程

有很多

例子在德尔福中展示了这种技术。

话虽如此,更好的选择是根本不使用netsh。 Windows 7 及更高版本具有移动宽带 API。 可以直接在代码中枚举 MBN 接口。

例如,使用 WwanEnumerateInterfaces() 函数:

unit WwApi;
{$MINENUMSIZE 4}
interface
uses
  Windows;
const
  WWAN_STR_DESC_LENGTH = 256;
type
  WWAN_INTERFACE_STATE = (
    WwanInterfaceStateNotReady,
    WwanInterfaceStateDeviceLocked,
    WwanInterfaceStateUserAccountNotActivated,
    WwanInterfaceStateRegistered,
    WwanInterfaceStateRegistering,
    WwanInterfaceStateDeregistered,
    WwanInterfaceStateAttached,
    WwanInterfaceStateAttaching,
    WwanInterfaceStateDetaching,
    WwanInterfaceStateActivated,
    WwanInterfaceStateActivating,
    WwanInterfaceStateDeactivating
  );
  WWAN_INTF_OPCODE = (
    WwanIntfOpcodePin,
    WwanIntfOpcodeRadioState,
    WwanIntfOpcodePreferredProviders,
    WwanIntfOpcodeCurrentConnection,
    WwanIntfOpcodeProvisionedContexts,
    WwanIntfOpcodeActivateUserAccount,
    WwanIntfOpcodeVendorSpecific,
    WwanIntfOpcodeInterfaceObject,
    WwanIntfOpcodeConnectionObject,
    WwanIntfOpcodeAcState,
    WwanIntfOpcodeClearManualConnectState,
    WwanIntfOpcodeGetStoredRadioState,
    WwanIntfOpcodeGetRadioInfo,
    WwanIntfOpcodeHomeProvider
  );
  // I don't know the definition of this type!
  WWAN_STATUS = DWORD; //?
  WWAN_INTERFACE_STATUS = record
    fInitialized: BOOL;
    InterfaceState: WWAN_INTERFACE_STATE;
  end;
  PWWAN_INTERFACE_INFO = ^WWAN_INTERFACE_INFO;
  WWAN_INTERFACE_INFO = record
    InterfaceGuid: TGuid;
    strInterfaceDescription: array[0..WWAN_STR_DESC_LENGTH-1] of WCHAR;
    InterfaceStatus: WWAN_INTERFACE_STATUS;
    ParentInterfaceGuid: TGuid;
    fIsAdditionalPdpContextInterface: BOOL;
  end;
  PWWAN_INTERFACE_INFO_LIST = ^WWAN_INTERFACE_INFO_LIST;
  WWAN_INTERFACE_INFO_LIST = record
    dwNumberOfItems: DWORD;
    pInterfaceInfo: array[0..0] of WWAN_INTERFACE_INFO;
  end;
function WwanOpenHandle(dwClientVersion: DWORD; pReserved: Pointer; var pdwNegotiatedVersion: DWORD; var phClientHandle: THandle): DWORD; stdcall;
function WwanCloseHandle(hClientHandle: THandle; pReserved: Pointer): DWORD; stdcall;
function WwanEnumerateInterfaces(hClientHandle: THandle; pdwReserved: PDWORD; var ppInterfaceList: PWWAN_INTERFACE_INFO_LIST): DWORD; stdcall;
procedure WwanFreeMemory(pMem: Pointer); stdcall;
function WwanQueryInterface(hClientHandle: THandle; const pInterfaceGuid: TGuid; opCode: WWAN_INTF_OPCODE; pReserved: Pointer; var pdwDataSize: DWORD; var ppData: PByte; var pRequestId: ULONG; var pStatus: WWAN_STATUS): DWORD; stdcall;
implementation
const
  WwApiLib = 'WwApi.dll';
function WwanOpenHandle; external WwApiLib delayed;
function WwanCloseHandle; external WwApiLib delayed;
function WwanEnumerateInterfaces; external WwApiLib delayed;
procedure WwanFreeMemory; external WwApiLib delayed;
function WwanQueryInterface; external WwApiLib delayed;
end.

unit uMain;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls;
type
  TfrmMain = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    procedure GetAirCardInformation;
    { Private declarations }
  public
    { Public declarations }
    IMEI: string;
    PhoneNumber: string;
  end;
var
  frmMain: TfrmMain;
implementation
{$R *.dfm}
uses
  WwApi;
procedure TfrmMain.Button1Click(Sender: TObject);
begin
  GetAirCardInformation;
end;
procedure TfrmMain.GetAirCardInformation;
var
  dwNegotiatedVersion: DWORD;
  hClientHandle: THandle;
  pInterfaceList: PWWAN_INTERFACE_INFO_LIST;
  pInterface: PWWAN_INTERFACE_INFO;
  I: DWORD;
begin
  IMEI := '';
  Memo1.Clear;
  try
    // The value of the first parameter is undocumented!
    // WlanOpenHandle() has a similar parameter, where 1
    // is for XP and 2 is for Vista+. Maybe it is the same
    // for WwanOpenHandle()?...
    //
    if WwanOpenHandle(2, nil, dwNegotiatedVersion, hClientHandle) = 0 then
    try
      if WwanEnumerateInterfaces(hClientHandle, nil, pInterfaceList) = 0 then
      try
        Memo1.Lines.Add('IMEIStrings Count: ' + IntToStr(pInterfaceList.dwNumberOfItems));
        if pInterfaceList.dwNumberOfItems > 0 then
        begin
          pInterface := @pInterfaceList.pInterfaceInfo[0];
          for I := 0 to pInterfaceList.dwNumberOfItems-1 do
          begin
            // use pInterface as needed...
            Memo1.Lines.Add('Desc:' + StrPas(pInterface.strInterfaceDescription));
            Memo1.Lines.Add('Intf:' + GUIDToString(pInterface.InterfaceGuid));
            // and so on ...
            Memo1.Lines.Add('');
            Inc(pInterface);
          end;
        end;
      finally
        WwanFreeMemory(pInterfaceList);
      end;
    finally
      WwanCloseHandle(hClientHandle, nil);
    end;
  except
  end;
  Memo1.Lines.Add('process complete');
end;
end.

或者,使用 IMbnInterfaceManagerIMbnInterface COM 接口,这些接口为您提供更多详细信息:

unit uMain;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls;
type
  TfrmMain = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    procedure GetAirCardInformation;
    { Private declarations }
  public
    { Public declarations }
    IMEI: string;
    PhoneNumber: string;
  end;
var
  frmMain: TfrmMain;
implementation
{$R *.dfm}
uses
  // I found the MbnApi.pas unit on the DelphiPraxis forum:
  //
  // http://www.delphipraxis.net/1342330-post2.html
  //
  // It is too large to post here on StackOverflow!
  // Otherwise, you can import the mbnapi.tlb TypeLibrary yourself...
  //
  MbnApi, ActiveX, ComObj;
procedure TfrmMain.Button1Click(Sender: TObject);
begin
  GetAirCardInformation;
end;
procedure TfrmMain.GetAirCardInformation;
var
  Mgr: IMbnInterfaceManager;
  pInterfaceArray, pPhoneNumberArray: PSafeArray;
  pInterface: IMbnInterface;
  subscriber: IMbnSubscriberInformation;
  ReadyState: MBN_READY_STATE;
  lIntfLower, lIntfUpper: LONG;
  lPhoneNumLower, lPhoneNumUpper: LONG;
  I, J: LONG;
  wStr: WideString;
begin
  Memo1.Clear;
  try
    OleCheck(CoCreateInstance(CLASS_MbnInterfaceManager, nil, CLSCTX_ALL, IMbnInterfaceManager, Mgr));
    OleCheck(Mgr.GetInterfaces(pInterfaceArray));
    try
      OleCheck(SafeArrayGetLBound(pInterfaceArray, 1, lIntfLower));
      OleCheck(SafeArrayGetUBound(pInterfaceArray, 1, lIntfUpper));
      for I = lIntfLower to lIntfUpper do
      begin
        OleCheck(SafeArrayGetElement(pInterfaceArray, I, pInterface));
        try
          // use pInterface as needed...
          OleCheck(pInterface.get_InterfaceID(wStr));
          try
            Memo1.Lines.Add('Interface ID:' + wStr);
          finally
            wStr := '';
          end;
          OleCheck(pInterface.GetReadyState(ReadyState));
          Memo1.Lines.Add('Ready State:' + IntToStr(Ord(ReadyState)));
          OleCheck(pInterface.GetSubscriberInformation(subscriber));
          try
            OleCheck(subscriber.Get_SubscriberID(wStr));
            try
              Memo1.Lines.Add('Subscriber ID: ' + wStr);
            finally
              wStr := '';
            end;
            OleCheck(subscriber.Get_SimIccID(wStr));
            try
              Memo1.Lines.Add('Sim ICC ID: ' + wStr);
            finally
              wStr := '';
            end;
            OleCheck(subscriber.Get_TelephoneNumbers(pPhoneNumberArray));
            try
              OleCheck(SafeArrayGetLBound(pPhoneNumberArray, 1, lPhoneNumLower));
              OleCheck(SafeArrayGetUBound(pPhoneNumberArray, 1, lPhoneNumUpper));
              for J = lPhoneNumLower to lPhoneNumUpper do
              begin
                OleCheck(SafeArrayGetElement(pPhoneNumberArray, J, wStr));
                try
                  Memo1.Lines.Add('Phone #:' + wStr);
                finally
                  wStr := '';
                end;
              end;
            finally
              SafeArrayDestroy(pPhoneNumberArray);
            end;
          finally
            subscriber := nil;
          end;
          // and so on...
          Memo1.Lines.Add('');
        finally
          pInterface := nil;
        end;
      end;
    finally
      SafeArrayDestroy(pInterfaceArray);
    end;
  except
  end;
  Memo1.Lines.Add('process complete');
end;
end.

相关内容

  • 没有找到相关文章

最新更新