I needed to compile the source code of Inno Media Player 0.03 which was modified by me to add a Cursor Hiding feature to it using Delphi.
I added the code to the source successfully and tried to recompile but the compiler says:
[dcc32 Error] MainUnit.pas(154): E2010 Incompatible types: 'LongBool' and 'Integer'.
What is the problem in this code?
The code I added to INNO MEDIA PLAYER:
const
OATRUE = -1;
procedure TDirectShowPlayer.InitializeVideoWindow(WindowHandle: HWND; var Width,
Height: Integer);
begin
ErrorCheck(FGraphBuilder.QueryInterface(IVideoWindow, FVideoWindow));
ErrorCheck(FVideoWindow.HideCursor(OATRUE)); **<<<ERROR IS HERE<<<**
...
end;
I called the IVideoWindow::HideCursor method on the FVideoWindow in the TDirectShowPlayer.InitializeVideoWindow.
The OATRUE Constant is a System.Shortint and IVideoWindow.HideCursor is a LongBool method.
Are those incompatible types or is my version of Delphi incompatible with this code that I added ?
On MSDN, IVideoWindow.HideCursor() is declared as taking a long as input, not a BOOL, so it should not be declared as LongBool in Delphi, it should be Longint instead. So either fix the declaration, or use a typecast:
ErrorCheck(FVideoWindow.HideCursor(BOOL(OATRUE)));
According to DirectShow documentation on IVideoWindow::HideCursor method signature is:
HRESULT HideCursor(
[in] long HideCursor
);
while corresponding signature in Progdigy's Pascal translation is:
function HideCursor(HideCursor: LongBool): HResult; stdcall;
So, while your code is absolutely complies to MS specification, you have to deal with incorrect type declaration somehow. You need to typecast your constant to declared type:
ErrorCheck(FVideoWindow.HideCursor(LongBool(OATRUE)));
Note: just passing True to HideCursor might also work provided DirectShow isn't sensitive to exact values. Use with caution.
Related
With the latest Delphi version (Berlin/10.1/24), is the [Ref] attribute really necessary?
I ask this because the online doc says:
Constant parameters may be passed to the function by value or by
reference, depending on the specific compiler used. To force the
compiler to pass a constant parameter by reference, you can use the
[Ref] decorator with the const keyword.
It's pretty much as described by the documentation. You'd use [ref] if you had a reason to enforce the argument to be passed by reference. One example that I can think of is for interop. Imagine you are calling an API function that is defined like this:
typedef struct {
int foo;
} INFO;
int DoStuff(const INFO *lpInfo);
In Pascal you might wish to import it like this:
type
TInfo = record
foo: Integer;
end;
function DoStuff(const Info: TInfo): Integer; cdecl; external libname;
But because TInfo is small, the compiler might choose to pass the structure by value. So you can annotate with [ref] to force the compiler to pass the parameter as a reference.
function DoStuff(const [ref] Info: TInfo): Integer; cdecl; external libname;
Another example is the new FreeAndNil procedure declaration in Delphi 10.4 in SysUtils.pas, which now finally ensures that only TObject descendants can be used with FreeAndNil. In previous Delphi versions, you could pass anything to this function, even if it didn't make sense.
I am trying to port some code that works in Delphi XE8 to Delphi 10 Seattle. This code calls the GetPath function in Winapi.Windows.
The new Win32 API function signature is:
function GetPath(DC: HDC; Points: PPointL; Types: PByte; nSize: Integer): Integer; stdcall;
In XE8, previously the function had "var Points,Types" which is known commonly as a "var untyped" parameter.
Fixing the code to work with Delphi 10 Seattle means "unifying" the arbitrary types in the application code to use exactly the types declared in the unit itself. However what is confusing me is that there are two types, PPointL, and TPoint, and when I get the GetPath function working, the data it populates is populated into an array of _POINTL records, declared thus in Winapi.Windows:
type
_POINTL = record { ptl }
x: Longint;
y: Longint;
end;
{$EXTERNALSYM _POINTL}
PPointL = ^TPointL;
TPointL = _POINTL;
However, there is also another type TPoint, declared in System.Types:
TPoint = record
X: FixedInt;
Y: FixedInt;
public
Elsewhere, FixedInt is aliased to Longint for both 32 bit and 64 bit Windows, and so TPoint and _POINTL are equivalent, as far as I can tell, on the Windows platform at least.
If existing application component code is all using a type named TPoint, like this:
procedure AddPoint(const P:TPoint);
... What sense am I to make of the situation on the ground inside the RTL sources in Delphi 10? What should my approach to fixing this be? Alias TPoint to _POINTL at the unit level?
How do I fix this and proceed? Since this code is a commercial component, I'm thinking I'll wait until the vendor fixes this, but then, I think that understanding the _POINTL and TPoint in the RTL, and why these structures are redundantly/duplicated in definition, would help others porting low level Win32 Code from Delphi XE8 to Delphi 10 Seattle.
Update: As a workaround, I find I can re-declare an import of the function GetPath, and have it remain as var untyped in my own private unit implementation area import, and continue:
{$ifdef D23}
{$POINTERMATH ON}
// Delphi 10 Seattle: function GetPath(DC: HDC; Points: PPointL; Types: PByte; nSize: Integer): Integer; stdcall;
// previously had "var Points,Types" untyped,
const
gdi32 = 'gdi32.dll';
{$EXTERNALSYM GetPath}
function GetPath(DC: HDC; var Points, Types; nSize: Integer): Integer; stdcall; external gdi32 name 'GetPath';
{$endif}
There's not much to be said about this, beyond the fact that the change to Winapi.Windows.GetPath in DX Seattle is wrong. I mean, technically it will work, but it leaves any code that uses GetPath in an isolated silo.
This TPointL type is not new, but it is the wrong type for GetPath. The Win32 API function is:
int GetPath(
_In_ HDC hdc,
_Out_ LPPOINT lpPoints,
_Out_ LPBYTE lpTypes,
_In_ int nSize
);
And LPPOINT is POINT* and POINT maps to TPoint. There are some Win32 API functions that use POINTL, but the majority use POINT. Of course, Microsoft are not helping by having declared two identical types when one would suffice.
Very hard to see how the Embarcadero developer has managed to come up with POINTL in the new GetPath, but there you go. In my view you should submit a QP report and request that the declaration is changed from PPointL to PPoint.
In the meantime a simple cast will suffice because these two types are binary compatible. You wish to pass a PPoint, but the compiler wants PPointL. So pass PPointL(...) where ... is the expression that yields a PPoint.
I have this piece of code from Delphi 7:
var
lpRgnData: PRgnData;
PC: PChar;
PR: PRect;
...
PC := #(lpRgnData^.Buffer[0]);
In Delphi XE4 it gives the following compile error:
Incompatible types: 'PWideChar' and 'Pointer'
How should this code be updated to work correctly in XE4?
Thanks
Whether or not this compiles depends upon the setting of the type-checked pointers option. You clearly have enabled that option which is an excellent decision. Doing so results in stricter type checking.
With type-checked pointers disabled, your code does compile. With type-checked pointers enabled, your code does not compile, which is what you want because your code is not valid.
Now, on to the types in question. They are defined in the Windows unit like this:
type
PRgnData = ^TRgnData;
{$EXTERNALSYM _RGNDATA}
_RGNDATA = record
rdh: TRgnDataHeader;
Buffer: array[0..0] of Byte;
Reserved: array[0..2] of Byte;
end;
TRgnData = _RGNDATA;
{$EXTERNALSYM RGNDATA}
RGNDATA = _RGNDATA;
The benefit of using type-checked pointers is that the compiler can tell you that what you are doing is not valid. It knows that lpRgnData^.Buffer[0] has type Byte and so #(lpRgnData^.Buffer[0]) has type ^Byte. And it knows that is not compatible with PChar which is an alias for PWideChar, that is ^WideChar.
Fix your code by changing the type of PC to ^Byte or PByte.
I have converted all of the VB.NET DLL declarations
Declare Function SFileOpenArchive Lib "Storm.dll" Alias "#266" (ByVal lpFileName As String, ByVal dwPriority As Integer, ByVal dwFlags As Integer, ByRef hMPQ As Integer) As Boolean
over into Delphi.
function SFileOpenArchive(lpFileName: String; dwPriority, dwFlags, hMPQ: Integer): Boolean; stdcall; external 'Storm.dll';
However, when I call the functions and compile the program I get the following error:
The procedure entry point SFileOpenArchive could not be located in the dynamic link library Storm.dll.
I have ensured that:
the DLL is stored in the same directory as the application
the functions I have declared exist (I was given the source code which was coded in VB.NET)
What can I do to fix this error?
Thank you in advanced.
You have the following problems that I can see:
The function has been exported by ordinal rather than name. You need to specify the ordinal in your Delphi code.
The first parameter should be PAnsiChar rather than a Delphi string. The VB code uses string to instruct the marshaller to pass a null-terminated string. As a rule of thumb, it's almost always a mistake to include a Delphi managed stype like string in a DLL import or export.
The final parameter is passed by reference. That's a Delphi var parameter.
The return value should be BOOL, I think, but that probably won't be causing you trouble.
Put it all together like this:
function SFileOpenArchive(lpFileName: PAnsiChar;
dwPriority, dwFlags: Integer; var hMPQ: Integer): BOOL;
stdcall; external 'Storm.dll' index 266;
Note that I'm not 100% sure that the text encoding is ANSI. However, the main blockage for you was the ordinal import. I hope I've cleared that for you. I trust you can resolve the remaining details.
I am reading the documentation for MoPaQ and trying to convert the functions over to Delphi because some of the data types mentioned in the documentation do not directly match the ones in Delphi.
This is the function I am having troubles with:
HANDLE WINAPI MpqOpenArchiveForUpdate(LPCSTR lpFileName, DWORD dwCreationDisposition, DWORD dwHashTableSize);
In Delphi, I have converted it as:
function MpqOpenArchiveForUpdate(lpFileName: Char, CreationDisposition, dwHashTableSize: LongWord); external 'lmpqapi.dll';
I am missing the return type for my function which I believe is HANDLE (according to the documentation). If that is the case, what is the Delphi equivalent for the HANDLE data type?
The equivalent would be something along these lines:
function MpqOpenArchiveForUpdate(lpFileName: LPCSTR;
dwCreattionDisposition,
dwHasTableSize: DWord): THandle; stdcall; external 'lmpqapi.dll';
Note that you'll have to find out if MoPacQ is Unicode-aware or not; if it's not, change the definition of lpFileName to PAnsiChar instead.
Remy points out in his comment below that Delphi maps LPCSTR to the proper PAnsiChar type on all versions, so you should use it that way.