Why can't I use a resourcestring as a constant? - delphi

I've downloaded embtvstools (Embarcadero TVirtualShellTools) from: http://embtvstools.svn.sourceforge.net/
However when I create a new package, drop the .pas files (and a missing compilers.inc from VirtualTreeView in) and compile the lot, I get an error E2026, why is this and how do I avoid/workaround this?
resourcestring
sAssociationChanged = 'Association Changed';
sItemCreate = 'Item Create';
sItemDelete = 'Item Delete';
....
const
// Literal translations of TShellNotifyEvent type. Useful when using the
// OnShellNotify event to print out what event occurred. VirtualShellUtilities.pas
// has a helper function ShellNotifyEventToStr that uses these.
VET_NOTIFY_EVENTS: array[0..19] of WideString = (
sAssociationChanged,
sAttributes,
sItemCreate,
.....
[Pascal Error] IDEVirtualResources.pas(155): E2026 Constant expression expected
[Pascal Error] IDEVirtualResources.pas(156): E2026 Constant expression expected
[Pascal Error] IDEVirtualResources.pas(157): E2026 Constant expression expected
Update
Changing the widestring to a string stops the compiler complaining, (I suspect it will create some issue elsewhere because widestring <> string) I would like to keep the constant of type widestring.

As Uwe points out in the comments, resourcestring in Unicode versions of Delphi is of type WideString. But you are using pre-Unicode Delphi and so resourcestring is simply AnsiString. This explains the compilation error.
How to proceed depends on what you are attempting to do. If you intend to translate these strings into different languages then you may be in a bind. If you are intending to do that then you would obviously be far better off with a Unicode version of Delphi.
So, since you are sticking with a pre-Unicode Delphi I guess you don't actually need to translate the strings. In which case just change the declaration of the const array from WideString to string. As it happens, this array is declared by this code but never once referred to.

Related

GlobalFree - Incompatible types: 'NativeUInt' and 'PWideChar'

Documentation of WinHttpGetIEProxyConfigForCurrentUser says:
The caller must free the lpszProxy, lpszProxyBypass and
lpszAutoConfigUrl strings in the WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
structure if they are non-NULL. Use GlobalFree to free the strings.
I wrote the following code (Delphi 10.3.2):
var
VConfig: TWinHttpCurrentUserIEProxyConfig;
begin
FillChar(VConfig, SizeOf(VConfig), 0);
if not WinHttpGetIEProxyConfigForCurrentUser(VConfig) then begin
RaiseLastOSError;
end;
...
if VConfig.lpszAutoConfigUrl <> nil then begin
GlobalFree(VConfig.lpszAutoConfigUrl); // <-- Error
end;
and got an error:
[dcc32 Error] E2010 Incompatible types: 'NativeUInt' and 'PWideChar'
Questions:
should I type-cast PWideChar to NativeUInt?
can I use GlobafFreePtr instead of GlobafFree (it accepts PWideChar and works fine in my tests)?
When MSDN tells you to free with a specific function then doing just that is your best bet.
Parts of the Windows API is written in C and (some parts even without STRICT defined?) and other languages with better type checking will require casts in some places.
In the case of HGLOBALs you have the GlobalFlags function that can help you out. In your case the low byte of flags is zero indicating that there are no locks. If the strings had been allocated as movable the documentation would have to tell you to lock before accessing the memory and it does not.
The final nail in the coffin is to debug the function and if you do that you will see that it calls GlobalAlloc with flags set to 0x40 (GPTR) and should therefore be passed to GlobalFree without unlocking. If your compiler complains then you must cast to the appropriate type:
GlobalFree(HGLOBAL(VConfig.lpszAutoConfigUrl));

Incompatible Types "LongBool" and "Integer"

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.

Delphi: Invalid typecast with Move

I am installing an old component pack TSCap32 and get error Invalid typecast in multiple location with Move command.
var
pCopiedDib: PChar;
...
Move(pOrigDibBmi^, TByteArray(pCopiedDib^)[0], BmiSize);
The unit itself declare TByteArray like bellow:
type
TByteArray = array[0..0] of Byte;
How to resolve this error?
The cast that you are using requires that the TByteArray and pCopiedDib^ types have the same size. They do not: TByteArray has size 1, and pCopiedDib^ has size 2. Thus the compiler rejects your code because it is not valid.
The code was presumably originally written for pre-Unicode Delphi where PChar is an alias for PAnsiChar. In that scenario the code compiles. Now, you use a Unicode Delphi and PChar is an alias for PWideChar, and hence the types have different size.
Exactly how to fix your code is unclear. If you define pCopiedDib as PAnsiChar then your code will compile, but whether or not it will work is a different matter altogther. I suggest that you study this code further now that you know the cause of the error.

NPAPI plugin framework Error

I am trying to use NPAPI Framework from Yury Sidorov by following this answer:
How to embed Delphi VCL form into HTML page using NPAPI
but I get an error with NPPlugin.pas. I am using delphi XE7 and here what i did by following Krom Stern instructions
procedure DefDebugOut(const Msg: string);
begin
OutputDebugStringA(PAnsiChar(Msg + #13#10)); // Changed From Pchar To PAnsiChar
end;
but still getting error with compiler with this message
[dcc32 Error] NPPlugin.pas(2215): E2010 Incompatible types: 'PWideChar' and 'PAnsiChar'
Error raised on this procedure
procedure TPlugin.SetException(const msg: string);
var
s: String;
begin
try
{$ifopt D+} NPP_DebugOut('Exception: ' + msg); {$endif}
s:=UTF8Encode(msg);
NPN_SetException(m_pScriptableObject, PAnsiChar(s));
except
{ prevent any exception from leaking out of DLL }
end;
end;
here is the procedure NPN_SetException
procedure NPN_SetException(npobj: PNPObject; msg: PNPUTF8);
begin
NavigatorFuncs.SetException(npobj, msg);
end;
I'll start with a piece by piece breakdown of what we can see. Bear in mind that we don't have NPPlugin.pas at hand and have to infer its contents from the information in the question. All the same, I think it's possible for us to do that accurately.
s := UTF8Encode(msg);
Here s is of type string. That's an alias for UnicodeString, encoded as UTF-16. So you convert from UTF-16 to UTF-8 and then back to UTF16.
You need it like this:
NPN_SetException(m_pScriptableObject, PAnsiChar(UTF8Encode(msg)));
Alternatively, if you need a variable to hold UTF-8 encoded text, declare it to be UTF8String which is AnsiString(65001). If you changed the type of s to be UTF8String then the code in the question would be correct. Although somewhat more verbose than it would need to be.
Another problem is here:
OutputDebugStringA(PAnsiChar(Msg + #13#10));
Your cast doesn't make Msg actually be 8 bit encoded. However, you don't want to use the ANSI version of the function. You need this:
OutputDebugString(PChar(Msg + sLineBreak));
Your exception handler is misguided. It is the DLL's job not to leak exceptions. If you attempt to catch and suppress them all you will simply mask errors in your own code. You need to remove that exception handler and check for errors by following the instructions given by the library documentation.
Now to the bigger picture. None of the above explains your reported error. The only sound explanation for that is that your declaration for NPN_SetException accepts wide text. In which case you could make the code compile simply by writing this:
NPN_SetException(m_pScriptableObject, PChar(msg));
Of course, that makes the appearance of UTF-8 somewhat inexplicable. In fact the library Mozilla does accept 8 bit text, UTF-8 encoded. So why would NPN_SetException expect to be passed UTF-16 text? Well it doesn't. The explanation is that you have declared NPN_SetException incorrectly. So, just to be clear, whilst PChar(msg) would make your code compile, it would not resolve your problem. You would be left with code that failed at runtime.
So, how did this happen? You've taken a working piece of code that used PChar aliased to PAnsiChar onto a Delphi with PChar aliased to PWideChar and not translated correctly. Even when you get your code to compile, it will not work correctly. You started with code like this:
function NPN_SetException(..., Msg: PChar): ...;
On older Delphi versions where PChar was PAnsiChar then this was correct. You are compiling this now on XE7 where PChar is PWideChar and so this is not correct. It needs to be:
function NPN_SetException(..., Msg: PAnsiChar): ...;
Then the calling code can be:
NPN_SetException(m_pScriptableObject, PAnsiChar(UTF8Encode(msg)));
My advice is that you:
Step back and revisit the handling of Unicode in Delphi.
Go back to you original code and change all the Mozilla interface code that uses PChar to PAnsiChar.
Whenever you need to provide PAnsiChar do it with PAnsiChar(UTF8Encode(str)).
This NPAPI code was clearly designed for older versions of Delphi before the switch to Unicode in Delphi 2009. The default String/(P)Char types are no longer aliases for AnsiString/(P)AnsiChar, they are now aliases for UnicodeString/(P)WideChar. A UnicodeString cannot be casted to a PAnsiChar, just like an AnsiString could never be casted to a PWideChar.
In DefDebugOut(), the simplest fix is to change PAnsiChar to PChar and change OutputDebugStringA() to OutputDebugString():
procedure DefDebugOut(const Msg: string);
begin
OutputDebugString(PChar(Msg + #13#10));
end;
This is compatible with all Delphi versions (the code should have been doing this from the beginning - there was no reason to call OutputDebugStringA() directly). PChar and OutputDebugString() map to PAnsiChar and OutputDebugStringA() in Delphi 2007 and earlier, and to PWideChar and OutputDebugStringW() in Delphi 2009 and later. So everything matches.
In TPlugin.SetException(), UTF8Encode() returns a UTF8String in all versions of Delphi. However, prior to Delphi 2009, UTF8String was just an alias for AnsiString itself, but in Delphi 2009 it was changed to a true UTF-8 string type with full RTL support (it still has an AnsiString base, so it can still be casted to PAnsiChar). When a UTF8String is assigned to a UnicodeString, the compiler performs an implicit data conversion from UTF-8 to UTF-16. And as stated above, UnicodeString cannot be casted to PAnsiChar. So you need to change the s variable from String to UTF8String for all Delphi versions:
procedure TPlugin.SetException(const msg: string);
var
s: UTF8String;
begin
try
{$ifopt D+} NPP_DebugOut('Exception: ' + msg); {$endif}
s:=UTF8Encode(msg);
{
UTF8Encode() is deprecated in Delphi 2009+.
In those versions, you can use this instead:
s := UTF8String(msg);
}
NPN_SetException(m_pScriptableObject, PAnsiChar(s));
except
{ prevent any exception from leaking out of DLL }
end;
end;
With that said, if you are still getting the same error on the NPN_SetException() call, then it means the second parameter of NPN_SetException() is declared as PChar. It needs to be declared as PAnsiChar instead.

Why doesn't the new compiler recognize "NULL" in this old code?

I just downloaded the ADSI and it seems to be that it is not compatible with Delphi Embarcadero XE4.
When I try to compile one of the examples, I get this error:
[dcc32 Error] adshlp.pas(128): E2003 Undeclared identifier: 'NULL'
And this is the line:
varArr := NULL;
What's wrong?
Null used to be declared in the System unit, so it was available globally. In Delphi 6, all Variant-related code moved out of that unit and into the new Variants unit. Since Null is a function that returns a Variant, Null was included in the move, so it is no longer available implicitly.
To fix the old code, simply add Variants to your uses clause in any unit that needs it:
uses ..., Variants;

Resources