what is the representation of PVOID in JNA?
PVOID is a Pointer to anything. The equivalent JNA class should be Pointer.
Related
I tried to use the below code snippet to call GetProcessAffinityMask in the windows api.
var
procaffmask,
sysaffmask : DWord;
begin
GetProcessAffinityMask(GetCurrentProcess, procaffmask, sysaffmask);
end;
Upon compilation I got the following error message......
[dcc32 Error] UnitfrmMain.pas(54): E2033 Types of actual and formal var parameters must be identical
The C++ syntax for the API call is below:
BOOL WINAPI GetProcessAffinityMask(
_In_ HANDLE hProcess,
_Out_ PDWORD_PTR lpProcessAffinityMask,
_Out_ PDWORD_PTR lpSystemAffinityMask
);
So then I changed the DWORD to a PDWORD but that did not fix it.
Can anybody tell me how to fix this? I see Delphi code samples around the internet that do not use pointers.
Here is the declaration of GetProcessAffinityMask() in Delphi's Winapi.Windows unit:
function GetProcessAffinityMask(hProcess: THandle;
var lpProcessAffinityMask, lpSystemAffinityMask: DWORD_PTR): BOOL; stdcall;
DWORD and DWORD_PTR are different data types. DWORD_PTR is not a "pointer to a DWORD", it is actually a "pointer-sized DWORD" (4 bytes on a 32bit system, 8 bytes on a 64bit system). Whereas DWORD is always 4 bytes on both 32bit and 64bit systems. Microsoft uses the P prefix to indicate a pointer to a type, and uses the _PTR suffix to indicate the type itself is dependent on the byte size of a pointer.
The Delphi declaration is using var parameters, so you have to match the data type exactly:
var
procaffmask,
sysaffmask : DWORD_PTR;
begin
GetProcessAffinityMask(GetCurrentProcess, procaffmask, sysaffmask);
end;
Even your quote of the C++ declaration shows that the parameters are PDWORD_PTR (pointer to DWORD_PTR).
instead of DWORD use SIZE_T, there will be no error
I can compile successfully the below code snippet in C++Builder 6, but I can't compile it in RAD Studio Seattle:
unsigned long x = 50;
String s = IntToStr(x);
[bcc32 Error] Unit1.cpp(55): E2015 Ambiguity between '_fastcall
System::Sysutils::IntToStr(int) at c:\program files
(x86)\embarcadero\studio\17.0\include\windows\rtl\System.SysUtils.hpp:3182'
and '_fastcall System::Sysutils::IntToStr(__int64) at c:\program files
(x86)\embarcadero\studio\17.0\include\windows\rtl\System.SysUtils.hpp:3183'
I've checked that IntToStr definition.
C++Builder 6:
extern PACKAGE AnsiString __fastcall IntToStr(int Value)/* overload */;
extern PACKAGE AnsiString __fastcall IntToStr(__int64 Value)/* overload */;
C++Builder Seattle:
extern DELPHI_PACKAGE System::UnicodeString __fastcall IntToStr(int Value)/* overload */;
extern DELPHI_PACKAGE System::UnicodeString __fastcall IntToStr(__int64 Value)/* overload */;
extern DELPHI_PACKAGE System::UnicodeString __fastcall UIntToStr(unsigned Value)/* overload */;
extern DELPHI_PACKAGE System::UnicodeString __fastcall UIntToStr(unsigned __int64 Value)/* overload */;
What is the difference between C++Builder 6 and C++ Builder Seattle?
Basically in this scenario there exists an Ambiguity, means there are two overloads of IntToStr , expecting different argument types (int and int64). the ambiguity is to downgrade the provided long type to int or upgrade it to int64.
here the parameter should be cast-ed to most matching type.
Apart from what #Ali Kazmi said, for unsigned you need to use one of the last 2, since your value is unsigned:
UIntToStr()
I think then it will not require you to cast the value and it should compile.
Builder 6 implicitly casted unsigned values to one of the signed types, the new Builders (Since 2010) does not do so by default, you need to explicitly cast it to a signed type or use the unsigned alternatives
You can reduce the complexity of finding the correct converter functions for each variable type (as you have to do in Delphi) by just using one of the overloaded constructors of that mighty UnicodeString class itself, e.g.:
unsigned long x = 50;
String s(x);
Also, you can write String(MyVariableName) anywhere in your code to get a UnicodeString representation of MyVariableName.
In older CBuilder versions, String was a typedef for AnsiString.
Nowadays, it's a typedef for UnicodeString.
How can I use this function in C#?
function CheckCard (pPortID:LongInt;pReaderID:LongInt;pTimeout:LongInt): PChar;
This function included the dll.
I can try this way:
[DllImport("..\\RFID_107_485.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.ThisCall)]
public static extern char CheckCard(int pccPortID, int pccdReaderID, int pccTimeout);
char pccCheckCard = CheckCard(3, 129, 1000);
Console.WriteLine(pccCheckCard);
but i don't get a true answer...
please help me ? :)
There are many problems here. This is what I can see:
The Delphi code as written uses the Delphi register calling convention. That is only accessible from Delphi code and cannot be called by a p/invoke method. However, it is possible that you have omitted the calling convention from the code and it is in fact stdcall.
Your p/invoke uses CallingConvention.ThisCall which certainly does not match any Delphi function. That calling convention is not supported by Delphi.
You mistranslate PChar, a pointer to null-terminated array of characters as char, a single UTF-16 character.
The Delphi code looks suspicious. The function returns PChar. Well, who is responsible for deallocating the string that is returned. I would not be surprised if the Delphi code was returning a pointer to a string variable that is destroyed when the function returns, a very common error.
You refer to the DLL using a relative path. That is very risky because you cannot easily control whether or not the DLL will be found. Place the DLL in the same directory as the executable, and specify just the DLL's file name.
There is no error checking to be seen.
A variant that might work could look like this:
Delphi
function CheckCard(pPortID: LongInt; pReaderID: LongInt; pTimeout: LongInt): PChar;
stdcall;
C#
[DllImport("RFID_107_485.dll", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr CheckCard(int pccPortID, int pccdReaderID, int pccTimeout);
....
IntPtr pccCheckCard = CheckCard(3, 129, 1000);
// check pccCheckCard for errors, presumably IntPtr.Zero indicates an error
// assuming ANSI text
string strCheckCard = Marshal.PtrToStringAnsi(pccCheckCard);
// or if the Delphi code returns UTF-16 text
string strCheckCard = Marshal.PtrToStringUni(pccCheckCard);
This leaves unresolved how to deallocate the pointer returned. You'll have to consult your documentation for the function to find that out. The question contains insufficient information.
In my Delphi code I have to call a DLL's function (written in Visual C) with the following prototype:
int PWFunc(LPCSTR szName, int nWidth, int nHeight, LPCSTR szFileName)
How can I convert Delphi AnsiString variables (for Name and FileName) into right type parameters (LPCSTR szName and szFileName) of function call ?
I know that VC LPCSTR type corresponds to Delphi PAnsiChar type, but what is the right procedure to convert AnsiString to PAnsiChar ?
LPCSTR and LPSTR correspond to PAnsiChar, so that is what you use:
function PWFunc(szName: PAnsiChar; nWidth, nHeight: Longint;
szFileName: PAnsiChar): Longint; cdecl { or stdcall, see documentation };
external 'somedll.dll' name 'PWFunc';
You call it like:
X := PWFunc(PAnsiChar(AnsiString(SomeName)), 17, 33,
PAnsiChar(AnsiString(SomeFileName)));
Whether your function is stdcall or dcecl depends on compiler settings. Read the documentation. If in doubt, try both. It looks like cdecl to me, so start with that.
The question arise after I read a MSDN Blog article, Why can't you treat a FILETIME as an __int64?. The article said that casting a FILETIME to an __int64 can create a misaligned pointer.
FILETIME, LUID, and LUID_AND_ATTRIBUTES structs declared in Windows header as follows:
typedef struct FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
}
typedef struct LUID {
ULONG LowPart;
LONG HighPart;
}
typedef struct LUID_AND_ATTRIBUTES {
LUID Luid;
DWORD Attributes;
}
Since FILETIME and LUID structs has a similar layout, therefore treating a LUID as an __int64 also can create a misaligned pointer. However, Windows.pas (Delphi XE3 here) practises this--, for example:
{$ALIGN 4}
LUID_AND_ATTRIBUTES = record
Luid : Int64; // Here, LUID is treated as Int64
Attributes: DWORD;
end;
{$ALIGN ON}
another example is
function LookupPrivilegeValue(lpSystemName, lpName: LPCWSTR;
var lpLuid: Int64): BOOL; stdcall; // LUID is treated as Int64
How to safely treat structs like FILETIME or LUID directly as UInt64/Int64? What is the key?
It's a largely non-issue on the architectures that Delphi supports. The x86 and x64 architectures forgive you if you access mis-aligned data. On the other hand, accessing mis-aligned data on Itanium will result in runtime errors. But Delphi never targeted Itanium.
The issue that is significant is record layout. An Int64 has alignment of 8. But FILETIME and LUID have alignment of 4. Which is why LUID_AND_ATTRIBUTES is marked with an explicit $ALIGN 4.
If you are going to declare FILETIME and LUID to be Int64 then you need to take special care with record layout every time you include one in a record.