Вы не должны использовать объект 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.
В качестве альтернативы, используя IMbnInterfaceManager
и IMbnInterface
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.
Почему вы используете COM-объект WShell для вызова '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/library/windows/desktop/dn313190.aspx) или ['IMbnInterfaceManager'] (https://msdn.microsoft.com/en-us/library/windows/desktop/dd430416.aspx), чтобы получить список интерфейсов MBN. –
спасибо Реми. Можете ли вы указать мне пример своего рода? Все, что я могу найти, находится на MSDN. Я нахожусь в Windows 10 Pro и не вижу библиотеки типов для этого или чего-то связанного. –
ТипLibrary для интерфейсов MBN - 'mbnapi.tlb'. Я нашел для него блок Delphi (http://www.delphipraxis.net/189688-windows-mbn-api-fuer-delphi-xe-portieren.html) ('MbnApi.pas') на форуме DelphiPraxis. Однако вам не нужна TypeLibrary для вызова функций 'Wwan ...()'. –