How should I fetch the ThemeServices instance in Delphi XE8 - delphi

I have this code from a legacy Delphi 2010 application.
var InternalServices: TThemeServices;
function ThemeServices: TThemeServices;
begin
if InternalServices = nil then
InternalServices := ThemeServicesClass.Create;
Result := InternalServices;
end;
The compiler tells me that ThemeServicesClass.Create does not exist. How should I do this in Delphi XE8?

The code that you include in the question is lifted from the VCL's Themes unit. That code should not be compiled by you. It was probably always a mistake for your application to compile that code rather than using the code from the Themes unit.
In XE8 you should call the StyleServices method of Vcl.Themes. The name change (from ThemeServices to StyleServices) is to reflect that fact that the older XP theme support has now been augmented by VCL styles.
So far as I can ascertain, the code in your question should not be compiled by you. It should be removed. It may be part of a much greater piece of code that perhaps also performs dubious acts. Without full sight of that code it's not possible for us to give you definitive advice.

Related

How to translate `reference to procedure` from Delphi to Lazarus?

Disclaim: I am asking to "Lazarus" because I don't really care about mode Delphi or mode ObjFPC...
I am translating some code from "Delphi 11" to Lazarus and found those:
TProc = reference to procedure(const AControl: TControl);
....
proc := MyProcedure;
This seems to be some managed reference to method for event callback, if I am correct.
How would I make something equivalent under Lazarus ?
You can use FPC from the main branch, which has this feature since May of last year. However, it will only be in the next major version release, which is not on the horizon, as far as I know.
Official announcement of the feature:
Feature announcement: Function References and Anonymous Functions

Why an application starts with FPU Control Word different than Default8087CW?

Could you please help me to understand what is going on with FPU Control Word in my Delphi application, on Win32 platform.
When we create a new VCL application, the control word is set up to 1372h. This is the first thing I don't understand, why it is 1372h instead of 1332h which is the Default8087CW defined in System unit.
The difference between these two:
1001101110010 //1372h
1001100110010 //1332h
is the 6th bit which according to documentation is reserved or not used.
The second question regards CreateOleObject.
function CreateOleObject(const ClassName: string): IDispatch;
var
ClassID: TCLSID;
begin
try
ClassID := ProgIDToClassID(ClassName);
{$IFDEF CPUX86}
try
Set8087CW( Default8087CW or $08);
{$ENDIF CPUX86}
OleCheck(CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, IDispatch, Result));
{$IFDEF CPUX86}
finally
Reset8087CW;
end;
{$ENDIF CPUX86}
except
on E: EOleSysError do
raise EOleSysError.Create(Format('%s, ProgID: "%s"',[E.Message, ClassName]),E.ErrorCode,0) { Do not localize }
end;
end;
The above function is changing control word to 137Ah, so it is turning on the 3rd bit (Overflow Mask). I don't understand why it is calling Reset8087CW after, instead of restoring the state of the word which was before entering into the function?
The 6th bit is reserved and ignored. Those two control words are in fact equal in the sense that the FPU behaves the same. The system just happens to set the reserved bit. Even if you attempt to set the value to $1332, the system will set it to $1372. No matter what value you ask the 6th bit to have, it will always be set. So, when comparing these values you have to ignore that bit. Nothing to worry about here.
As for CreateOleObject the authors decided that if you are going to use that function then you are also going to mask overflow when using the COM object, and indeed beyond. Who knows why they did so, and for 32 bit code only? Probably they found a bunch of COM objects that routinely overflowed, and so added this sticking plaster. It wasn't enough to mask overflow on creation, it also need to be done when using the object so The RTL designers chose to unmask overflow henceforth.
Or perhaps it was a bug. They decided not to fix it for 32 bit code because people relied on the behaviour, but they did fix for 64 bit code.
In any case this function does nothing very special. You don't need to use it. You can write your own that does what you want it to do.
Floating point control is a problem when working with interop. Delphi code expects unmasked exceptions. Code built with other tools typically masks them. Ideally you would mask exceptions when you call out of your Delphi code and unmask them on return. Expect other libraries to arbitrarily change the control word. Also be aware that Set8087CW is not thread safe which is a massive problem that Embarcadero have refused to address for many years.
There's no easy way forward. If you aren't using floating point in your program then you could simply mask exceptions and probably be fine. Otherwise you need to make sure that the control word is set appropriately at all points in all threads. In general that is close to impossible using the standard Delphi RTL. I personally handle this by replacing the key parts of the RTL with threadsafe versions. I have documented how to do so in this QC report: QC#107411.
Disclaimer: I debugged the questions in Delphi XE.
First, the second question.
If you look at the code of Set8087CW you will see that it stores the new FPU CW value in Default8087CW variable, and Reset8087CW restores FPU CW from Default8087CW; so the Reset8087CW call after Set8087CW does nothing at all, which is demonstrated by
Memo1.Lines.Clear;
Memo1.Lines.Add(IntToHex(Get8087CW, 4)); // 1372
Set8087CW( Default8087CW or $08);
Memo1.Lines.Add(IntToHex(Get8087CW, 4)); // 137A
Reset8087CW;
Memo1.Lines.Add(IntToHex(Get8087CW, 4)); // 137A
Evidently a bug.
Now the first question - it was interesting debugging exercise.
The Default8087CW value of Delphi VCL application is changed from hex 1332 to 1372 by Windows.CreateWindowEx function, called from Classes.AllocateHWnd, called from TApplication.Create, called from initialization section of Controls.pas unit.
Have a look at CreateWindowEx code - it explains what happens. I don't really want to discuss it further - the FPU support in Delphi is too messy and buggy.

