2016-07-14 73 views
0

我正在嘗試捕獲AirCard的設備ID。我正在使用以下代碼,目的是將結果存儲在存儲在Temp文件夾中的文本文件(imei.txt)中,並循環查看內容,查找DEVICE ID。從Delphi程序發出Netsh命令

的問題是,它只是寫道:「下面的命令沒有被發現:MBN顯示界面。」到文件。

我已經在命令行測試的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) + '\Temp\imei.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. 
+0

爲什麼你在使用WShell COM對象來調用嗎? 'cmd.exe'?改用'CreateProcess()'。錯誤信息意味着'netsh'本身不能識別'mbn show interface'命令。你在哪個系統上運行?你爲什麼使用'netsh'? Windows有一個[移動寬帶API](https://msdn.microsoft.com/en-us/library/windows/desktop/dd323271.aspx),用['WwanEnumerateInterfaces()'](https://msdn.microsoft .COM/EN-US /庫/窗/臺式機/ dn313190.aspx)或['IMbnInterfaceManager'(https://msdn.microsoft.com/en-us/library/windows/desktop/dd430416.aspx)來獲得MBN接口列表。 –

+0

謝謝雷米。 你能指點我一個排序的例子嗎?我只能在MSDN上找到。我在Windows 10 Pro上,沒有看到這個或任何相關的類型庫。 –

+0

MBN接口的TypeLibrary是'mbnapi.tlb'。我在DelphiPraxis論壇上找到了一個[Delphi unit for it](http://www.delphipraxis.net/189688-windows-mbn-api-fuer-delphi-xe-portieren.html)('MbnApi.pas')。不過,您不需要TypeLibrary來調用'Wwan ...()'函數。 –

回答

2

你不應該使用WShell COM對象運行cmd.exe進行。這是矯枉過正。您可以改用CreateProcess()。但是,在可編程運行cmd.exe時,不能使用>運算符重定向其輸出,該運算符只能在實際的命令窗口中運行。您可以改用STARTUPINFO結構將輸出重定向到與CreatePipe()創建一個匿名管道,然後你可以使用ReadFile()該管道讀取。根本不需要使用臨時文件。 MSDN有關於這個主題的一篇文章:

Creating a Child Process with Redirected Input and Output

有大量的演示Delphi中這種技術的例子左右浮動。

話雖這麼說,更好的選擇是不使用netsh在所有。 Windows 7和更高版本有一個Mobile Broadband 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. 
+0

雷米, 我嘗試使用WwApi的做法,但我無法弄清手機沒有或設備ID。這是我所有的客戶想要的。 我有一個批處理文件,下面有兩行 netsh mbn show interfaces>「imei.txt」 netsh mbn show readyinfo =「移動寬帶連接」> pno.txt「 它只是我想要的,但不是當我從德爾福調用它。我都用了ShellExe和CreateProcess的,有和沒有Wow64DisableWow64FsRedirection但總是在同一個地方結束。它似乎運行netsh但不承認該行的其餘部分。我只想數據 –

+0

'IMbnInterface '提供你正在尋找的信息,在'ReadyState'和'SubscriberInformation'性能。如果你堅持使用netsh的,你不能使用'>'運營商與'的ShellExecute()'/'CreateProcess的文件重定向( )'。你必須使用管道重定向,正如我將MSDN文章鏈接到的那樣。不要使用臨時文件。 –

+0

好的,我回來了使用WwApi,但我找不到我的方式ReadyState或SubscriberInformation。我在高雜草中像一個球一樣迷失。我想要做的就是讓我的客戶使用空卡電話號碼和設備ID。每條路線似乎都是死路一條。 –