2014-02-06 2 views
0

저는 Delphi XE4를 사용하고 있습니다.XE4 Firemonkey OLE 유형 변환 오류 (MAC 주소 얻기)

나는 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

코드가 어디에서나 컴파일되지 않습니다. VCL도 FMX도 아닙니다. 따라서이 문제는 FMX와 전혀 관련이 없습니다. 아마도 이전 버전이 있었지만 코드는 여기에 없었을 것입니다.

@ TLama는 사용 조항이있는 올바른 경로에 있다고 생각합니다. Ole2이 아닌 ActiveX 단위에서 IEnumVARIANT이 필요합니다. 에있는 IEnumVARIANT의 문제점은 해당 GUID이 누락되었으므로 as 캐스트가 실패 함을 의미합니다. 그리고 IUnknownOle2에 평범한 클래스입니다. 그리고 IEnumVARIANT._NextOle2var 매개 변수에 부호가있는 정수를 사용합니다. 따라서 Ole2은 나쁜 소식입니다.

또한 에 필요한 Variants 단위가 누락되었습니다.

코드의 버전은 성공적으로 실행 :

{$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. 

이것은 당신이 시작한 곳으로 바로 돌아 아마! FMX 코드에서 ActiveX을 사용하고 싶지 않습니다. 하지만 Ole2도 좋지 않습니다. 코드에 로컬 선언을 IEnumVARIANT으로 작성하면됩니다. ActiveX 기기 전체를 ​​사용할 필요가 없습니다.

위의 코드부터 시작하십시오. ActiveX 장치를 제거합니다. 그리고 ActiveX 단위의 출처에서 복사 된 IEnumVARAINT의 좋은 선언을 제공하십시오.


FWIW,이 문제는 WMI에서 해결되지 않습니다. 그것은 매우 무거 우며 현재 진행중인 작업에 필요하지 않습니다. 그것에 대해

{$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. 
+0

감사, 이전 버전보다 그 심지어 가벼운 무게 : 여기

내가 로컬 네트워크 인터페이스의 MAC 주소를 얻을 것입니다 방법입니다. – John