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;
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 forAnsiString
/(P)AnsiChar
, they are now aliases forUnicodeString
/(P)WideChar
. AUnicodeString
cannot be casted to aPAnsiChar
, just like anAnsiString
could never be casted to aPWideChar
.In
DefDebugOut()
, the simplest fix is to changePAnsiChar
toPChar
and changeOutputDebugStringA()
toOutputDebugString()
: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
andOutputDebugString()
map toPAnsiChar
andOutputDebugStringA()
in Delphi 2007 and earlier, and toPWideChar
andOutputDebugStringW()
in Delphi 2009 and later. So everything matches.In
TPlugin.SetException()
,UTF8Encode()
returns aUTF8String
in all versions of Delphi. However, prior to Delphi 2009,UTF8String
was just an alias forAnsiString
itself, but in Delphi 2009 it was changed to a true UTF-8 string type with full RTL support (it still has anAnsiString
base, so it can still be casted toPAnsiChar
). When aUTF8String
is assigned to aUnicodeString
, the compiler performs an implicit data conversion from UTF-8 to UTF-16. And as stated above,UnicodeString
cannot be casted toPAnsiChar
. So you need to change thes
variable fromString
toUTF8String
for all Delphi versions:With that said, if you are still getting the same error on the
NPN_SetException()
call, then it means the second parameter ofNPN_SetException()
is declared asPChar
. It needs to be declared asPAnsiChar
instead.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.Here
s
is of typestring
. That's an alias forUnicodeString
, encoded as UTF-16. So you convert from UTF-16 to UTF-8 and then back to UTF16.You need it like this:
Alternatively, if you need a variable to hold UTF-8 encoded text, declare it to be
UTF8String
which isAnsiString(65001)
. If you changed the type ofs
to beUTF8String
then the code in the question would be correct. Although somewhat more verbose than it would need to be.Another problem is here:
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: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: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 declaredNPN_SetException
incorrectly. So, just to be clear, whilstPChar(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 toPAnsiChar
onto a Delphi withPChar
aliased toPWideChar
and not translated correctly. Even when you get your code to compile, it will not work correctly. You started with code like this:On older Delphi versions where
PChar
wasPAnsiChar
then this was correct. You are compiling this now on XE7 wherePChar
isPWideChar
and so this is not correct. It needs to be:Then the calling code can be:
My advice is that you:
PChar
toPAnsiChar
.PAnsiChar
do it withPAnsiChar(UTF8Encode(str))
.