我正在使用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;
答案 0 :(得分:1)
您的代码无法在任何地方编译。无论是VCL还是FMX。所以,这个问题根本与FMX无关。也许是早期版本,但不是这里的代码。
我认为@TLama与您的使用条款在正确的轨道上。您需要IEnumVARIANT
单元中的ActiveX
而不是Ole2
中的单IEnumVARIANT
。 Ole2
中GUID
的问题在于它缺少as
,这意味着IUnknown
强制转换失败。 Ole2
中的IEnumVARIANT._Next
是一个非常奇怪的类。 Ole2
中的var
对Ole2
参数使用有符号整数,也很奇怪。所以,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}}