Вы не должны использовать COM-объект WShell для запуска cmd.exe
. Это перебор. Вместо этого вы можете использовать CreateProcess()
. Однако при программном запуске cmd.exe
вы не можете перенаправить его вывод с помощью оператора >
, который работает только в реальном командном окне. Вместо этого вы можете использовать структуру STARTUPINFO
для перенаправления вывода в анонимный канал, созданный с помощью CreatePipe()
, а затем вы можете читать из этого канала с помощью ReadFile()
. Нет необходимости использовать временный файл вообще. В MSDN есть статья на эту тему:
Создание дочернего процесса с перенаправленным вводом и выводом
Существует множество примеров, демонстрирующих эту технику в Delphi.
При этом лучше вообще не использовать 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.
Alternatively, using the IMbnInterfaceManager
and IMbnInterface
COM interfaces, which give you more detailed information:
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.
person
Remy Lebeau
schedule
15.07.2016
cmd.exe
? Вместо этого используйтеCreateProcess()
. Сообщение об ошибке означает, что самnetsh
не распознает командуmbn show interface
. На какой системе вы работаете? Почему вы вообще используетеnetsh
? В Windows есть Mobile Broadband API, используйтеWwanEnumerateInterfaces()
илиIMbnInterfaceManager
, чтобы получить список интерфейсов MBN. - person Remy Lebeau   schedule 15.07.2016mbnapi.tlb
. Я нашел для него модуль Delphi (MbnApi.pas
) на форуме DelphiPraxis. Однако вам не нужна TypeLibrary для вызова функцийWwan...()
. - person Remy Lebeau   schedule 15.07.2016