Strange Count value after calling FileRead - windows

I'm trying to compare the number of bytes read with the count passed to FileRead which is a wrapper around the WinAPi ReadFile function.
The problem is that I get different values based on the structure of my ReadFromFile procedure (none of the added/subtracted lines change the count variable).
If you run the below code you get this output
FileHandle: 400
SizeOfFile: 8672
Current position: 8655
aCount before SetLength: 17
aCount before FileRead: 17
Number of bytes read: 17
aCount after FileRead: 2200
EAccessViolation: Access violation at address 0040C5BC in module 'Project7.exe'. Read of address C23C30BA
the AV is because of freeing the dynamic array by the compiler at the end of scope (this is not always).
as you can see the count == 2200 here (I got 0 before this) after the FileRead. If you comment out the second API Call or Line two the count is right
Can you tell me what is this and how can I solve it?
program Project7;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, WinAPI.Windows, System.Classes;
procedure ReadFromFile(aFileHandle: THandle; aCount: Longint);
var
aPosition, ReadRes: Int64;
TmpBuffer: TBytes;
begin
writeln('aCount before SetLength: ',aCount);
SetLength(TmpBuffer, aCount);
writeln('aCount before FileRead: ',aCount);
ReadRes := FileRead(aFileHandle, TmpBuffer, aCount);
Writeln('Number of bytes read: ', ReadRes);
//aPosition := FileSeek(aFileHandle, 0, Ord(soCurrent)); // second API call
//Writeln('Current position after read: ', aPosition); // line two
writeln('aCount after FileRead: ',aCount);
if ReadRes <> aCount then
//Raise Exception.Create('hi there');
// DoWrite(TmpBuffer[0], aCount);
end;
var
FFileHandle: THandle;
aFileName: string;
I1: Integer;
aFilePhysicalSize: Int64;
FPosition: Int64;
begin
try
aFileName := 'C:\Users\nacereddine\Desktop\ascii-table.gif';
{ TODO -oUser -cConsole Main : Insert code here }
FFileHandle := CreateFile(PChar(aFileName), GENERIC_READ,
FILE_SHARE_READ, nil, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
Writeln('FileHandle: ', FFileHandle);
aFilePhysicalSize := FileSeek(FFileHandle, 0 , Ord(soEnd));
Writeln('SizeOfFile: ', aFilePhysicalSize);
FPosition := FileSeek(FFileHandle, aFilePhysicalSize - 17 , Ord(soBeginning));
Writeln('Current position: ', FPosition);
I1 := 17;
ReadFromFile(FFileHandle, I1);
readln;
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
readln;
end;
end;
end.

You are using version of procedure fileread with untyped second parameter here:
TmpBuffer: TBytes;
...
ReadRes := FileRead(aFileHandle, TmpBuffer, aCount);
but in this case you should dereference dynamic array like TmpBuffer[0]
From your help link:
//this version is used
function FileRead(Handle: THandle; var Buffer; Count: LongWord): Integer;
//perhaps you wanted that one:
function FileRead(Handle: THandle; var Buffer: TBytes; Offset, Count: LongWord): Integer;

Related

Find HID/PID in DELPHI / ARDUINO Interface

(First, I am not sure whether this question is placed in the correct section of Stack Exchange. If not so, please give me a notice and delete the question.)
I have 8 Arduino's (Ards). Some Uno's and some 2650 Mega's. In an attempt to automatize the connection process (I use Delphi D-7 SE as I/O), I want to differentate between the UNO and the 2650 (mostly because the hardware differences in the appropriate chip). The way to do this (I think), is to get the PID and VID from the board. But I don't know how to do this. The code below gives me the correct driver, but not PID/VID . Is it possible to get PID/VID for this code-snippet ?? IF so, HOW ?
Thanks a lot.
Code here:
unit ArduinoTestU;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, JVsetupAPI, Registry, StdCtrls,
CPortCtl, CPort, Menus, XPMan;
type
TMainForm = class(TForm)
ListBox1: TListBox;
Label1: TLabel;
Button1: TButton;
procedure FormCreate(Sender: TObject);
function SetupEnumAvailableComPorts : TstringList;
procedure ListBox1Click(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
ArdType : Integer;
end;
var
MainForm : TMainForm;
ComPortStringList : TStringList;
MyComPort : String;
CurDir : String;
implementation
uses Form1Unit, ArdFormU; (* , ArdFormU; *)
{$R *.dfm}
procedure TMainForm.Button1Click(Sender: TObject);
begin
MainForm.FormActivate(NIL);
end;
procedure TMainForm.FormActivate(Sender: TObject);
var
index : integer;
begin
ComPortStringList := SetupEnumAvailableComPorts;
if (ComPortStringList <> nil) and (ComPortStringList.Count > 0) then
for Index := 0 to ComPortStringList.Count - 1 do
Listbox1.Items.Add(ComPortStringList[Index]);
if Listbox1.Items.Count <> 0 then
BEGIN
Listbox1.Enabled := True;
Button1.Enabled := False;
END;
end;
procedure TMainForm.FormCreate(Sender: TObject);
BEGIN
Curdir := ExtractFileDir(Application.Exename);
end;
(*
The function below returns a list of available COM-ports
(not open by this or an other process), with friendly names. The list is formatted as follows:
COM1: = Communications Port (COM1)
COM5: = NI Serial Port (Com5)
COM6: = NI Serial Port (Com6)
COM7: = USB Serial Port (COM7)
COM8: = Bluetooth Communications Port (COM8)
COM9: = Bluetooth Communications Port (COM9)
This code originally posted at http://www.delphi3000.com/articles/article_4001.asp?SK=
errors have been fixed so it will work with Delphi 7 and SetupAPI from JVCL
*)
function TMainForm.SetupEnumAvailableComPorts : TstringList;
//
// Enumerates all serial communications ports that are available and ready to
// be used.
//
var
RequiredSize: Cardinal;
GUIDSize: DWORD;
Guid: TGUID;
DevInfoHandle: HDEVINFO;
DeviceInfoData: TSPDevInfoData;
MemberIndex: Cardinal;
PropertyRegDataType: DWord;
RegProperty: Cardinal;
RegTyp: Cardinal;
Key: Hkey;
Info: TRegKeyInfo;
S1,S2: string;
hc: THandle;
begin
Result := Nil;
//
//If we cannot access the setupapi.dll then we return a nil pointer.
//
if not LoadsetupAPI then
exit;
try
//
// get 'Ports' class guid from name
//
GUIDSize := 1; // missing from original code - need to tell function that the Guid structure contains a single GUID
if SetupDiClassGuidsFromName('Ports',#Guid,GUIDSize,RequiredSize) then
begin
//
//get object handle of 'Ports' class to interate all devices
//
DevInfoHandle := SetupDiGetClassDevs(#Guid,Nil,0,DIGCF_PRESENT);
if Cardinal(DevInfoHandle) <> Invalid_Handle_Value then
begin
try
MemberIndex := 0;
result := TStringList.Create;
//iterate device list
repeat
FillChar(DeviceInfoData,SizeOf(DeviceInfoData),0);
DeviceInfoData.cbSize := SizeOf(DeviceInfoData);
//get device info that corresponds to the next memberindex
if Not SetupDiEnumDeviceInfo(DevInfoHandle,MemberIndex,DeviceInfoData) then
break;
//query friendly device name LIKE 'BlueTooth Communication Port (COM8)' etc
RegProperty := SPDRP_FriendlyName; {SPDRP_Driver, SPDRP_SERVICE, SPDRP_ENUMERATOR_NAME,SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,SPDRP_FRIENDLYNAME,}
SetupDiGetDeviceRegistryProperty(DevInfoHandle, DeviceInfoData,RegProperty, PropertyRegDataType,NIL,0,RequiredSize);
SetLength(S1,RequiredSize);
// ShowMessage('TEST: ' + S1);
if SetupDiGetDeviceRegistryProperty(DevInfoHandle,DeviceInfoData,RegProperty,PropertyRegDataType,#S1[1],RequiredSize,RequiredSize) then
begin
KEY := SetupDiOpenDevRegKey(DevInfoHandle,DeviceInfoData,DICS_FLAG_GLOBAL,0,DIREG_DEV,KEY_READ);
if key <> INValid_Handle_Value then
begin
FillChar(Info, SizeOf(Info), 0);
//query the real port name from the registry value 'PortName'
if RegQueryInfoKey(Key, nil, nil, nil, #Info.NumSubKeys,#Info.MaxSubKeyLen, nil, #Info.NumValues, #Info.MaxValueLen,
#Info.MaxDataLen, nil, #Info.FileTime) = ERROR_SUCCESS then
begin
RequiredSize := Info.MaxValueLen + 1;
SetLength(S2,RequiredSize);
if RegQueryValueEx(KEY,'PortName',Nil,#Regtyp,#s2[1],#RequiredSize) = Error_Success then
begin
If (Pos('COM',S2) = 1) then
begin
//Test if the device can be used
hc := CreateFile(pchar('\\.\' + S2 + #0), GENERIC_READ or GENERIC_WRITE,
0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if hc <> INVALID_HANDLE_VALUE then
begin
Result.Add(Strpas(PChar(S2)) + ' := ' + StrPas(PChar(S1)));
CloseHandle(hc);
end;
end;
end;
end;
RegCloseKey(key);
end;
end;
Inc(MemberIndex);
until False;
//If we did not found any free com. port we return a NIL pointer.
if Result.Count = 0 then
begin
Result.Free;
Result := NIL;
end
finally
SetupDiDestroyDeviceInfoList(DevInfoHandle);
end;
end;
end;
finally
UnloadSetupApi;
end;
end;
procedure TMainForm.ListBox1Click(Sender: TObject);
begin
Ardtype := Listbox1.ItemIndex;
MainForm.Hide;
ArdForm.ShowModal;
if Ardform.ModalResult <> mrOK then
ShowMessage('Der opstod en fejl ')
ELSE
BEGIN
MainForm.Show;
END;
end;
end.
Kris aka snestrup2016

How to compile using Free Pascal

Guys I got a source from a friend that is suppose to help me learn RE a lot but I got error
Error:identifier not found "TResourceStream"
"Bool"
"TMemoryStream"
"TResourceInfo"
"try"
And
Fatal: Syntax error, ";" expected but " identifier MS" found
Please help I need to compile this.
Excuse me please I know nothing yet, about programming.
Here is the source
function EnumResourceNames(hModule: HMODULE; // EXE handle returned from LoadLibrary/Ex
lpType: PChar; // resource type (eg: RT_RCDATA)
lpEnumFunc: ENUMRESNAMEPROC; // callback function address
lParam: Integer // long integer (eg: pointer to an object)
): BOOL; stdcall;
function CB_EnumDfmNameProc(hModule: THandle; lpszType, lpszName: PChar;
lParam: Integer): Boolean; stdcall;
var
ms: TMemoryStream;
rs: TResourceStream;
Buffer: array of Byte;
begin
with TResourceInfo(lParam) do
begin
rs := TResourceStream.Create(TResourceInfo(lParam).Module,
lpszname, lpszType); // load resource in memory
try
ms := TMemoryStream.Create;
try
try
SetLength(Buffer, 4);
rs.Read(Buffer[0], SizeOf(Buffer)); // read the first 4 bytes
if string(Buffer) = 'TPF0' then // is it a DFM resource?
begin
rs.Seek(0, 0);
ObjectBinaryToText(rs, ms); // decode DFM
ms.Seek(0, 0);
AddDfm(StrPas(lpszName), ms); // add it to our own list
end;
except
raise;
end;
finally
ms.Free;
end;
finally
rs.free;
end;
end;
Result := True;
end;
procedure TResourceInfo.EnumDfmNames;
begin
if FModule > 0 then // if an EXE file has been loaded
EnumResourceNames(FModule, RT_RCDATA, // go and search RCDATA resources
#CB_EnumDfmNameProc, Integer(Self));
end;

How to get drive letter of a USB memory stick drive given its volume label?

A USB memory stick has two partitions - one read only and the other read-write.
My program runs from the read-only partition.
The volume labels for both partitions are fixed by the manufacturer:
MYDISK-RO and MYDISK-RW
When inserted in Windows, each partition (volume) gets a different drive letter. These drive letters are different on different computers depending on the configuration ie. the number of drive letters already allocated to disk drives.
My question is:
Which is the best (most efficient) way for the program to find the drive letter of the read-write partition, using the volume label?
It needs to work on Windows XP and up.
Rather than enumerate all drive letters and compare the volume label to the one that we need, I'm looking ideally for a single function call to Windows .. something like:
GetDriveLetterByVolumeName(AVolumeLabel: String);
or
GetVolumeInformation(AVolumeLabel: String);
Is there such a function or is enumerating the drive letters and comparing each volume label the only solution?
TIA.
Long long time ago I used this code (Was on Delphi7)
This procedure add in combobox all the root of all Removable drives found
Procedure TfMain.GetDiskDrives();
var
r: LongWord;
Drives: array[0..128] of char;
pDrive: pchar;
begin
Result := '';
r := GetLogicalDriveStrings(sizeof(Drives), Drives);
if r = 0 then exit;
if r > sizeof(Drives) then
raise Exception.Create(SysErrorMessage(ERROR_OUTOFMEMORY));
pDrive := Drives; // Point to the first drive
while pDrive^ <> #0 do begin
if GetDriveType(pDrive) = DRIVE_REMOVABLE then begin
cDrive.Items.Add(pDrive);
end;
inc(pDrive, 4); // Point to the next drive
end;
if cDrive.Items.Count=1 then cDrive.ItemIndex:=0;
end;
After that you can use the following function to get the volume name
function GetVolumeName(DriveLetter: Char): string;
var
dummy: DWORD;
buffer: array[0..MAX_PATH] of Char;
oldmode: LongInt;
begin
oldmode := SetErrorMode(SEM_FAILCRITICALERRORS);
try
GetVolumeInformation(PChar(DriveLetter + ':\'),
buffer,
SizeOf(buffer),
nil,
dummy,
dummy,
nil,
0);
Result := StrPas(buffer);
finally
SetErrorMode(oldmode);
end;
end;
I'm posting my code adapted from Gianluca Colombo's answer:
Tested and working with Delphi XE2 Update 4.1 on Windows 7 x64.
unit uDiskUtils;
interface
uses Windows, Classes, SysUtils;
Procedure GetDiskDrives(var ADriveList: TStrings);
function GetVolumeName(const ADriveLetter: Char): string;
function FindDiskDriveByVolumeName(const AVolumeName: String): Char;
implementation
Procedure GetDiskDrives(var ADriveList: TStrings);
var
r: LongWord;
Drives: array [0 .. 128] of Char;
pDrive: pchar;
begin
ADriveList.Clear;
r := GetLogicalDriveStrings(sizeof(Drives), Drives);
if r = 0 then
exit;
if r > sizeof(Drives) then
raise Exception.Create(SysErrorMessage(ERROR_OUTOFMEMORY));
pDrive := Drives; // Point to the first drive
while pDrive^ <> #0 do
begin
if GetDriveType(pDrive) = DRIVE_REMOVABLE then
begin
ADriveList.Add(pDrive);
end;
inc(pDrive, 4); // Point to the next drive
end;
end;
function GetVolumeName(const ADriveLetter: Char): string;
var
dummy: DWORD;
buffer: array [0 .. MAX_PATH] of Char;
oldmode: LongInt;
begin
oldmode := SetErrorMode(SEM_FAILCRITICALERRORS);
try
GetVolumeInformation(pchar(ADriveLetter + ':\'), buffer, sizeof(buffer), nil, dummy, dummy, nil, 0);
Result := StrPas(buffer);
finally
SetErrorMode(oldmode);
end;
end;
function FindDiskDriveByVolumeName(const AVolumeName: String): Char;
var
dl: TStringList;
c: Integer;
begin
Result := ' ';
dl := TStringList.Create;
try
GetDiskDrives(TStrings(dl));
for c := 0 to dl.Count - 1 do
if (AVolumeName = GetVolumeName(dl[c][1])) then
Result := dl[c][1];
finally
dl.Free;
end;
end;
end.

how to get access console buffer from another process? AttachConsole ERROR_INVALID_PARAMETER

I want to get access to the buffer of another process console (via AttachConsole), for calling ReadConsoleOutput, etc.
Is a DOS 16bit application. I can't use pipes because it doesn't writes output secuentially (it emulates "windows".. like FAR commander if you know what I mean).
So I should:
1) launch the app
2) get the process id
3) call AttachConsole(ProcId)
4) call GetConsoleScreenBufferInfo to get the size
5) call ReadConsoleOutput
The problem is at 3: when I call AttachConsole ir returns 0, and after a call to GetLastError it reports ERROR_INVALID_PARAMETER 87 (0x57).
The only parameter of AttachConsole is the ProcessId and I've checked it with ProcessExplorer that is right (it's actually the PID of ntvdm.exe that emulates the app).
Delphi code:
function AttachConsole(dwProcessId: DWORD): Cardinal; external kernel32 name 'AttachConsole';
var
Handle: HWND;
function EnumWindowsProc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
s: string;
IsVisible, IsOwned, IsAppWindow: Boolean;
begin
Result := True;//carry on enumerating
IsVisible := IsWindowVisible(hwnd);
if not IsVisible then
exit;
IsOwned := GetWindow(hwnd, GW_OWNER)<>0;
if IsOwned then
exit;
IsAppWindow := GetWindowLongPtr(hwnd, GWL_STYLE) and WS_EX_APPWINDOW<>0;
if not IsAppWindow then
exit;
SetLength(s, GetWindowTextLength(hwnd));
GetWindowText(hwnd, PChar(s), Length(s)+1);
if AnsiContainsText(s, '????.EXE') then // set windows name to search
Handle := hwnd;
end;
procedure Test(Strings: TStrings);
var
ProcessID: Cardinal;
begin
Handle := 0;
EnumWindows(#EnumWindowsProc, 0);
Strings.Add('Handle: ' + IntToStr(Handle));
if Handle <> 0 then
SetForegroundWindow(Handle);
Sleep(100);
GetWindowThreadProcessId(Handle, #ProcessID);
Strings.Add('ProcessId: ' + IntToStr(ProcessID));
if AttachConsole(ProcessId) <> 0 then
Strings.Add('Ok Attached')
else
Strings.Add('Error: ' + IntToStr(GetLastError));
end;
Drop memo and button in form. At OnClick call Test(Memo1.Lines).
===== EDIT complete solution =====
function AttachAndGetConsoleHandle(ProcessId: Cardinal): Cardinal;
begin
if not AttachConsole(ProcessId) then
raise Exception.Create('AttachConsole error: ' + IntToStr(GetLastError));
Result := GetStdHandle(STD_OUTPUT_HANDLE);
if Result = INVALID_HANDLE_VALUE then
raise Exception.Create('GetStdHandle(STD_OUTPUT_HANDLE) error: ' + IntToStr(GetLastError));
end;
procedure DettachConsole;
begin
if not FreeConsole then
raise Exception.Create('FreeConsole error: ' + IntToStr(GetLastError));
end;
function ReadConsole(ConsoleHandle: Cardinal): TStringList;
var
BufferInfo: _CONSOLE_SCREEN_BUFFER_INFO;
BufferSize, BufferCoord: _COORD;
ReadRegion: _SMALL_RECT;
Buffer: Array of _CHAR_INFO;
I, J: Integer;
Line: AnsiString;
begin
Result := TStringList.Create;
ZeroMemory(#BufferInfo, SizeOf(BufferInfo));
if not GetConsoleScreenBufferInfo(ConsoleHandle, BufferInfo) then
raise Exception.Create('GetConsoleScreenBufferInfo error: ' + IntToStr(GetLastError));
SetLength(Buffer, BufferInfo.dwSize.X * BufferInfo.dwSize.Y);
BufferSize.X := BufferInfo.dwSize.X;
BufferSize.Y := BufferInfo.dwSize.Y;
BufferCoord.X := 0;
BufferCoord.Y := 0;
ReadRegion.Left := 0;
ReadRegion.Top := 0;
ReadRegion.Right := BufferInfo.dwSize.X;
ReadRegion.Bottom := BufferInfo.dwSize.Y;
if ReadConsoleOutput(ConsoleHandle, Pointer(Buffer), BufferSize, BufferCoord, ReadRegion) then
begin
for I := 0 to BufferInfo.dwSize.Y - 1 do
begin
Line := '';
for J := 0 to BufferInfo.dwSize.X - 1 do
Line := Line + Buffer[I * BufferInfo.dwSize.X + J].AsciiChar;
Result.Add(Line)
end
end
else
raise Exception.Create('ReadConsoleOutput error: ' + IntToStr(GetLastError));
end;
The definition should be:
function AttachConsole(dwProcessId: DWORD): BOOL; stdcall; external
kernel32 name 'AttachConsole';
So the code following it should be:
if AttachConsole(ProcessId) then
Can't help you anymore than that.

How to get MAC address in windows7? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
Getting Machine’s MAC Address — Good Solution?
How do I get the MAC address of a network card using Delphi?
I am using MAC address as hardware id for protection(ofcourse I have encrypted this data)
I am using below code to get MAC address on user computer
function MacAddress: string;
var
Lib: Cardinal;
Func: function(GUID: PGUID): Longint; stdcall;
GUID1, GUID2: TGUID;
begin
Result := '';
Lib := LoadLibrary('rpcrt4.dll');
if Lib <> 0 then
begin
#Func := GetProcAddress(Lib, 'UuidCreateSequential');
if Assigned(Func) then
begin
if (Func(#GUID1) = 0) and
(Func(#GUID2) = 0) and
(GUID1.D4[2] = GUID2.D4[2]) and
(GUID1.D4[3] = GUID2.D4[3]) and
(GUID1.D4[4] = GUID2.D4[4]) and
(GUID1.D4[5] = GUID2.D4[5]) and
(GUID1.D4[6] = GUID2.D4[6]) and
(GUID1.D4[7] = GUID2.D4[7]) then
begin
Result :=
IntToHex(GUID1.D4[2], 2) + '-' +
IntToHex(GUID1.D4[3], 2) + '-' +
IntToHex(GUID1.D4[4], 2) + '-' +
IntToHex(GUID1.D4[5], 2) + '-' +
IntToHex(GUID1.D4[6], 2) + '-' +
IntToHex(GUID1.D4[7], 2);
end;
end;
end;
end;
above code works perfectly on windows XP
but its giving different values in windows7 ,the value changing every time after computer resratred :(
is there any chance of getting MAC address thats constant (unless user changed his MAC address)
or is there any good code which retrvies constant data on all OS ?
thanks in advance
#steve0, to retrieve the mac address of an Network Adapter you can use the WMI and the Win32_NetworkAdapterConfiguration Class and check the MACAddress property.
Check this code:
program WMI_MAC;
{$APPTYPE CONSOLE}
uses
SysUtils
,ActiveX
,ComObj
,Variants;
function VarToStrNil(Value:Variant):string; //Dummy function to onvert an variant value to string
begin
if VarIsNull(Value) then
Result:=''
else
Result:=VarToStr(Value);
end;
Procedure GetMacAddress;
var
objWMIService : OLEVariant;
colItems : OLEVariant;
colItem : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
wmiHost, root, wmiClass: string;
function GetWMIObject(const objectName: String): IDispatch;
var
chEaten: Integer;
BindCtx: IBindCtx;//for access to a bind context
Moniker: IMoniker;//Enables you to use a moniker object
begin
OleCheck(CreateBindCtx(0, bindCtx));
OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));//Converts a string into a moniker that identifies the object named by the string
OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));//Binds to the specified object
end;
begin
wmiHost := '.';
root := 'root\CIMV2';
wmiClass := 'Win32_NetworkAdapterConfiguration';
objWMIService := GetWMIObject(Format('winmgmts:\\%s\%s',[wmiHost,root]));
colItems := objWMIService.ExecQuery(Format('SELECT * FROM %s',[wmiClass]),'WQL',0);
oEnum := IUnknown(colItems._NewEnum) as IEnumVariant;
while oEnum.Next(1, colItem, iValue) = 0 do
//if VarToStrNil(colItem.MACAddress)<>'' then //uncomment if you only want list the interfaces with mac adress
//if colItem.IPEnabled then // uncomment if you only want list the active interfaces
begin
WriteLn('Card Description '+VarToStrNil(colItem.Caption));
WriteLn('MACAddress '+VarToStrNil(colItem.MACAddress));
end;
end;
begin
try
CoInitialize(nil);
try
GetMacAddress;
Readln;
finally
CoUninitialize;
end;
except
on E:Exception do
Begin
Writeln(E.Classname, ': ', E.Message);
Readln;
End;
end;
end.
Here is some code working well for any computer on your network - may try it to get your own, using '127.0.0.1' as IP:
function GetRemoteMacAddress(const IP: AnsiString): TSockData;
// implements http://msdn.microsoft.com/en-us/library/aa366358(VS.85).aspx
type
TSendARP = function(DestIp: DWORD; srcIP: DWORD; pMacAddr: pointer; PhyAddrLen: Pointer): DWORD; stdcall;
const
HexChars: array[0..15] of AnsiChar = '0123456789ABCDEF';
var dwRemoteIP: DWORD;
PhyAddrLen: Longword;
pMacAddr : array [0..7] of byte;
I: integer;
P: PAnsiChar;
SendARPLibHandle: THandle;
SendARP: TSendARP;
begin
result := '';
SendARPLibHandle := LoadLibrary('iphlpapi.dll');
if SendARPLibHandle<>0 then
try
SendARP := GetProcAddress(SendARPLibHandle,'SendARP');
if #SendARP=nil then
exit; // we are not under 2K or later
dwremoteIP := inet_addr(pointer(IP));
if dwremoteIP<>0 then begin
PhyAddrLen := 8;
if SendARP(dwremoteIP, 0, #pMacAddr, #PhyAddrLen)=NO_ERROR then begin
if PhyAddrLen=6 then begin
SetLength(result,12);
P := pointer(result);
for i := 0 to 5 do begin
P[0] := HexChars[pMacAddr[i] shr 4];
P[1] := HexChars[pMacAddr[i] and $F];
inc(P,2);
end;
end;
end;
end;
finally
FreeLibrary(SendARPLibHandle);
end;
end;
This code is extracted from our freeware and open source framework, unit SynCrtSock.pas. See http://synopse.info/fossil

Resources