There is an old project that I need to recompile to XE5 trying to aavoid the weird Twebbrowser errors that the original D7 component brings. The code bellow works great on D7 but not on XE5.
function GetFrame(FrameNo: Integer; WB: TWEbbrowser): IWebbrowser2;
var
OleContainer: IOleContainer;
enum: IEnumUnknown;
unk: IUnknown;
Fetched: PLongint;
begin
while WB.ReadyState <> READYSTATE_COMPLETE do
Application.ProcessMessages;
if Assigned(WB.document) then
begin
Fetched := nil;
OleContainer := WB.Document as IOleContainer;
OleContainer.EnumObjects(OLECONTF_EMBEDDINGS, Enum);
Enum.Skip(FrameNo);
Enum.Next(1, Unk, Fetched);
Result := Unk as IWebbrowser2;
end
else
Result := nil;
end;
I've checked and the parameters for EnumObjects are the same on both versions but XE5 says "E2033. Types of actual and formal var parameters must be identical".
Any idea how I can recompile this puppy? Thanks. Peace!
For a variable parameter, the actual argument must be of the exact type of the formal parameter.
If you get the error I can assume that type of your enum variable is not of type : ActiveX.IEnumUnknown, so you can try to change this line in the variable declaration section :
enum: IEnumUnknown;
to :
enum: ActiveX.IEnumUnknown;
Related
This follows on from my answer to this Q:
Can I change the display format for strings in the watch list?
It turns out that at some point between D7 and XE3, the implementation of the IDE's Watch Window changed from using a TListView to a TVirtualStringTree.
Although I posted an update to my answer that works with XE4 by ignoring the VST and getting the watch value from the clipboard, I'd still like to be able to get the watch value from the VST if I can. I think I know how to do that
once I have a reference to the VST but the problem is that my attempt to get one fails.
Following is an MCVE of the code I'm using in my custom package. Hopefully, what it does is self-explanatory. The problem is that the code in the block
if WatchWindow.Components[i] is TVirtualStringTree then begin
[...]
end;
never executes, DESPITE the classname "TVirtualStringTree" appearing in Memo1. Obviously the component with that classname fails the "is" test. I'm guessing that the reason is that the TVirtualTreeView compiled into the IDE is a different version that the one I'm using, v.5.3.0, which is the nearest predecessor I could find to XE4.
So, my question is, is that the likely explanation, and is there anything I can do about it? I suspect if someone can flourish the version of TVirtualStringTree that was used for XE4 from a hat, that might solve my problem.
type
TOtaMenuForm = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
WatchWindow : TForm;
VST : TVirtualStringTree;
end;
procedure TOtaMenuForm.FormCreate(Sender: TObject);
var
i : Integer;
S : String;
begin
WatchWindow := Nil;
VST := Nil;
// Iterate the IDE's forms to find the Watch Window
for i := 0 to Screen.FormCount - 1 do begin
S := Screen.Forms[i].Name;
if CompareText(S, 'WatchWindow') = 0 then begin
WatchWindow := Screen.Forms[i];
Break;
end;
end;
Assert(WatchWindow <> Nil);
if WatchWindow <> Nil then begin
Memo1.Lines.Add('Looking for VST');
for i := 0 to WatchWindow.ComponentCount - 1 do begin
Memo1.Lines.Add(IntToStr(i) + ':' + WatchWindow.Components[i].ClassName);
if WatchWindow.Components[i] is TVirtualStringTree then begin
VST := TVirtualStringTree(WatchWindow.Components[i]);
Memo1.Lines.Add('found VST');
Break;
end;
end;
if VST = Nil then
Memo1.Lines.Add('VST not found');
end;
end;
Btw, I realise that solutions that depend of implementational details of IDE are likely to be fragile, but this is just for amusement (I liked the challenge of getting string data out of a component that goes out of its way to avoid storing any).
May be You can try to use only published properties of embedded into IDE TVirtualStringTree implementation through RTTI methods to do what you want?
I have written a code with Delphi 2009 and updated my CodeGear Delphi to XE2. It compiled perfectly with Delphi 2009, but now it doesn't ! It gives me this error instead :
[DCC Error] Incompatible types: 'TFormStyle' and 'TTeeFontStyle'!
I tried creating a new Vcl Forms Application and wrote the command that generates this error :
Form1.FormStyle := FsNormal;
and it compiled perfectly too,I don't know why is this happening, although I believe there's nothing wrong with my syntax, please help, thanks.
This is the code that is not compiling :
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
begin
begin
KeyPreview := True;
case Msg.message of
WM_KEYDOWN:
if Msg.wParam = 27 then
begin
form1.Menu:=mainmenu1;
fullscreen1.Checked:=false;
form1.formstyle:=fsnormal;
form1.BorderStyle:=bssizeable;
end
else
if msg.wParam=VK_f5 then
begin
browser.Navigate(memo2.Text);
end;
end;
end;
end;
There is name conflict with some TeeChart module, which is in "use" clause. You can write full-qualified identificator name to resolve this problem:
formstyle := Vcl.Forms.fsnormal;
P.S. Note that I deleted "form1." qualifier also. Normally it is not very useful in the form method body, and sometimes even harmful (imagine that you have multiple instances of TForm1)
In addition to the answer of MBo, I think it is better to use:
Self.formstyle := Vcl.Forms.fsnormal;
When you have multiple instances of TForm1, this will always adjust the instance you are using at that moment.
Qualify the value with the particular enum type that it comes from:
Form1.FormStyle := TFormStyle.fsNormal;
Or even:
Form1.FormStyle := Vcl.Forms.TFormStyle.fsNormal;
EDIT - See Update at end
This is for Delphi 7.0 Build 4.453
Summary
I need to be able to take the Handle property from a TMonitor object (an element in the Monitors array in the TScreen component) which is a HMONITOR, and turn it into the string you would use in calls to EnumDisplaySettings as the lpszDeviceName parameter.
(my end goal is to get a list of device settings from a given HMONITOR value, by passing the resolved lpszDeviceName into calls to EnumDisplaySettings).
Detailed Information
As mentioned above, the Screen.Monitors[x].Handle property is of type HMONITOR and is normally used to pass into the GetMonitorInfo function, which returns, geometry information, but no lpszDeviceName. (note: there is a TMonitorInfoEx structure that has a szDevice field, but it does not seem to get filled in on my system, even though i am setting the cbSize field to the appropriate size).
Alternatively, if i can use a szDeviceName to get the equivalent HMONITOR value, i could plug it into the following function, which would use it in a comparison (I have inserted a call to fictitious function called hMonitorFromDeviceName in the code below) to indicate how it would be used.
function GetMonitorDeviceName(hmon : HMONITOR) : string;
var
DispDev : TDisplayDevice;
deviceName : string;
nDeviceIndex : integer;
begin
Result := '';
FillChar(DispDev, sizeof(DispDev),0);
DispDev.cb := sizeof(DispDev);
nDeviceIndex := 0;
while (EnumDisplayDevices(nil, nDeviceIndex, DispDev, 0)) do
begin
if ( hMonitorFromDeviceName(DispDev.DeviceString) = hmon ) then
begin
Result := StrPas(DispDev.DeviceString);
exit;
end;
inc(nDeviceIndex);
end;
end;
Update
Thanks to David Heffernan, I have tested his solution, and here is a sample function to get the monitor name from a given handle:
function GetMonitorName(hmon : HMONITOR) : string;
type
TMonitorInfoEx = record
cbSize: DWORD;
rcMonitor: TRect;
rcWork: TRect;
dwFlags: DWORD;
szDevice: array[0..CCHDEVICENAME - 1] of AnsiChar;
end;
var
DispDev : TDisplayDevice;
deviceName : string;
monInfo : TMonitorInfoEx;
begin
Result := '';
monInfo.cbSize := sizeof(monInfo);
if GetMonitorInfo(hmon,#monInfo) then
begin
DispDev.cb := sizeof(DispDev);
EnumDisplayDevices(#monInfo.szDevice, 0, DispDev, 0);
Result := StrPas(DispDev.DeviceString);
end;
end;
I think that you must be calling GetMonitorInfo incorrectly. This code:
{$APPTYPE CONSOLE}
uses
SysUtils, MultiMon, Windows, Forms;
var
i: Integer;
MonitorInfo: TMonitorInfoEx;
begin
MonitorInfo.cbSize := SizeOf(MonitorInfo);
for i := 0 to Screen.MonitorCount-1 do
begin
if not GetMonitorInfo(Screen.Monitors[i].Handle, #MonitorInfo) then
RaiseLastOSError;
Writeln(MonitorInfo.szDevice);
end;
Readln;
end.
produces this output on my machine:
\\.\DISPLAY1
\\.\DISPLAY2
I suspect that your call to GetMonitorInfo is failing in some way and perhaps you are not checking the return value for errors.
Having searched QualityCentral I suspect you have fallen victim to a known bug in older versions of Delphi: QC#3239. This is reported fixed in version 10.0.2124.6661 which is Delphi 2006.
Your comments confirm this diagnosis. To fix the problem you'll need a new TMonitorInfoEx definition. Here's one that will work on your pre-Unicode Delphi:
type
TMonitorInfoEx = record
cbSize: DWORD;
rcMonitor: TRect;
rcWork: TRect;
dwFlags: DWORD;
szDevice: array[0..CCHDEVICENAME - 1] of AnsiChar;
end;
If you add that to the code above (before you declare the variables of course) then I believe it will resolve your problem.
As an interesting aside, even in XE3, these structs have not been translated correctly: QC#114460. Admittedly the error is rather benign as it only affects PMonitorInfoExA and TMonitorInfoExA, but the error caught me out whilst trying to solve the problem in this question!
I recently migrated from D2010 to DXE2 and found a showstopper bug (Or feature?) in XE2 and XE3 (Tested in my friend XE3) related to RTTI generation for TBytes fields inside classes.
I found that the RTTI information for a TBytes variable inside a class is never generated.
The following code works well in D2010, but shows the message "Error" in XE2/XE3
Does anyone have any clue? This will totally break all our software data serialization implementation
To test the code please add Rtti unit to the uses declaration
type
TMyClass = class
public
Field1: Integer;
Field2: TBytes;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
i: Integer;
Data: TMyClass;
Rtti: TRttiContext;
RttiClassType: TRttiInstanceType;
begin
Data := TMyClass.Create;
try
// Get the context
Rtti := TRttiContext.Create;
try
// Get the type for the class
RttiClassType := TRttiInstanceType(Rtti.GetType(Data.ClassInfo));
// Check the fields
for i := 0 to High(RttiClassType.GetFields) do
begin
// Check the field type
if not Assigned(RttiClassType.GetFields[i].FieldType) then
ShowMessage('Error');
end;
finally
Rtti.Free;
end;
finally
Data.Free;
end;
end;
The error message will be displayed when checking for Field2 that is a TBytes becayse the FieldType is always nil!!!
Does anyone has any clue of what have changed in the RTTI from D2010 do XE2? Maybe because the TBytes type was changed from array of Byte to the generic array?
You can fix this error (it is actually not the same bug as the one Mason mentioned).
type
FixTypeInfoAttribute = class(TCustomAttribute)
public
FTypeInfo: PPTypeInfo;
constructor Create(TypeInfo: PTypeInfo);
end;
procedure FixFieldType(TypeInfo: PTypeInfo);
var
ctx: TRttiContext;
t: TRttiType;
f: TRttiField;
a: TCustomAttribute;
n: Cardinal;
begin
t := ctx.GetType(TypeInfo);
for f in t.GetFields do
begin
for a in f.GetAttributes do
begin
if (a is FixTypeInfoAttribute) and f.ClassNameIs('TRttiInstanceFieldEx') then
begin
WriteProcessMemory(GetCurrentProcess, #PFieldExEntry(f.Handle).TypeRef,
#FixTypeInfoAttribute(a).FTypeInfo, SizeOf(Pointer), n);
end;
end;
end;
end;
constructor FixTypeInfoAttribute.Create(TypeInfo: PTypeInfo);
begin
FTypeInfo := PPTypeInfo(PByte(TypeInfo) - SizeOf(Pointer));
end;
Then you add the attribute to your class definition:
type
TMyClass = class
private
Field1: Integer;
[FixTypeInfo(TypeInfo(TBytes))]
Field2: TBytes;
end;
and make sure the FixFieldType routine is called:
initialization
FixFieldType(TypeInfo(TMyClass));
Tested on XE
This is a known issue that was fixed in XE3. Unfortunately, upgrading is the only way to get a fix for it; bug fixes don't usually get ported back.
EDIT: Or not. Apparently this is not actually fixed, as it still occurs in XE3. Reporting it as a new case and mentioning 103729 would probably be the best course of action.
can anyone tell me why I get "Return value ... might be undefined" here:
function TXMLAcceptorBCOLSubmission.createRecordsInBCFEEPAR(AXML: TRipXMLElement): String;
var
...
begin
Result := '';
I am using Delphi 5 and it looks like the problem is caused by declaring more than 30 variables (I know, I know). It doesn't seem to matter what they are called or what types they are.
Following code doesn't generate a warning using Delphi 5 so
either it is a bug in an other Delphi version (you should mention the version you use)
or either it is something you didn't show us yet.
Code
program ProveAPoint;
{$APPTYPE CONSOLE}
uses SysUtils;
type
TRipXMLElement = record
end;
TXMLAcceptorBCOLSubmission = class
public
function createRecordsInBCFEEPAR(AXML: TRipXMLElement): string;
end;
function TXMLAcceptorBCOLSubmission.createRecordsInBCFEEPAR(AXML: TRipXMLElement): String;
begin
Result := '';
end;
var
AXML: TRipXMLElement;
begin
with TXMLAcceptorBCOLSubmission.Create do
begin
createRecordsInBCFEEPAR(AXML);
Free;
end;
end.