Good morning,
I'm wanting catch the total number of webcams in a computer, and traslate a source code that found in C++ (code is here) to Delphi like following:
const
MAX_PATH = 260;
CR_SUCCESS =$00000000;
type
HDevInfo = Pointer; { a pointer to a HID device info structure }
THDEVINFO = Pointer;
PSP_DevInfo_Data = ^TSP_DevInfo_Data;
SP_DEVINFO_DATA = packed record
cbSize: DWORD;
ClassGuid: TGUID;
DevInst: DWORD;
Reserved: LongWord;
end;
TSP_DevInfo_Data = SP_DEVINFO_DATA;
PDEVPROPKEY = ^TDEVPROPKEY;
DEVPROPKEY = packed record
fmtid : TGUID ;
pid : Pointer;
end;
TDEVPROPKEY = DEVPROPKEY;
DEVPROPTYPE = Pointer;
PCWSTR = PWCHAR;
TDEVINST = DWord;
TPOSVERSIONINFOW = ^TOSVERSIONINFOW;
TOSVERSIONINFOW = packed record
dwOSVersionInfoSize : DWORD ;
dwMajorVersion : DWORD ;
dwMinorVersion : DWORD ;
dwBuildNumber : DWORD ;
dwPlatformId : DWORD ;
szCSDVersion : array[0..127] of wchar;
end;
function SetupDiGetDeviceProperty(DeviceInfoSet: THDEVINFO; DeviceInfoData: PSP_DEVINFO_DATA; const PropertyKey: PDEVPROPKEY; var PropertyType:DEVPROPTYPE; PropertyBuffer:PBYTE;PropertyBufferSize:DWORD; RequiredSize:PDWORD; Flags:DWORD): BOOL; stdcall; external 'Setupapi.DLL' name 'SetupDiGetDevicePropertyW';
function SetupDiGetClassDevsW(const ClassGuid: PGUID; Enumerator: PCWSTR; hwndParent: HWND; Flags: DWORD): THDEVINFO; stdcall; external 'Setupapi.DLL' name 'SetupDiGetClassDevsW';
function SetupDiGetClassDevsA(ClassGuid: PGUID; const Enumerator: PAnsiChar;
hwndParent: HWND; Flags: DWORD): THandle; stdcall; external 'SetupApi.dll';
function SetupDiEnumDeviceInfo(DeviceInfoSet: THDEVINFO; MemberIndex: DWORD; DeviceInfoData: PSP_DEVINFO_DATA): BOOL; stdcall; external 'Setupapi.DLL' name 'SetupDiEnumDeviceInfo';
function CM_Get_Device_IDW(DeviceInstanceHandle: TDEVINst; Buffer:PCWSTR; Bufferlen : ULONG; ulFlags:ULONG): DWORD; stdcall; external 'Setupapi.DLL' name 'CM_Get_Device_IDW';
function SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet: THDEVINFO; const DeviceInfoData: SP_DevInfo_Data; Property_: DWORD; var PropertyRegDataType: DWORD; PropertyBuffer: PBYTE; PropertyBufferSize: DWORD; var RequiredSize: DWORD): BOOL; stdcall; external 'Setupapi.DLL' name 'SetupDiGetDeviceRegistryPropertyW';
function GetVersionExW(OsVersion:TPOSVERSIONINFOW): BOOL; stdcall; external 'Kernel32.dll' name 'GetVersionExW';
const
DIGCF_PRESENT = $00000002;
DIGCF_ALLCLASSES = $00000004;
DIGCF_PROFILE = $00000008;
DIGCF_DEVICEINTERFACE = $00000010;
INVALID_HANDLE_VALUE = DWORD($FFFFFFFF);
MAX_DEVICE_ID_LEN = 200;
SPDRP_DEVICEDESC = ($00000000) ;
DEVPKEY_Device_BusReportedDeviceDesc : TDEVPROPKEY = (fmtid : '{540b947e-8b40-45bc-a8a2-6a0b894cbda2}' ; pid : pointer(4) );
implementation
function GetNumCam: integer;
var
MemberIndex: integer;
dev: HDEVINFO;
DeviceInfoData: SP_DEVINFO_DATA;
begin
DeviceInfoData.cbSize := sizeof(DeviceInfoData);
dev := SetupDiGetClassDevsA(#GUID_DEVINTERFACE_IMAGE, nil, nil, DIGCF_PRESENT);
if dev = nil then begin
//raise exception.Create('Nenhum dispositivo encontrado');
exit;
end
else
while SetupDiEnumDeviceInfo(dev,MemberIndex, #DeviceInfoData) do
begin
MemberIndex:= MemberIndex + 1;
end;
Result:= MemberIndex;
end;
but I'm with difficulties for find a value for GUID_DEVINTERFACE_IMAGE in Delphi, and after assign this value for this constant. I saw in (this unit) but don't have this constant for I catch the value.
Someone have the exact value for this constant, please?
Thank in advance.
The value can be found in the documentation:
{0x6bdd1fc6L, 0x810f, 0x11d0, 0xbe, 0xc7, 0x08,
0x00, 0x2b, 0xe2, 0x09, 0x2f}
In Delphi you declare it like this:
const
GUID_DEVINTERFACE_IMAGE: TGUID = (
D1:$6bdd1fc6; D2:$810f; D3:$11d0; D4:($be, $c7, $08, $00, $2b, $e2, $09, $2f)
);
or like this:
const
GUID_DEVINTERFACE_IMAGE: TGUID = '{6bdd1fc6-810f-11d0-bec7-08002be2092f}';
Related
I have a library written in C and I have a header file with a description of the interface in C. The DLL has a function to get this interface. How to describe it correctly and get it in the DELPHI application?
using DllCallbackClassPtr = void*;
using DllCallbackFunction = void(*)(const char *, DllCallbackClassPtr);
#ifdef _WIN32
#include <Windows.h>
__interface IXeoma
{
public:
enum ConnectErrorCode {
OK = 0,
SERVER_NOT_FOUND,
WRONG_PASSWORD,
UNKNOWN
};
// return ConnectErrorCode
virtual int start(const char* connectionString) = 0;
virtual bool isConnected() = 0;
virtual void stop() = 0;
virtual void requestData(const char* request, const char* additionalData, DllCallbackClassPtr classPtr, DllCallbackFunction callbackFunc) = 0;
virtual const char* getRequestResult(const char* request) = 0;
virtual void setCameraRenderHandle(const char* previewId, HWND hWnd) = 0;
};
The library is loaded, but the function returns nil.
type
IXeoma = interface
function Start(connectionString: PChar): integer;
end;
type
TCreateXeomaInterface = function() : IXeoma; stdcall;
var
Form1: TForm1;
CreateXeomaInterface: TCreateXeomaInterface;
implementation
{$R *.dfm}
var
LibraryHandle: THandle;
procedure TForm1.Button1Click(Sender: TObject);
var
XeomaInt: IXeoma;
i: integer;
begin
LibraryHandle := LoadLibrary(PChar('D:\Projects\XeomaSDK\Win32\Debug\xeomaclientdll.dll'));
if LibraryHandle >= 32 then
begin
#CreateXeomaInterface := GetProcAddress(LibraryHandle, 'createXeomaInterface');
end;
XeomaInt := CreateXeomaInterface();
// Here XeomaInt = nil
end;
The __interface extension in Visual C++, and the interface keyword in Delphi, are not the same thing, and are not compatible with each other.
IXeoma in the C++ code is just an ordinary class type, not a COM interface. But in Delphi, all interfaces derive from IUnknown, and all classes derive from TObject, neither of which you want in this situation. So, you are going to have to use a plain record instead, and declare TCreateXeomaInterface as returning a pointer to that record.
Also, note that a Delphi record can't have virtual methods, but the C++ class does have them, so you are going to have to manually account for the C++ class's vtable in Delphi.
Try something like this:
type
DllCallbackClassPtr = Pointer;
DllCallbackFunction = procedure(Param1: PAnsiChar; Param2: DllCallbackClassPtr); cdecl;
IXeomaPtr = ^IXeoma;
IXeomaVTable = record
start: function(_Self: IXeomaPtr; connectionString: PAnsiChar): Integer; cdecl;
isConnected: function(_Self: IXeomaPtr): Boolean; cdecl;;
stop: procedure(_Self: IXeomaPtr); cdecl;
requestData: procedure(_Self: IXeomaPtr; request: PAnsiChar; additionalData: PAnsiChar; classPtr: DllCallbackClassPtr; callbackFunc: DllCallbackFunction); cdecl;
getRequestResult: function(_Self: IXeomaPtr; request: PAnsiChar): PAnsiChar; cdecl;
setCameraRenderHandle: procedure(_Self: IXeomaPtr; previewId: PAnsiChar; hWnd: HWND); cdecl;
end;
ConnectErrorCode = (
OK = 0,
SERVER_NOT_FOUND,
WRONG_PASSWORD,
UNKNOWN
);
IXeoma = record
vtable: ^IXeomaVTable:
end;
type
TCreateXeomaInterface = function() : IXeomaPtr; stdcall;
var
Form1: TForm1;
CreateXeomaInterface: TCreateXeomaInterface;
implementation
{$R *.dfm}
var
LibraryHandle: THandle;
procedure TForm1.Button1Click(Sender: TObject);
var
XeomaInt: IXeomaPtr;
i: integer;
begin
XeomaInt := nil;
LibraryHandle := LoadLibrary('D:\Projects\XeomaSDK\Win32\Debug\xeomaclientdll.dll');
if LibraryHandle >= 32 then
begin
#CreateXeomaInterface := GetProcAddress(LibraryHandle, 'createXeomaInterface');
XeomaInt := CreateXeomaInterface();
if XeomaInt <> nil then
XeomaInt^.vtable^.start(XeomaInt, '123:123#localhost:8090');
end;
...
end;
i'm trying disconnect a socket at AcceptExHookProc routine.
i hooked AcceptEx at .dll and injected at .exe app who i want disconnect socket if ip connected at socket is same at my if.
the program uses AcceptEx, not WSAAccept (i know about about the callback using CF_REJECT) but isn't the case for this program since him uses AcceptEx from Winsock library (not winsock2).
const WSAID_DISCONNECTEX: TGuid = '{7fda2e11-8630-436f-a031-f536a6eec157}';
type
LPFN_DISCONNECTEX = function(const hSocket : TSocket; AOverlapped:
POverlapped; const dwFlags : DWORD; const dwReserved : DWORD) : BOOL; stdcall;
function GetAddress(ASocket: TSocket; const AName: String; const AGuid: TGUID): Pointer; inline; overload;
var
BytesSend: DWORD;
begin
if WSAIoctl(ASocket, SIO_GET_EXTENSION_FUNCTION_POINTER, #AGuid, DWORD(SizeOf(TGuid)),
#Result, DWORD(SizeOf(FARPROC)), BytesSend, nil, nil) <> 0 then
Result := nil;
end;
function AcceptExHookProc(sListenSocket, sAcceptSocket: TSocket;
lpOutputBuffer: Pointer; dwReceiveDataLength, dwLocalAddressLength,
dwRemoteAddressLength: DWORD; var lpdwBytesReceived: DWORD;
lpOverlapped: POverlapped): BOOL; stdcall;
var
IP : String;
LRet, RRet : Winsock.PSockAddr;
lsize, rsize : Integer;
DisconnectEx : LPFN_DISCONNECTEX;
BytesOut : DWORD;
Res : Integer;
begin
Result := TrampolineAcceptEx(sListenSocket, sAcceptSocket, lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived, lpOverlapped);
lsize := 32;
rsize := 32;
Winsock.GetAcceptExSockaddrs(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, LRet, lsize, RRet, rsize);
IP := Winsock.inet_ntoa(RRet.sin_addr);
if (IP = '177.222.164.65') then
begin
Res := setsockopt(sAcceptSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, #sListenSocket, SizeOf(sListenSocket));
WriteLn(Format('Result %d / %d', [Res, GetLastError]));
// Show result - 1 and sock error 10057
DisconnectEx := GetAddress(sAcceptSocket, 'DisconnectEx', WSAID_DISCONNECTEX);
if #DisconnectEx <> nil then
if DisconnectEx(sAcceptSocket, nil, TF_REUSE_SOCKET, 0) then
WriteLn('Disconnect ok')
else
WriteLn('Disconnect falhou + ' + IntToStr(GetLastError));
// Show sock error 10057
WriteLn(Format(' [%s] Connection from IP (%s) DISCONNECT', [TimeToStr(Now), IP]));
end
else
begin
WriteLn(Format('[%s] Connection from IP (%s)', [TimeToStr(Now), IP]));
end;
end;
works but return false and getlasterror show socket error 10057 (Socket is not connected.)
but connection still estabilished (i check at process hacker)
I'm trying to implement AES GCM using CNG Windows API and stuck on last step.
Disclaimer: Do not be afraid with that amount of code, most of it is just WinAPI functions and structures declaration, scroll down to actual question text. Thanks.
Uses:
uses System.Classes, Winapi.Windows, System.SysUtils;
Interface section (NOT everything is correct here (see accepted answer), added just in case if somebody will try to reproduce):
type
BCRYPT_KEY_LENGTHS_STRUCT = packed record
dwMinLength, dwMaxLength, dwIncrement: ULONG;
end;
BCRYPT_AUTH_TAG_LENGTHS_STRUCT = BCRYPT_KEY_LENGTHS_STRUCT;
BCRYPT_KEY_DATA_BLOB_HEADER = packed record
dwMagic, dwVersion, cbKeyData: ULONG;
end;
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO = packed record
cbSize, dwInfoVersion: ULONG;
pbNonce: Pointer;
cbNonce: ULONG;
pbAuthData: Pointer;
cbAuthData: ULONG;
pbTag: Pointer;
cbTag: ULONG;
pbMacContext: Pointer;
cbMacContext, cbAAD: ULONG;
cbData: ULONGLONG;
dwFlags: ULONG;
end;
const
BCRYPT_CHAINING_MODE = 'ChainingMode';
BCRYPT_CHAIN_MODE_GCM = 'ChainingModeGCM';
BCRYPT_AUTH_TAG_LENGTH = 'AuthTagLength';
BCRYPT_KEY_DATA_BLOB = 'KeyDataBlob';
//
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION = $00000001;
//
BCrypt = 'Bcrypt.dll';
function BCryptOpenAlgorithmProvider(var phAlgorithm: Pointer;
pszAlgId: PWideChar; pszImplementation: PWideChar; dwFlags: ULONG): DWORD;
stdcall; external BCrypt;
function BCryptSetProperty(hObject: Pointer; pszProperty: PWideChar;
pbInput: Pointer; cbInput: ULONG; dwFlags: ULONG): DWORD; stdcall;
external BCrypt;
function BCryptGetProperty(hObject: Pointer; pszProperty: PWideChar;
pbOutput: Pointer; cbOutput: ULONG; var pcbResult: ULONG; dwFlagd: ULONG)
: DWORD; stdcall; external BCrypt;
function BCryptGenerateSymmetricKey(hAlgorithm: Pointer; var phKey: Pointer;
pbKeyObject: Pointer; cbKeyObject: ULONG; pbSecret: Pointer; cbSecret: ULONG;
dwFlags: ULONG): DWORD; stdcall; external BCrypt;
function BCryptGenRandom(phAlgorithm: Pointer; pbBuffer: Pointer;
cbBuffer: ULONG; dwFlags: ULONG): DWORD; stdcall; external BCrypt;
function BCryptExportKey(hKey: Pointer; hExportKey: Pointer;
pszBlobType: PWideChar; pbOutput: Pointer; cbOutput: ULONG;
var pcbResult: ULONG; dwFlags: ULONG): DWORD; stdcall; external BCrypt;
function BCryptEncrypt(hKey: Pointer; pbInput: Pointer; cbInput: ULONG;
pPaddingInfo: Pointer; pbIV: Pointer; cbIV: ULONG; pbOutput: Pointer;
cbOutput: ULONG; var pcbResult: ULONG; dwFlags: ULONG): DWORD; stdcall;
function BCryptDestroyKey(hKey: Pointer): DWORD; stdcall; external BCrypt;
function BCryptCloseAlgorithmProvider(hAlgorithm: Pointer; dwFlags: ULONG)
: DWORD; stdcall; external BCrypt;
Implementation:
function GetCryptoRandomBytes(var Buffer: TBytes; Size: DWORD): Boolean;
var
Status: DWORD;
hAlgorithm, hKey: Pointer;
begin
result := False;
Status := BCryptOpenAlgorithmProvider(hAlgorithm,
BCRYPT_RNG_ALGORITHM, nil, 0);
if Status = 0 then
begin
SetLength(Buffer, Size);
Status := BCryptGenRandom(hAlgorithm, Buffer, Size, 0);
if Status = 0 then
result := True;
end;
BCryptCloseAlgorithmProvider(hAlgorithm, 0)
end;
function AESGCMEncrypt(var Data, AAD, Key, IV, Tag, EncryptedData: TBytes;
KeyLength: DWORD = 32): Boolean;
const
AES_GCM_IV_LENGTH = 12; // nonce
var
Status, KeyLen, BytesDone, BlockLength: DWORD;
hAlgorithm, hKey: Pointer;
TagLength: BCRYPT_AUTH_TAG_LENGTHS_STRUCT;
KeyDataBlobHeader: BCRYPT_KEY_DATA_BLOB_HEADER;
AuthCiferModeInfo: BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO;
KeyTemp: TBytes;
begin
result := False;
BytesDone := 0;
Status := BCryptOpenAlgorithmProvider(hAlgorithm,
BCRYPT_AES_ALGORITHM, nil, 0);
if Status = 0 then
begin
KeyLen := Length(BCRYPT_CHAIN_MODE_GCM);
Status := BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE,
PChar(BCRYPT_CHAIN_MODE_GCM), BytesDone, 0);
if Status = 0 then
begin
KeyLen := SizeOf(TagLength);
Status := BCryptGetProperty(hAlgorithm, BCRYPT_AUTH_TAG_LENGTH,
#TagLength, KeyLen, BytesDone, 0);
if (Status = 0) and GetCryptoRandomBytes(KeyTemp, KeyLength) then
begin
Status := BCryptGenerateSymmetricKey(hAlgorithm, hKey, nil, 0, KeyTemp,
KeyLength, 0);
if Status = 0 then
begin
Status := BCryptExportKey(hKey, nil, BCRYPT_KEY_DATA_BLOB, nil, 0,
KeyLen, 0); // Get size
if Status = 0 then
begin
SetLength(KeyTemp, KeyLen);
Status := BCryptExportKey(hKey, nil, BCRYPT_KEY_DATA_BLOB, KeyTemp,
KeyLen, KeyLen, 0);
if Status = 0 then
begin
Move(KeyTemp[0], KeyDataBlobHeader, SizeOf(KeyDataBlobHeader));
SetLength(Key, KeyDataBlobHeader.cbKeyData);
Move(KeyTemp[SizeOf(KeyDataBlobHeader)], Key[0],
KeyDataBlobHeader.cbKeyData);
if GetCryptoRandomBytes(IV, AES_GCM_IV_LENGTH) then
begin
SetLength(Tag, TagLength.dwMaxLength);
SetLength(EncryptedData, Length(Data)); // same length as source
FillChar(AuthCiferModeInfo, SizeOf(AuthCiferModeInfo), #0);
with AuthCiferModeInfo do
begin
cbSize := SizeOf(AuthCiferModeInfo);
dwInfoVersion := BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION;
pbNonce := IV;
cbNonce := AES_GCM_IV_LENGTH;
pbAuthData := AAD;
cbAuthData := Length(AAD);
pbTag := Tag;
cbTag := TagLength.dwMaxLength;
end;
KeyLen := Length(Data);
Status := BCryptEncrypt(hKey, Data, KeyLen, #AuthCiferModeInfo,
nil, 0, EncryptedData, KeyLen, BytesDone, 0);
// Status = $C000000D = STATUS_INVALID_PARAMETER
if Status = 0 then
result := True
else // Free all buffers
begin
SetLength(Tag, 0);
SetLength(EncryptedData, 0);
SetLength(Key, 0);
SetLength(IV, 0);
end;
end
else // Free all buffers
begin
SetLength(Key, 0);
SetLength(IV, 0);
end;
end;
end;
BCryptDestroyKey(hKey);
end;
SetLength(KeyTemp, 0); // Free buffer
end;
end;
end;
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
end;
Here actual question started
I know it seems like there's a lot of code, but it's not the point. All works perfectly except last BCryptEncrypt() call which returns STATUS_INVALID_PARAMETER (0xC000000D).
I've tried to follow docs, so I have no idea which of parameters doesn't fit. I guess issue is in BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO structure, but can't find it.
So, dear WinAPI Gods, could you please point me what have I done wrong? I would really appreciate any help: links, debugigng ideas, etc.
Here's how I call this function:
var
Key, Tag, IV, AAD, Data, EncData: TBytes;
src, add_data: string;
begin
src := 'test_string_1234';
add_data := '12345678';
Data := TEncoding.UTF8.GetBytes(src);
AAD := TEncoding.UTF8.GetBytes(add_data);
AESGCMEncrypt(Data, AAD, Key, IV, Tag, EncData);
end;
P.S. I'm using Delphi 10.3 Community.
UPDATE
I've tried to check how this API works in C++ and ... just look. Here is BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO structure (copied from docs):
typedef struct _BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO {
ULONG cbSize; // 4 bytes
ULONG dwInfoVersion; // 4 bytes
PUCHAR pbNonce; // 8 bytes (on x64)
ULONG cbNonce; // 4 bytes
PUCHAR pbAuthData; // 8 bytes (on x64)
ULONG cbAuthData; // 4 bytes
PUCHAR pbTag; // 8 bytes (on x64)
ULONG cbTag; // 4 bytes
PUCHAR pbMacContext; // 8 bytes (on x64)
ULONG cbMacContext; // 4 bytes
ULONG cbAAD; // 4 bytes
ULONGLONG cbData; // 8 bytes
ULONG dwFlags; // 4 bytes
} BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO, *PBCRYPT_AUTHENTICATED_CIPHER_MODE_INFO;
Let's calculate total size: 4 + 4 + 8 + 4 + 8 + 4 + 8 + 4 + 8 + 4 + 4 + 8 + 4 = 72. BUT sizeof(BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO) returns 88. I have no clue, where 16 additional bytes came from. Could somebody explain me??
BCryptEncrypt() call which returns STATUS_INVALID_PARAMETER
(0xC000000D).
BCryptEncrypt(keyHandle, pt, sizeof(pt), &authInfo, NULL, 0, ct, sizeof(ct), &bytesDone, 0);
Show values passed in above function that work for me, then you can compare with yours.
Update:
After comparing, it turns out that the size (cbSize) of BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO structure is wrong calculated. It expects 88 but pass in 72. It is related to "Padding and Alignment of Structure Members".
cbSize
The size, in bytes, of this structure. Do not set this field directly.
Use the BCRYPT_INIT_AUTH_MODE_INFO macro instead.
Small update
To let code from question work properly change BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO = packed record to BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO = record.
How can I list all users of an AD group in Delphi 7?
One of the options, as I know, is to use a string LDAP. I got a LDAP string, but how to use it?
I tried to use WinAPI, example from internet that i search
function TSequrity.DomainUsers: String;
var
EntiesRead: DWORD;
TotalEntries: DWORD;
UserInfo: lpUSER_INFO_1;
lpBuffer: Pointer;
ResumeHandle: DWORD;
Counter: Integer;
NetApiStatus: LongWord;
w:WideString;
begin
ResumeHandle := 0;
w:=Domain;
NetApiStatus := NetUserEnum(#w[1], 1, 0, lpBuffer, 0, EntiesRead, TotalEntries, ResumeHandle);
NetApiBufferFree(lpBuffer);
NetApiStatus := NetUserEnum(#w[1], 1, 0, lpBuffer, TotalEntries*TotalEntries, EntiesRead, TotalEntries, ResumeHandle);
UserInfo := lpBuffer;
for Counter := 0 to EntiesRead - 1 do
begin
Result:=Result+WideCharToString(UserInfo^.usri1_name)+#13#10;
Inc(UserInfo);
end;
NetApiBufferFree(lpBuffer);
end;
It find local users. But im need to find users of domain group.
Here's an example using "NetGroupGetUsers". Please be aware that this does not work with nested groups (groups containing other groups).
{$WARN SYMBOL_PLATFORM OFF}
program DomainGroupGetUsersTest;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows, Classes;
const
netapi32lib = 'netapi32.dll';
type
PGroupUsersInfo0 = ^TGroupUsersInfo0;
_GROUP_USERS_INFO_0 = record
grui0_name: LPWSTR;
end;
TGroupUsersInfo0 = _GROUP_USERS_INFO_0;
GROUP_USERS_INFO_0 = _GROUP_USERS_INFO_0;
NET_API_STATUS = DWORD;
LPBYTE = ^BYTE;
function NetApiBufferFree (Buffer: Pointer): NET_API_STATUS; stdcall;
external netapi32lib;
function NetGroupGetUsers (servername: LPCWSTR; groupname: LPCWSTR;
level: DWORD; var bufptr: LPBYTE; prefmaxlen: DWORD; var entriesread: DWORD;
var totalentries: DWORD; ResumeHandle: PDWORD): NET_API_STATUS; stdcall;
external netapi32lib;
function DomainGroupGetUsers (const sGroup: WideString;
const UserList: TStrings;
const sLogonServer: WideString) : Boolean;
{ "sLogonServer" must be prefixed with "\\".
"sGroup" must contain the group name only. }
type
TaUserGroup = array of TGroupUsersInfo0;
const
PREF_LEN = 1024;
var
pBuffer : LPBYTE;
i : Integer;
Res : NET_API_STATUS;
dwRead, dwTotal : DWord;
hRes : DWord;
begin
Assert (sGroup <> '');
Assert (sLogonServer <> '');
Assert (UserList <> NIL);
UserList.Clear;
Result := true;
hRes := 0;
repeat
Res := NetGroupGetUsers (PWideChar (sLogonServer), PWideChar (sGroup),
0, pBuffer, PREF_LEN, dwRead, dwTotal,
PDWord (#hRes));
if (Res = Error_Success) or (Res = ERROR_MORE_DATA) then
begin
if (dwRead > 0) then
for i := 0 to dwRead - 1 do
with TaUserGroup (pBuffer) [i] do
UserList.Add (grui0_name);
NetApiBufferFree (pBuffer);
end { if }
else Result := false;
until (Res <> ERROR_MORE_DATA);
end; { DomainGroupGetUsers }
var
UserList : TStringList;
iIndex : Integer;
begin
UserList := TStringList.Create;
try
DomainGroupGetUsers ('Domain Users', UserList,
GetEnvironmentVariable ('LOGONSERVER'));
for iIndex := 0 to UserList.Count - 1 do
WriteLn (UserList [iIndex]);
finally
UserList.Free;
end; { try / finally }
if (DebugHook <> 0) then
begin
WriteLn;
Write ('Press [Enter] to continue ...');
ReadLn;
end; { if }
end.
I have a delphi project that works fine in delphi 6, but when I upgraded to XE it does not work.
I know it has to do with the new unicode type in delphi XE, I have tried changing the definition of the parameter from pchar to pansichar, ansichar but no succes so far. Can anyone see what i have done wrong?
My project calls a function in an third party dll that is defined like this:
type
PPChar = array of PChar;
{$EXTERNALSYM gsapi_init_with_args}
function gsapi_init_with_args(pinstance:Pgs_main_instance;argc:integer;argv:PPChar):integer; stdcall;
Implementation
{$EXTERNALSYM gsapi_init_with_args}
function gsapi_init_with_args; stdcall; external gsdll32 name 'gsapi_init_with_args';
And here is how I call the function.
procedure PSPDF(input : string; output:string);
var
code:integer;
instance:Pointer;
argv:array of PAnsiChar;
begin
new(instance);
setlength(argv,10);
code:=gsapi_new_instance(#instance,nil);
if code<>0 then
begin
raise Exception.Create('Impossible to open an instance of ghostscript. Error code: '+IntToStr(code));
end;
try
argv[0] := PAnsiChar('ps2pdf');
argv[1] := PAnsiChar('-dNOPAUSE');
argv[2] := PAnsiChar('-dBATCH');
argv[3] := PAnsiChar('-dSAFER');
argv[4] := PAnsiChar('-sDEVICE=pdfwrite');
argv[5] := PAnsiChar(PAnsiString('-sOutputFile='+output));
argv[6] := PAnsiChar('-c');
argv[7] := PAnsiChar('.setpdfwrite');
argv[8] := PAnsiChar('-f');
argv[9] := PAnsiChar(PAnsiString(input));
gsapi_new_instance(instance, nil);
code := gsapi_init_with_args(instance,length(argv),#argv[0]);
if code<0 then
raise Exception.Create('ERROR: init_args: '+IntToStr(code));
gsapi_exit(instance);
gsapi_delete_instance(instance);
finally
end;
end;
I will very much appreciate if someone can help me out.
Mario.
Changing PChar to PAnsiChar is the correct thing to do, however array of ... is not safe to use in DLL function parameters and was the wrong thing to use even in your Delphi 6 project. After looking at the official Ghostscript documentation, try this instead, in both projects:
interface
type
PPAnsiChar = ^PAnsiChar;
{$NODEFINE PPAnsiChar}
function gsapi_new_instance(var pinstance: Pointer; caller_handle: Pointer): Integer; stdcall;
{$EXTERNALSYM gsapi_new_instance}
procedure gsapi_delete_instance(instance: Pointer); stdcall;
{$EXTERNALSYM gsapi_delete_instance}
function gsapi_init_with_args(instance: Pointer; argc: Integer; argv: PPAnsiChar): Integer; stdcall;
{$EXTERNALSYM gsapi_init_with_args}
function gsapi_exit(instance: Pointer): Integer; stdcall;
{$EXTERNALSYM gsapi_exit}
implementation
function gsapi_new_instance; external gsdll32 name 'gsapi_new_instance';
procedure gsapi_delete_instance; external gsdll32 name 'gsapi_delete_instance';
function gsapi_init_with_args; external gsdll32 name 'gsapi_init_with_args';
function gsapi_exit; external gsdll32 name 'gsapi_exit';
.
procedure PSPDF(input : AnsiString; output: AnsiString);
var
code:integer;
instance: Pointer;
argv: array of PAnsiChar;
begin
code := gsapi_new_instance(instance, nil);
if code < 0 then
raise Exception.Create('Impossible to open an instance of ghostscript. Error code: '+IntToStr(code));
try
SetLength(argv, 10);
argv[0] := PAnsiChar('ps2pdf');
argv[1] := PAnsiChar('-dNOPAUSE');
argv[2] := PAnsiChar('-dBATCH');
argv[3] := PAnsiChar('-dSAFER');
argv[4] := PAnsiChar('-sDEVICE=pdfwrite');
argv[5] := PAnsiChar('-sOutputFile='+output);
argv[6] := PAnsiChar('-c');
argv[7] := PAnsiChar('.setpdfwrite');
argv[8] := PAnsiChar('-f');
argv[9] := PAnsiChar(input);
code := gsapi_init_with_args(instance, Length(argv), #argv[0]);
if code < 0 then
raise Exception.Create('ERROR: init_args: '+IntToStr(code));
try
...
finally
gsapi_exit(instance);
end;
finally
gsapi_delete_instance(instance);
end;
end;
Update: here is a corrected version of the gsapi.pas unit that should work in both Delphi versions:
// Copyright (c) 2001-2002 Alessandro Briosi
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
//
// This software was written by Alessandro Briosi with the
// assistance of Russell Lang, as an example of how the
// Ghostscript DLL may be used Delphi.
//
unit gsapi;
interface
uses
Windows;
// {$HPPEMIT '#include <iminst.h>'}
const
gsdll32 = 'gsdll32.dll';
STDIN_BUF_SIZE = 128;
{$EXTERNALSYM STDIN_BUF_SIZE}
STDOUT_BUF_SIZE = 128;
{$EXTERNALSYM STDOUT_BUF_SIZE}
STDERR_BUF_SIZE = 128;
{$EXTERNALSYM STDERR_BUF_SIZE}
DISPLAY_VERSION_MAJOR = 1;
{$EXTERNALSYM DISPLAY_VERSION_MAJOR}
DISPLAY_VERSION_MINOR = 0;
{$EXTERNALSYM DISPLAY_VERSION_MINOR}
//* Define the color space alternatives */
DISPLAY_COLORS_NATIVE = $01;
{$EXTERNALSYM DISPLAY_COLORS_NATIVE}
DISPLAY_COLORS_GRAY = $02;
{$EXTERNALSYM DISPLAY_COLORS_GRAY}
DISPLAY_COLORS_RGB = $04;
{$EXTERNALSYM DISPLAY_COLORS_RGB}
DISPLAY_COLORS_CMYK = $08;
{$EXTERNALSYM DISPLAY_COLORS_CMYK}
DISPLAY_COLORS_MASK = $000f;
{$EXTERNALSYM DISPLAY_COLORS_MASK}
//* Define whether alpha information, or an extra unused bytes is included */
//* DISPLAY_ALPHA_FIRST and DISPLAY_ALPHA_LAST are not implemented */
DISPLAY_ALPHA_NONE = $00;
{$EXTERNALSYM DISPLAY_ALPHA_NONE}
DISPLAY_ALPHA_FIRST = $10;
{$EXTERNALSYM DISPLAY_ALPHA_FIRST}
DISPLAY_ALPHA_LAST = $20;
{$EXTERNALSYM DISPLAY_ALPHA_LAST}
DISPLAY_UNUSED_FIRST = $40; //* e.g. Mac xRGB */
{$EXTERNALSYM DISPLAY_UNUSED_FIRST}
DISPLAY_UNUSED_LAST = $80; //* e.g. Windows BGRx */
{$EXTERNALSYM DISPLAY_UNUSED_LAST}
DISPLAY_ALPHA_MASK = $0070;
{$EXTERNALSYM DISPLAY_ALPHA_MASK}
// * Define the depth per component for DISPLAY_COLORS_GRAY,
// * DISPLAY_COLORS_RGB and DISPLAY_COLORS_CMYK,
// * or the depth per pixel for DISPLAY_COLORS_NATIVE
// * DISPLAY_DEPTH_2 and DISPLAY_DEPTH_12 have not been tested.
// *
DISPLAY_DEPTH_1 = $0100;
{$EXTERNALSYM DISPLAY_DEPTH_1}
DISPLAY_DEPTH_2 = $0200;
{$EXTERNALSYM DISPLAY_DEPTH_2}
DISPLAY_DEPTH_4 = $0400;
{$EXTERNALSYM DISPLAY_DEPTH_4}
DISPLAY_DEPTH_8 = $0800;
{$EXTERNALSYM DISPLAY_DEPTH_8}
DISPLAY_DEPTH_12 = $1000;
{$EXTERNALSYM DISPLAY_DEPTH_12}
DISPLAY_DEPTH_16 = $2000;
{$EXTERNALSYM DISPLAY_DEPTH_16}
//* unused (1<<14) */
//* unused (1<<15) */
DISPLAY_DEPTH_MASK = $ff00;
{$EXTERNALSYM DISPLAY_DEPTH_MASK}
// * Define whether Red/Cyan should come first,
// * or whether Blue/Black should come first
// */
DISPLAY_BIGENDIAN = $00000; //* Red/Cyan first */
{$EXTERNALSYM DISPLAY_BIGENDIAN}
DISPLAY_LITTLEENDIAN = $10000; //* Blue/Black first */
{$EXTERNALSYM DISPLAY_LITTLEENDIAN}
DISPLAY_ENDIAN_MASK = $00010000;
{$EXTERNALSYM DISPLAY_ENDIAN_MASK}
//* Define whether the raster starts at the top or bottom of the bitmap */
DISPLAY_TOPFIRST = $00000; //* Unix, Mac */
{$EXTERNALSYM DISPLAY_TOPFIRST}
DISPLAY_BOTTOMFIRST = $20000; //* Windows */
{$EXTERNALSYM DISPLAY_BOTTOMFIRST}
DISPLAY_FIRSTROW_MASK = $00020000;
{$EXTERNALSYM DISPLAY_FIRSTROW_MASK}
//* Define whether packing RGB in 16-bits should use 555
// * or 565 (extra bit for green)
// */
DISPLAY_NATIVE_555 = $00000;
{$EXTERNALSYM DISPLAY_NATIVE_555}
DISPLAY_NATIVE_565 = $40000;
{$EXTERNALSYM DISPLAY_NATIVE_565}
DISPLAY_555_MASK = $00040000;
{$EXTERNALSYM DISPLAY_555_MASK}
type
TGSAPIrevision = record
product: PAnsiChar;
copyright: PAnsiChar;
revision: Longint;
revisiondat: Longint;
end;
TStdioFunction = function(caller_handle: Pointer; buf: PAnsiChar; len: Integer): Integer; stdcall;
TPollFunction = function(caller_handle: Pointer): Integer; stdcall;
TDisplayEvent = function(handle: Pointer; device: Pointer): Integer; cdecl;
TDisplayPreResizeEvent = function(handle: Pointer; device: Pointer;
width: Integer; height: Integer; raster: Integer; format: UINT): Integer; cdecl;
TDisplayResizeEvent = function(handle: Pointer; device: Pointer;
width: Integer; height: Integer; raster: Integer; format: UINT; pimage: PAnsiChar): Integer; cdecl;
TDisplayPageEvent = function(handle: Pointer; device: Pointer; copies: Integer; flush: Integer): Integer; cdecl;
TDisplayUpdateEvent = function(handle: Pointer; device: Pointer; x: Integer; y: Integer; w: Integer; h: Integer): Integer; cdecl;
TDisplayMemAlloc = procedure(handle: Pointer; device: Pointer; size: ulong); cdecl;
TDisplayMemFree = function(handle: Pointer; device: Pointer; mem: Pointer): Integer; cdecl;
TDisplayCallback = record
size: Integer;
version_major: Integer;
version_minor: Integer;
// New device has been opened */
// This is the first event from this device. */
display_open: TDisplayEvent;
// Device is about to be closed. */
// Device will not be closed until this function returns. */
display_preclose: TDisplayEvent;
// Device has been closed. */
// This is the last event from this device. */
display_close: TDisplayEvent;
// Device is about to be resized. */
// Resize will only occur if this function returns 0. */
// raster is byte count of a row. */
display_presize: TDisplayPreResizeEvent;
// Device has been resized. */
// New pointer to raster returned in pimage */
display_size: TDisplayResizeEvent;
// flushpage */
display_sync: TDisplayEvent;
// showpage */
// If you want to pause on showpage, then don't return immediately */
display_page: TDisplayPageEvent;
// Notify the caller whenever a portion of the raster is updated. */
// This can be used for cooperative multitasking or for
// progressive update of the display.
// This function pointer may be set to NULL if not required.
//
display_update: TDisplayUpdateEvent;
// Allocate memory for bitmap */
// This is provided in case you need to create memory in a special
// way, e.g. shared. If this is NULL, the Ghostscript memory device
// allocates the bitmap. This will only called to allocate the
// image buffer. The first row will be placed at the address
// returned by display_memalloc.
//
display_memalloc: TDisplayMemAlloc;
// Free memory for bitmap */
// If this is NULL, the Ghostscript memory device will free the bitmap */
display_memfree: TDisplayMemFree;
end;
PPAnsiChar = ^PAnsiChar;
{$NODEFINE PPAnsiChar}
function gsapi_revision(var pr: TGSAPIrevision; len: Integer): Integer; stdcall;
{$EXTERNALSYM gsapi_revision}
function gsapi_new_instance(var pinstance: Pointer; caller_handle: Pointer): Integer; stdcall;
{$EXTERNALSYM gsapi_new_instance}
procedure gsapi_delete_instance(pinstance: Pointer); stdcall;
{$EXTERNALSYM gsapi_delete_instance}
function gsapi_set_stdio(pinstance: Pointer;
stdin_fn: TStdioFunction; stdout_fn: TStdioFunction;
stderr_fn: TStdioFunction): Integer; stdcall;
{$EXTERNALSYM gsapi_set_stdio}
function gsapi_set_poll(pinstance: Pointer; poll_fn: TPollFunction): Integer; stdcall;
{$EXTERNALSYM gsapi_set_poll}
function gsapi_set_display_callback(pinstance: Pointer; const callback: TDisplayCallback): Integer; stdcall;
{$EXTERNALSYM gsapi_set_display_callback}
function gsapi_init_with_args(pinstance: Pointer; argc: Integer; argv: PPAnsiChar): Integer; stdcall;
{$EXTERNALSYM gsapi_init_with_args}
function gsapi_run_string_begin(pinstance: Pointer; user_errors: Integer; var pexit_code: Integer): Integer; stdcall;
{$EXTERNALSYM gsapi_run_string_begin}
function gsapi_run_string_continue(pinstance: Pointer; str: PAnsiChar; len: Integer; user_errors: Integer; var pexit_code: Integer): Integer; stdcall;
{$EXTERNALSYM gsapi_run_string_continue}
function gsapi_run_string_end(pinstance: Pointer; user_errors: Integer; var pexit_code: Integer): Integer; stdcall;
{$EXTERNALSYM gsapi_run_string_end}
function gsapi_run_string_with_length(pinstance: Pointer; str: PAnsiChar; len: Integer; user_errors: Integer; var pexit_code: Integer): Integer; stdcall;
{$EXTERNALSYM gsapi_run_string_with_length}
function gsapi_run_string(pinstance: Pointer; str: PAnsiChar; user_errors: Integer; var pexit_code: Integer): Integer; stdcall;
{$EXTERNALSYM gsapi_run_string}
function gsapi_run_file(pinstance: Pointer; file_name: PAnsiChar; user_errors: Integer; var pexit_code: Integer): Integer; stdcall;
{$EXTERNALSYM gsapi_run_file}
function gsapi_exit(pinstance: Pointer): Integer; stdcall;
{$EXTERNALSYM gsapi_exit}
implementation
function gsapi_revision; external gsdll32 name 'gsapi_revision';
function gsapi_new_instance; external gsdll32 name 'gsapi_new_instance';
procedure gsapi_delete_instance; external gsdll32 name 'gsapi_delete_instance';
function gsapi_set_stdio; external gsdll32 name 'gsapi_set_stdio';
function gsapi_set_poll; external gsdll32 name 'gsapi_set_poll';
function gsapi_set_display_callback; external gsdll32 name 'gsapi_set_display_callback';
function gsapi_init_with_args; external gsdll32 name 'gsapi_init_with_args';
function gsapi_run_string_begin; external gsdll32 name 'gsapi_run_string_begin';
function gsapi_run_string_continue; external gsdll32 name 'gsapi_run_string_continue';
function gsapi_run_string_end; external gsdll32 name 'gsapi_run_string_end';
function gsapi_run_string_with_length; external gsdll32 name 'gsapi_run_string_with_length';
function gsapi_run_string; external gsdll32 name 'gsapi_run_string';
function gsapi_run_file; external gsdll32 name 'gsapi_run_file';
function gsapi_exit; external gsdll32 name 'gsapi_exit';
end.
The old Delphi 6 PChar is PAnsiChar on Unicode Delphi (2009+), so everything should work if you change all the PChar references to PAnsiChar.
(Including your Pgs_main_instance declaration, if any PChar is over there)
type
PPAnsiChar = array of PAnsiChar;
{$EXTERNALSYM gsapi_init_with_args}
function gsapi_init_with_args(pinstance: Pgs_main_instance;
argc: Integer; argv:PPAnsiChar): Integer; stdcall;
implementation
function gsapi_init_with_args(pinstance: Pgs_main_instance;
argc: Integer; argv:PPAnsiChar): Integer;
external gsdll32 name 'gsapi_init_with_args';
Calling code:
var
argv:PPAnsiChar;
instance: Pointer;
begin
new(instance); //how many bytes, this really doesn't make sense with a untyped pointer!
setlength(argv, 4);
argv[0] := PAnsiChar('ps2pdf');
argv[1] := PAnsiChar('-dNOPAUSE');
argv[2] := PAnsiChar('-dBATCH');
argv[3] := PAnsiChar('-dSAFER');
gsapi_init_with_args(instance, Length(argv), argv);
end;
To understand what's new in Unicode, I advise you to read the Delphi and Unicode white paper from Marco Cantù.