Your code does not compile anywhere. Neither VCL nor FMX. So, this issue not related to FMX at all. Perhaps an earlier version did, but not the code here.
I think that @TLama is on the right track with your uses clauses. You need to the IEnumVARIANT
from the ActiveX
unit rather than the one from Ole2
. The problem with the IEnumVARIANT
in Ole2
is that it is missing its GUID
which means the as
cast fails. And the IUnknown
in Ole2
is a class which is plain weird. And the IEnumVARIANT._Next
in Ole2
uses a signed integer for the var
parameter, also weird. So, Ole2
appears to be bad news!
Also, you were missing the Variants
unit which is needed for VarIsNull
.
This version of your code runs successfully:
{$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.
This is probably right back to where you started! You don't want to use ActiveX
in you FMX code. But Ole2
is no good either. All you need to do is make a local declaration of IEnumVARIANT
in your code. There's no need to take the whole of the ActiveX
unit.
So start from the code above. Remove the ActiveX
unit. And supply the good declaration of IEnumVARAINT
copied from the ActiveX
unit's source.
FWIW, I would not solve this problem with WMI. It is very heavyweight and just not needed for the task at hand.
Here's how I would obtain the MAC address of the local network interface:
{$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.