Delphi TButton component styling

I just want to apologize in advanced if this question is already in another thread. I am also relatively new to Delphi.
Today I have seen an example Delphi program that has TButton components on it. The buttons have a pulsating blue effect that I assume is part of the Windows styling. There is absolutely no code written to make the button this way. I have searched for a possible setting, but to no avail.
Note: The buttons makes the effect at run-time and there is no custom components installed.
If someone could give me some information about how to do this without code, maybe just a setting would be great.
I am using Delphi 7 (2002).
Delphi Firemonkey (FMX) component framework has a TColorAnimation for which you can set properties like Duration, StartValue, StopValue, trigger etc. The FMX framework was introduced in Delphi XE2.
Blinking button demo
Now that you have clarified that you use Delphi 7 (please remember in future to indicate the version), here's an alternative that works in Delphi 7 (FMX is not compatible with Delphi 7)
var
b: boolean;
procedure TForm9.Timer1Timer(Sender: TObject);
begin
b := not b;
if b then
Button1.Perform(BM_SETSTATE, 0, 0)
else
Button1.Perform(BM_SETSTATE, 1, 0);
end;
Flashing is controlled by a TTimer, e.g 500 ms.
However, this doesn't fulfill your requirement of "There is absolutely no code written to make the button this way.", but I'm not aware of any way to achieve that.

IdStreamVCLWin32 not found error in Delphi XE4

My old Delphi 7 application is using IdStreamVCLWin32 unit in one pas file. This unit is located at following location.
C:\Program Files\Indy 10 for Delphi\Source\System\IdStreamVCLWin32.pas
When I am running same code in my Delphi XE4 environment, I am getting error IdStreamVCLWin32 not found.
Note: Delphi 7 is using Indy 10 but Delphi XE4 is using Indy which comes default with it. I have not installed indy explicitly in Delphi XE4 environment.
I searched my entire C drive where Delphi XE4 is installed but found no IdStreamVCLWin32.pas file.
How to get rid from this error?
From what I can tell, you were never meant to include that unit directly. The unit IdStreamVCL would delegate to either IdStreamVCLDotNet or IdStreamVCLWin32. And so it appears to me that IdStreamVCLWin32 is an implementation detail that you are shielded from by using IdStreamVCL.
These units have, nowadays, all been coalesced into IdStreamVCL. And so you could include that. However, it's not clear to me that you should even do that. Take a look at IdStream:
unit IdStream;
interface
{$I IdCompilerDefines.inc}
uses
{$IFDEF DOTNET}
IdStreamNET
{$ELSE}
IdStreamVCL
{$ENDIF};
type
{$IFDEF DOTNET}
TIdStreamHelper = TIdStreamHelperNET;
{$ELSE}
TIdStreamHelper = TIdStreamHelperVCL;
{$ENDIF}
implementation
end.
It seems pretty clear that you are meant to use IdStream and let the compiler work out whether that implementation is provided by IdStreamNET or IdStreamVCL.
So, the answer to your question is probably that you should replace your use of IdStreamVCLWin32 with IdStream. Note that the functionality in IdStream is implemented differently now. You no longer instantiate an instance of a stream class. The modern Indy offers you a helper class TIdStreamHelper which contains class functions. So you end up writing code like this:
BytesWritten := TIdStreamHelper.Write(Stream, Bytes, Count);
However, I cannot be sure that's the right approach since I don't know what you actually use from IdStreamVCLWin32. It's quite plausible that your code uses nothing from there and the use of IdStreamVCLWin32 is simply a stray hangover from some older version of your code.
So my advice is:
Remove IdStreamVCLWin32 from your uses.
Deal with any subsequent compiler errors by studying the code and working out the right way to do it with the current Indy code.

Automation object leaks memory (TConnectionPoints)

I have an automation object with event support that leaks memory. The FConnectionPoints which comes with the generated source is never freed. When I manually add FConnectionPoints.Free in the destructor, the leak goes away.
I am on Delphi 7, using a FastMM BorlandMM.dll and FastMM_Fulldebugmode.dll.
Steps to reproduce:
Start a new ActiveX Library project
Add a new Automation Object: Name = TestObject; Check "Generate Event support code"
Open the TypeLibrary, add a method to ITestObject, add an event to ITestObjectEvents
Refresh, code will be generated.
Add ShareMem as the first unit in your .dpr file
Save, compile and register this ActiveX Server (Run menu)
Start a new Application project
Put ShareMem as the first unit in your .dpr file
Import Type Library unit: create the unit from the dll you've just created in step 6, and check "Generate Component Wrapper"
In your FormCreate add the following code:
code:
var
lTest: TTestObject;
begin
lTest := TTestObject.Create(nil);
try
lTest.ConnectKind := ckNewInstance;
lTest.Connect;
lTest.Disconnect;
finally
lTest.Free;
end;
end;
Now compile, run and close this application. A memoryleak will be reported.
Question:
Is this a bug in the Delphi code template, am I doing someting wrong, or is it intended to free FConnectionPoints yourself (the help doesn't mention it)?
I don't fully understand the question as I never worked with automation objects but as far as I can see IConnectionPoint is an interface. Interfaces in Delphi are reference-counted (if the implementation inherits from TInterfacedObject, TContainedObject or TAgreggatedObject or implements _AddRef and _Release accordingly), so there should be no memory leak.
For more information on interfaces look at this article.
This chapter from the Delphi Language Guide could help too.
I found this issue to be reported in Quality Central report #1480.
A Sysop asked me to create a new report so I did: report #81288.
This also answers my question: it is a bug in the code template.

Resources