XE4 Firemonkey OLE类型转换错误(获取win MAC地址)

时间:2014-02-06 12:24:50

标签: delphi com firemonkey ole delphi-xe4

我正在使用Delphi XE4。

我正在移植一段编译代码,这些代码是在vcl(使用ActiveX,vcl.oleauto)下运行到firemonkey友好版本。

它会抛出无效的类型转换错误。有人知道vcl单元和这些单元有什么不同吗?

谢谢

约翰。

uses

{$IFDEF MSWINDOWS}
  Winapi.Windows,
  System.Win.ComObj,
  Winapi.ole2,
{$ENDIF}

SysUtils;


function GetfirstMacAddress : String;
const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;

begin
  Result := '';
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT Description,MACAddress FROM Win32_NetworkAdapterConfiguration','WQL',wbemFlagForwardOnly);

  oEnum         := (IUnknown(FWbemObjectSet._NewEnum)) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    if not VarIsNull(FWbemObject.MACAddress) then
      begin
        Result := (FWbemObject.MACAddress);
        exit;
      end;
    FWbemObject:=Unassigned;
  end;
end;

1 个答案:

答案 0 :(得分:1)

您的代码无法在任何地方编译。无论是VCL还是FMX。所以,这个问题根本与FMX无关。也许是早期版本,但不是这里的代码。

我认为@TLama与您的使用条款在正确的轨道上。您需要IEnumVARIANT单元中的ActiveX而不是Ole2中的单IEnumVARIANTOle2GUID的问题在于它缺少as,这意味着IUnknown强制转换失败。 Ole2中的IEnumVARIANT._Next是一个非常奇怪的类。 Ole2中的varOle2参数使用有符号整数,也很奇怪。所以,Variants似乎是坏消息!

此外,您错过了VarIsNull所需的{$APPTYPE CONSOLE} uses System.Variants, Winapi.ActiveX, System.Win.ComObj; function GetFirstMacAddress : String; const wbemFlagForwardOnly = $00000020; var FSWbemLocator : OLEVariant; FWMIService : OLEVariant; FWbemObjectSet: OLEVariant; FWbemObject : OLEVariant; oEnum : IEnumvariant; iValue : LongWord; begin Result := ''; FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator'); FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', ''); FWbemObjectSet:= FWMIService.ExecQuery('SELECT Description,MACAddress FROM Win32_NetworkAdapterConfiguration','WQL',wbemFlagForwardOnly); oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant; while oEnum.Next(1, FWbemObject, iValue) = 0 do begin if not VarIsNull(FWbemObject.MACAddress) then begin Result := (FWbemObject.MACAddress); exit; end; FWbemObject:=Unassigned; end; end; begin CoInitialize(nil); Writeln(GetFirstMacAddress); Readln; end. 单元。

此版本的代码成功运行:

ActiveX

这可能是回到你开始的地方!您不想在FMX代码中使用Ole2。但IEnumVARIANT也不好。您需要做的就是在代码中进行ActiveX的本地声明。没有必要占用整个ActiveX单位。

从上面的代码开始。删除IEnumVARAINT单位。并提供从ActiveX单位来源复制的{$APPTYPE CONSOLE} uses System.SysUtils, Winapi.Windows, Winapi.WinSock; type TMacAddress = array [0..5] of Byte; function SendARP(DestIP, SrcIP: ULONG; pMacAddr: Pointer; var PhyAddrLen: ULONG): DWORD; stdcall; external 'Iphlpapi.dll'; procedure InitializeWinSock; var wsaData: TWSADATA; begin Win32Check(Winapi.WinSock.WSAStartup($0202, wsaData)=0); end; procedure FinalizeWinSock; begin Winapi.WinSock.WSACleanup; end; function inet_addr(const IPAddress: string): ULONG; begin Result := ULONG(Winapi.WinSock.inet_addr(PAnsiChar(AnsiString(IPAddress)))); end; function GetMacAddress(const IPAddress: string): TMacAddress; var MaxMacAddrLen: ULONG; begin MaxMacAddrLen := SizeOf(Result); if SendARP(inet_addr(IPAddress), 0, @Result, MaxMacAddrLen)<>NO_ERROR then begin raise Exception.CreateFmt('Unable to do SendARP on address: ''%s''', [IPAddress]); end; end; var i: Integer; mac: TMacAddress; begin InitializeWinSock; mac := GetMacAddress('localhost'); for i := low(mac) to high(mac) do begin Write(IntToHex(mac[i], 2)); if i<high(mac) then Write(':'); end; Writeln; FinalizeWinSock; Readln; end. 的良好声明。


FWIW,我不会用WMI解决这个问题。它非常重量级,只是手头的任务不需要。

以下是我将如何获取本地网络接口的MAC地址:

{{1}}