Quantcast
Channel: Planet Object Pascal
Viewing all 1725 articles
Browse latest View live

Te Waka o Pascal: Delphi for Android Supports Android!

$
0
0
Jim McKeeth is getting all excited about being able to develop for Google Glass using Delphi XE5. I’m pleased for him, I really am. It must be a huge relief that Delphi for Android can actually target this Android device. Of course, the very fact that there was any doubt and the fact that the […]

Te Waka o Pascal: Extending Smoketest (Part 2) – Great(er) Expectations

$
0
0
In my previous post on Smoketest I showed how you can extend the inspections framework to work with complex types in your code. As promised, I shall now show how you can do much the same thing to extend the framework with entirely new tests. “I must be taken as I have been made. The […]

Te Waka o Pascal: Creation Stories

$
0
0
In the beginning there was The Word a HWND. But not all gifts of creation can be relied upon, as I just learned. Or rather, remembered. As regular readers will know, I am currently polishing up my Smoketest framework for release (don’t worry, this post won’t take long and then I can get back to […]

It's a blong, blong, blong road...: Delphi and Android services

$
0
0

Since Delphi’s introduction of Android support with the release of XE5, there have been many questions posted hither and thither regarding whether and how you can build service applications with it. The pervading suggestion or suspicion is that maybe Delphi isn’t cut out to build such exotic Android creations.

Well, if your goal is to just build some sort of a service app I wouldn’t particularly recommend Delphi for the job right now, simply because it hasn’t got the wherewithal to support you in that endeavour in its current guise, and consequently it’s quite difficult. Really, if you just want to build a service app you’d probably have an easier time using Java or Oxygene for Java in conjunction with the Android SDK.

However if you are invested in building a Delphi Android app, are in the midst of building a FireMonkey application for mobile deployment, and need an Android service as part of that, well it’s quite possible. But as I may have mentioned, it’s neither particularly easy nor especially straightforward.

I am aware that I have (at this time of writing) yet to write up the business of adding Android menus to Delphi apps, employing a splash screen and launching Android activities and getting results back (as demo’d in my CodeRage 8 talk, albeit with code samples available in that linked post)*.

Now I can add to the list of things I have yet to write up the steps for creating a service application. If you take a look at this Google Play Store listing you’ll see I’ve built an app that, as well as a splash screen, also implements a service.

Service app running Service app includes a service

So yes, it’s quite feasible to build a service and a broadcast receiver in a Delphi app. That said, I’ve had to be a little creative on exiting the app to avoid a failure being evident on the screen.

As mentioned, these Android aspects that fall outside the standard simple business app paradigm haven’t factored into what is readily supported currently in Delphi’s Android support. Hopefully this will be improved as time goes on to allow all sorts of Android features and facets to be surfaced in Delphi Android code. In the mean time a certain degree of spelunking and skulduggery is needed to achieve certain ends.

I know quite a few people are clamouring for knowledge on how to build service apps. Hopefully in the near future I’ll write it up, but certainly in the nearer future I’ll release the code sample, once I’ve exhausted possibilities to clean up the wrinkle around app shutdown. That should satisfy the keener of you out there. In the mean time, be satisfied that it’s been proved to be possible at all.

DelphiTools.info: Memory Managers and String Building

$
0
0
[This is a guest post, written by Primož Gabrijelčič, www.thedelphigeek.com] One thing interested me since I started reading Eric’s series on string concatenation performance – how would different memory managers compare in a multi-threaded scenario. Today I decided to spend an hour finding out… Contenders Three memory managers were tested. In the first place, there was…

Salt Lake City Delphi Users Group: November 2013 SLCDUG Users Group Meeting

The Podcast at Delphi.org: Installing and Running Android Apps From Command-Line

$
0
0

Delphi automatically installs and runs your app for you, but sometimes it is nice to do manually from the command-line. Here are the commands you need. These all assume adb (Android Debug Bridge) is on your system path and you only have one Android device (or emulator) attached. They should work on both Mac and Windows.

See the end for notes on multiple devices or if you are running both an emulator and device.

First to install your app:

adb install path\ProjectName.apk

In this example path\ProjectName.apk is the full relative path to the apk. The apk usually has the same name as the project. If your apk is already installed, then use the following command to “reinstall” it, leaving the data intact:

adb install -r path\ProjectName.apk

The great thing about the -r is it works even if it wasn’t already installed.

Now if you want to uninstall your apk you can do that too:

adb shell pm uninstall -k com.embarcadero.ProjectName

Again, com.embarcadero.ProjectName is the default name of the package. If you changed it under Project Options -> Version Info -> Package, then use that value instead. BTW, the pm in there is the Android Package Manager.

One note, when Delphi deploys your app to run it, it performs an uninstall first. This results in all the data being cleaned out, which can be useful during development to be sure you don’t leave anything behind from the previous run. When a user updates an app from the App store, or installs it via most any other means, then it performs a reinstall, which leaves the data intact.

Now if you want to run it, things get a little more interesting. Now we use the Android Activity Manager (AM).

adb shell am start -n com.embarcadero.ProjectName/com.embarcadero.firemonkey.FMXNativeActivity

There are two parts to this. Before the slash is the package name, just like for uninstalling it. After the slash is the name of the Main Activity, which unless you’ve edited your AndroidManifest.template.xml (and some other fundamentals of your app) is always com.embarcadero.firemonkey.FMXNativeActivity. If you are trying to start an app written with another tool, then consult the AndroidManifest, but it is common for most tools to use MainActivity, so you can launch it like:

adb shell am start -n com.other.ProjectName/.MainActivity

If you want to stop your app after it is running, you just need the name of the package and the following:

adb shell am force-stop com.embarcadero.ProjectName

This can be useful to test what your app behaves like from a fresh restart, vs. just returning from the background.

The Android adb tool is very powerful. Most of these are using the shell command which actually allow you to pass commands to the modified Linux shell that runs inside Android. You can actually use “adb shell” to open a shell prompt and navigate your device like a remote machine.

If you have both an emulator running and a device attached then you can use the switch -d like

adb -d shell

and it directs it to the only device. If you use -e then it goes to the emulator.

When you have multiple devices then use -s and the device ID which can be obtained via the adb devices command.

There are so many other useful things you can do with adb. Check out the documentation.

Te Waka o Pascal: Setting The Record Straight

$
0
0
Commenter Alexander complained that my blog had become “really, but REALLY boring” recently. I was surprised because I thought I had been posting a lot of interesting, technical material lately and I wondered why Alexander seemed to think I was spending most – if not all – of my time on opinion pieces. So I […]

Te Waka o Pascal: A True Work of ART

$
0
0
For the past two years Google have been working on something for Android that could herald a sea change on the platform. ART. Essentially, ART is a new runtime which incorporates AOT (Ahead Of Time) compilation, essentially taking JIT to the next level by compiling an application in full at the time of installation on […]

Firebird News: Firebird 2.5.2 Update 1 for all Ubuntu releases is uploaded into Firebird stable ppa

$
0
0
Here you can find the latest stable release Firebird 2.5.2 Update 1 for all supported Ubuntu releases. Follow the Firebird 2.5.x guide for usage and installation. What is changed is added the security fixes plus many fixes from Debian unstable repository. Compared with previous upload support for hardy and oneiric is dropped (unsupported by Canonical)

The Podcast at Delphi.org: More Complete Supported Android Devies List

$
0
0

The Delphi Wiki has a much more exhaustive Supported Android Devices list. It also includes the new Nexus 5 (running Kit Kat), Google Glass and Droid Razr M, to name a few. At the bottom of the list there are some BlackBerry devices listed too, all of which are either not tested, or not supported. Curious to see if any of those end up working

There is also a link to some easy to follow testing instructions if you want to test your own devices, including some scripts to help automate part of the process.

Looking at the list it is obvious that there are more supported devices than not. Most pass over 80% of the tests too, of course it is always nice to see specific devices verified.

Delphi Code Monkey: When all you have is a hammer, everything looks like a nail.

$
0
0
I frequently run across questions like this one on Stackoverflow.  The person is asking how they might avoid hand-coding complex INSERT statements, using TADOQuery.   My comment in this question reads:

You might find it easier to use a dataset (TADODataset or TADOTable) to do a dataset-like-job, and use a TADOQuery to do a query-like-job. Oh, and there is TADOCommand to run a Command. So if you're writing SQL "insert" strings, you might want to look at running those with TADOCommand. And you might want to avoid writing them at all, and just set field values and insert into a TADODataset.
 This is a common coding anti-pattern:

The "All I Have Is A Hammer, So That Must Be a Nail" Anti-Pattern:

  1. Try something, it works on Tuesday July 1st, 2001 to solve the problem you had on Tuesday July 1st, 2001. 
  2. This is now the Standard Way You Do Everything Until the Day You Retire Forever from Coding.
  3. Do not reflect on whether you are forcing round pegs into square holes, but simply continue to develop a large body of "cargo cult" programming practices that were functional once, and are optimal almost never.

Why do we developers do this?  Because we know how to build one solution to a problem, we often stop looking for more ways to do this.    Learning about using the IDE (especially the debugger), and learning about using (and writing) components, understanding the entire Pascal language, these are all dimensions of learning to be a Delphi developer.   As a single developer learning, the pitfall is to stop too soon.

As a team, this pitfall morphs into a collective trap.  Developers working on a team must communicate "rules" and "best practices" to each other, and must agree and work together.  Working together is a whole other topic that I wish to brush past, but let's just do that, and ask, "how do teams create and modify the set of established rules and conventions they use, and do they ever fall into trap B while they try to avoid falling into trap A?".   Do rules that teams make, ever become "dogma"?  Are they written without qualifiers, or exceptions?  If so, then your team practices can force developers into the "Everything is a Nail", so "Hit it with the Hammer" trap.
 
I can list about 20 common "Hammer/Nail traps" that I have seen developers fall into, and they usually involve the word "always" or "never", and seldom involve the words "think about it", or "use when appropriate":

  1. Never use EXIT
  2. Always use EXIT
  3. Never use GOTO
  4. Always use GOTO
  5. Always put begin and end and never use single statements.
  6. Never put begin and end around single statements.
  7. Always use Data-Aware-Controls.
  8. Never use Data-Aware-Controls. (See Footnote)
  9. Always use Test Driven Development.
  10. Never use Test Driven Development.
  11. Always use Objects, Generics, and Gang-of-Four Patterns, and write your Pascal code like it was Java.
  12. Never use Objects, Generics, or Patterns, and write your Pascal code like it was Turbo Pascal and it's 1989.
Why do developers get stuck in the "always do X" and "never do X" patterns? Why do we argue and fuss about these rules?  I would like to suggest a constructive idea about why:

Solving problems is hard.  When the solution space (the number of things you have to try) gets large, your brain shuts down.  By closing down the "Go Left, Go Right, and Go South" rules in your brain, and leaving only the "Go North" rule, as the One Rule you always follow, until you hit a wall, at which point, your "Rotate Counterclockwise 90 degrees" rule kicks in, developers find it easier to navigate the complex maze of decisions that we make every day when we seek for solutions to our coding problems.   When a solution has worked many times in the past, we sometimes promote our solutions into dogma, like this:

1.  Once, I found it confusing that someone put an exit statement in the code, and I didn't notice it when reading the code, and so the flow of the program was confusing to me as a human being even though it was not confusing to the compiler.
2.  Due to my inability to read and see Exit statements, they are similar to Goto statements, and since they are similar to Goto Statements, and Goto Statements are "Considered Harmful", as everybody knows, they go on the no fly list.

Now let's look at code written without exit statements:

procedure  TMyForm.MyButtonClick(Sender:TObject);
begin
  if ValidationFunction1(param1,param2,param3) then
  begin
     if ValidationFunction2(param4,param5,param6) then
    begin
        if ValidationFunction3(param1,param2,param3) then
        begin
        if ConfigurationStateDetection(param1,param2,param3) then
        begin
           DoSomething;      
        end
        else
        begin
           DoSomethingElse;
        end;
    end;
  end;
end;

This could code be written better as:

procedure  TMyForm.MyButtonClick(Sender:TObject);
begin
  if not ValidationFunction1(param1,param2,param3) then
    exit;
 
  if not ValidationFunction2(param4,param5,param6) then
    exit;

  if not ValidationFunction1(param1,param2,param3) then
    exit;
  
  if ConfigurationStateDetection(param1,param2,param3) then
  begin
      DoSomething;      
  end
  else
  begin
      DoSomethingElse;
  end;
end;

The above is intended to be a sample that is an order of magnitude less complex than the worst "nesting of begins and ends" that I have seen in the field, at places where "exit" is discouraged or banned.   Practice 1 (which has some merits, I understand about exit being confusing to developers), causes Problem 2.

If you're going to make the rule "no exits", then you should have a better solution for a flow chart like this, that is better than nesting 30 blocks deep with begin and end:



There are exit-free solutions but most of them are far more baroque than just using exit, and if you are comitted to your rule "no exits" you should choose one, and make sure people know how to construct something that is less of a mess than a block of 30-nested begins and ends.  But then, when you're done, ask whether that finite state machine engine you invented isn't just your brain hiding an Exit-like and Goto-like language statement underneath some new layer of bafflement.

Let me suggest a better set of rules, either with the always/never removed, or at least, weakened with an appeal to developer rationality.



  1. Never use EXIT, when something better exists.
  2. Always use EXIT, when no better solution exists.
  3. Never use GOTO, when something better exists.
  4. Always use GOTO, when no better solution exists.
...  I think I can leave the rest of the list as an exercise for the reader.

So here is my Rule about Coding Rules:

A.  When you think of a coding rule or best-practice, keep your mind engaged while using that practice, and look for places where that practice creates as much or more trouble than it solves.
B.   When you share your ideas about coding rules within your team,  add conditions like the ones I added above in blue, that make it clear to team members that these are not Cargo Cult practices, but active thought processes that the team uses to develop software.

As a single developer in a team, it's your job not to create endless waves of complaints, but when you see something that is not working, or which is causing problems, it's important to find ways to discuss these issues.  At all times, you should avoid insults or personal comments.  If the team's best practice is to indent or format or organize code in some unusual way you've never seen before, and which you find yourself unable to understand and deal with (something I experienced personally at one place I worked),  you may find yourself tested to the very limits of your ability to cope with the zeitgeist at that team. I know I did.  If you're like me, and you like there to be a "why" or a reason for things being the way they are it may frustrate you to no end that people are in fact, not automatons whose behaviour can be predicted or explained by mere rational analysis, and often do the same things over and over for reasons that may be inscrutable to you, not knowing or caring why they do them this way. I'd like to reiterate why teams are like this:

People do things the same way over and over because that's how the human brain works.

Becoming aware of this, and trying to point out that people are hammering screws into plywood with a hammer, because all they've ever used before is a nail, is a bit of an extreme metaphor, and seems insulting, really, at some level.  But we have to remember that "nails" may have been 99.9% effective in all the places where developers have tried to use them.  Your team might think "TADOQuery is good, and TADOCommand and TADODataset and TADOTable are bad", for instance, because that got you out of some bad situation once, and now that is your rule.  But ask yourself, are you being introspective and is your team able to discuss this, or do you just "put your head down" and not ask questions, not think outside the box.

Going back to the StackOverflow question that inspired this post, I would like to point out that I am not trying to pick on a new Delphi user who is just learning.   But I do find that I myself sometimes fail to learn all that could be learned about a tool or an environment, and I tend to repeat using the same pattern or solution myself, and that I notice this problem in myself, and that I humbly offer this reflection to you, if it is of value:

Ask yourself, every day: "Are there ways to do this that I have not thought of?", and "If I don't know a better way but I sense something is off here, can I ask a colleague for suggestions, and could we find some more efficient or more optimal way to do this?".    So, in the end, the StackOverflow person who asked this question is more right, and more of a good example, because he or she asked a question, and got a lot of feedback from the big crowd of Delphi Geeks on the Internet.

That might be the smartest development best-practice of all.



Behind the connection: Delphi uses Excel to create a chart in a PDF document

$
0
0
Microsoft Excel exposes all his features thru a COM interface which can easily be used from a Delphi application. In this article, I use that feature to create a 3D pie chart from data available within a Delphi program and produce a PDF document. I already talked about using Microsoft Office applications in this article. I gave examples using Word. In this article I use Excel for what it does

twm’s blog: Delphi 2005/2006 on Windows 8.1

$
0
0

After getting Delphi 2007 to work again I tried to do the same for Delphi 2005 and 2006.

Both versions require the dotNET framework 1.1 which is officially no longer supported on Windows 8 (and 8.1). According to Microsoft, you should contact your independent software vendor (ISV) to have the application upgraded to run on the .NET Framework 3.5 SP1 or later version. Good luck with that.

This is odd, because I could install and use both Delphi versions on Windows 8. The installations broke only when Windows was updated to 8.1, so Microsoft is BSing us here, at least partly.

Reinstalling the “dotNET Framework 1.1 Redistributable Package” failed with some unhelpful error message.

Praise the Google, I found a solution on this site. The .NET Framework Cleanup Tool resolved that problem. After running it, letting it clean up the mess the update apparently made of the dotNET Framework 1.1 and rebooting, I could reinstall it.

Delphi 2005 started again, complained about something regarding “Star Team” which I just ignored / disabled, and behold, the IDE seemed to work.

The same with Delphi 2006. It too complained about “Star Team” which I again just ignored / disabled. It also seemed to work.

Beware: I haven’t done much more than starting both IDEs and compiling GExperts with it. So there might still be issues.

twm’s blog: Delphi 2007 on Windows 8.1

$
0
0

When I updated to Windows 8.1 my Delphi 2007 installation broke. I could no longer open projects in the IDE and my command line compilation scripts also stopped working. It turned out that some files that were added by the installer to the dotNET framework were missing. In addition there is a known problem with Delphi 2007 on 64 bit Windows (starting with Vista).

This is the error message from the IDE:

MissingBorlandDelphiTargets

followed by this one which is more readable:

MissingBorlandDelphiTargets2
(click on the picture to get it in full size)

This is the error message from my build script:

D:\src\MyProject.dproj(77,11):
error MSB4019: The imported project
"C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\Borland.Delphi.Targets"
was not found. Confirm that the path in the  declaration is correct,
and that the file exists on disk.

You might notice that the error messages slightly vary: The IDE complains about a missing file in …\Framework\ while the build script complains about the same file in …\Framework64\. I’ll come back to that later.

So here is what I did to fix it:

  1. I let Windows search for the missing file Borland.Delphi.Targets and it found it in
    C:\ProgramData\{B59CE2E6-B15A-4F23-BD0E-72BF2ADDC3C7}\core\7EFD2DA3\6C948720
    

    (Unfortunately I had already deleted the backup that was created by the Windows Update process.)
    After looking closer into this directory I found 4 files that match Borland.*.Targets. It stands to reason that Delphi will need them all in one way or another so I just copied all 4 of them to

    C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
    

    After I did that, the IDE no longer complained and also was able to compile the projects.

  2. To get the command line compile working again there are three options:
    • Some older advice I found on the net said to also copy these files to
      C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
      

      I didn’t like that approach because the build process is 32 bit, so why should it involve the 64 bit dotNET framework at all?

    • I found that for some reason the rsvars.bat script contained the line
      @SET FrameworkDir=C:\Windows\Microsoft.NET\Framework64\
      

      followed by

      @SET PATH=%FrameworkDir%%FrameworkVersion%;%FrameworkSDKDir%;%PATH%
      

      The Delphi 2007 installer is probably using some outdated method to find the dotNET framework, which works only on 32 bit Windows. I guess this was fixed in later versions.
      So another option to fix the problem is to change the FrameworkDir to point to …\Framework\ rather than …\Framework64\.
      I didn’t really like that approach either so I went for option 3.

    • I changed my build script to work around this issue:
      [...]
      set OldPath=%PATH%
      call "%DelphiDir%\bin\rsvars.bat"
      SET FrameworkDir=%SystemRoot%\Microsoft.NET\Framework\
      SET PATH=%FrameworkDir%%FrameworkVersion%;%FrameworkSDKDir%;%OldPath%
      

      (The actual build script is a bit more involved because it allows to call several different Delphi versions depending on an environment variable.)

After this change the build script worked again.

I hope this helps others to fix that problem, but I wrote this post mostly to find this information later if I need it again. ;-)

Just in case you are wondering:

Delphi 2006 and 2005 don’t work either. They are missing an older version of the dotNET framework which was there in Windows 8 but vanished in the update process. Thanks Microsoft! But there is a solution.

Delphi 7 still works. Delphi 6 has some issue with not finding its registration information that I haven’t looked into yet.


twm’s blog: Delphi 6 on Windows 8.1

$
0
0

After getting Delphi 2005/2006 and 2007 working again the last stumbling block was Delphi 6.

It used to work fine on Windows 8 but after the update to Windows 8.1 it always started the registration wizard for a new activation. Unfortunately this activation did not work, I tried it twice, just to be sure. So, again I turned to the Google and found Code Singh: Virtualising Delphi 6 PC (Activation Errors)

The problem described there looked a lot like the one I was having so since I had nothing to lose, I just deleted the registry entry

HKCU\Software\Borland\Delphi\6.0\LM

(I did not make a backup, what would have been the point?)

I started Delphi 6, ignored the warning about incompatibilities (which was talking about Delphi 7 anyway) and went through the registration/activation process again. This time it worked.

Maybe I should mention, that I did not install any of my Delphi versions to c:\program files but put them into c:\Delphi instead to avoid any problems with access rights to the installation directory.

So, now I have got working Installations of Delphi 6 to XE4 again.

XE3 and XE5 are missing, but I hope that’s just a matter of installing them.

The road to Delphi: The VCL Styles Utils Project now supports dialogs and popup menus

$
0
0

Two missing parts of the standard VCL Styles is the lack of the capacity to theme the popup menus and the standard Windows dialogs. I started to work a year ago in the dialogs area, but due to my limited time I was not able to finish that. But a few months ago I receive a very interesting mail from Mahdi Safsafi (SMP3) that show me his own work on this topic. So we decided merge the code of his project and the VCL Styles Utils. So finally the VCL Styles Utils project was updated to support standard dialogs, popup and system menus.

How it works?

The key is using a WH_CBT Hook, detecting the HCBT_CREATEWND and HCBT_DESTROYWND codes and then checking if the class of the window is #32770 (the class for a dialog box.) or the #32768 (the class for a popupmenu) from here you can replace the window procedure (WndProc) using the SetWindowLongPtr function with the GWL_WNDPROC index. Now we have the control of the messages sent by the windows dialogs and menus and we can iterate over the child controls and replace the window procedure again using the GWL_WNDPROC index. Finally depending of the class of the control (button, syslistview32, Combobox and so on) a Wrapper class (like the VCL does) is created to handle the messages related to the paint of the control.

Check the next source code which install the hook and process the Win32 controls

unit Vcl.Styles.SysControls;

interface

implementation

uses
  Winapi.Windows,
  System.Generics.Collections,
  System.SysUtils,
  Vcl.Controls,
  Vcl.Dialogs,
  Vcl.Styles,
  Vcl.Themes,
  Vcl.Styles.PopupWnd,
  Vcl.Styles.EditWnd,
  Vcl.Styles.StaticWnd,
  Vcl.Styles.ThemedDialog,
  Vcl.Styles.ToolbarWindow32Wnd,
  Vcl.Styles.SysListView32Wnd,
  Vcl.Styles.ButtonWnd,
  Vcl.Styles.UnknownControlWnd,
  Vcl.Styles.ControlWnd,
  Vcl.Styles.ComboBoxWnd,
  Vcl.Styles.ToolTipsWnd;

type
  TThemedSysControls = class
  private
  class var
    FBalloonHint: TBalloonHint;
    FPreviousSysBtn: Integer;
    FPreviousHandle: THandle;
    FHook: HHook;
  protected
    class function HookActionCallBack(Code: Integer; wParam: wParam;
      lParam: lParam): LRESULT; stdcall; static;
    procedure InstallHook;
    procedure RemoveHook;
  public
    constructor Create; overload;
    destructor Destroy; override;
  end;

var
  MenuItemInfoArray: array of TMenuItemInfo;
  TooltipsWndList: TObjectDictionary<HWND, TooltipsWnd>;
  PopupWndList: TObjectDictionary<HWND, TPopupWnd>;
  StaticWndList: TObjectDictionary<HWND, TStaticWnd>;
  DialogWndList: TObjectDictionary<HWND, TDialogWnd>;
  EditWndList: TObjectDictionary<HWND, TEditWnd>;
  ComboBoxWndList: TObjectDictionary<HWND, TComboBoxWnd>;
  UnknownControlList: TObjectDictionary<HWND, TUnknownControlWnd>;
  ToolbarWindow32WndList : TObjectDictionary<HWND, TToolbarWindow32Wnd>;
  SysListView32WndList : TObjectDictionary<HWND, TSysListView32Wnd>;
  BtnWndArrayList : TObjectDictionary<HWND, TButtonWnd>;
  ThemedSysControls: TThemedSysControls;

{ TThemedSysControls }

constructor TThemedSysControls.Create;
begin
  inherited;
  FBalloonHint := TBalloonHint.Create(nil);
  FBalloonHint.Style := bhsStandard;
  FBalloonHint.Delay := 1500;
  FBalloonHint.HideAfter := 3000;
  FPreviousHandle := 0;
  FHook := 0;
  InstallHook;
  PopupWndList:= TObjectDictionary<HWND, TPopupWnd>.Create([doOwnsValues]);
  TooltipsWndList:= TObjectDictionary<HWND, TooltipsWnd>.Create([doOwnsValues]);
  StaticWndList:= TObjectDictionary<HWND, TStaticWnd>.Create([doOwnsValues]);
  DialogWndList:= TObjectDictionary<HWND,TDialogWnd>.Create([doOwnsValues]);
  EditWndList:= TObjectDictionary<HWND, TEditWnd>.Create([doOwnsValues]);
  ComboBoxWndList:= TObjectDictionary<HWND, TComboBoxWnd>.Create([doOwnsValues]);
  UnknownControlList:= TObjectDictionary<HWND, TUnknownControlWnd>.Create([doOwnsValues]);
  ToolbarWindow32WndList:= TObjectDictionary<HWND, TToolbarWindow32Wnd>.Create([doOwnsValues]);
  SysListView32WndList := TObjectDictionary<HWND, TSysListView32Wnd>.Create([doOwnsValues]);
  BtnWndArrayList := TObjectDictionary<HWND, TButtonWnd>.Create([doOwnsValues]);
end;

destructor TThemedSysControls.Destroy;
begin
  RemoveHook;

  PopupWndList.Free;
  TooltipsWndList.Free;
  StaticWndList.Free;
  DialogWndList.Free;
  EditWndList.Free;
  ComboBoxWndList.Free;
  UnknownControlList.Free;
  ToolbarWindow32WndList.Free;
  SysListView32WndList.Free;
  BtnWndArrayList.Free;

  FBalloonHint.Free;
  inherited;
end;

class function TThemedSysControls.HookActionCallBack(Code: Integer;
  wParam: wParam; lParam: lParam): LRESULT;
var
  Msg: TMOUSEHOOKSTRUCT;
  C: array [0 .. 256] of Char;

  procedure HideSysToolTip;
  var
    hSysToolTip: THandle;
  begin
    For hSysToolTip := 65550 To 65600 do
      begin
        If IsWindowVisible(hSysToolTip) then
          begin
            GetClassName(hSysToolTip, C, 256);
            ShowWindow(hSysToolTip, SW_HIDE);
          end;
      end;
  end;

  procedure ShowToolTip(HintTitle: String);
  begin
    HideSysToolTip;
    if FPreviousSysBtn <> Integer(Msg.wHitTestCode) then
      begin
        FBalloonHint.HideHint;
        FBalloonHint.Title := HintTitle;
        FPreviousSysBtn := Msg.wHitTestCode;
        FBalloonHint.ShowHint(Msg.pt);
      end;
  end;

var
  CBTSturct: TCBTCreateWnd;
  sClassName : string;
begin
    if (StyleServices.Enabled) and not (StyleServices.IsSystemStyle) then
    begin
      if Code = HCBT_SYSCOMMAND then
        begin
          FBalloonHint.HideHint;
          FPreviousSysBtn := 0;
        end
      else
      if Code = HCBT_DESTROYWND then
      begin
        sClassName := GetWindowClassName(wParam);
          if sClassName = '#32768' then
          {PopupMenu}
          begin
            if PopupWndList.ContainsKey(wParam) then
              PopupWndList.Remove(wParam);
            //OutputDebugString(PChar('remove PopupWndList count '+IntToStr(PopupWndList.Count)));
          end
          else
          if sClassName = '#32770' then
          {Dialog}
          begin
            if DialogWndList.ContainsKey(wParam) then
              DialogWndList.Remove(wParam);
            //OutputDebugString(PChar('remove DialogWndList count '+IntToStr(DialogWndList.Count)));
          end
          else
          if sClassName = 'Button' then
          {Button}
          begin
            if BtnWndArrayList.ContainsKey(wParam) then
              BtnWndArrayList.Remove(wParam);
            //OutputDebugString(PChar('remove BtnWndArrayList count '+IntToStr(BtnWndArrayList.Count)));
          end
          else
          if (sClassName = 'ScrollBar') or (sClassName = 'ReBarWindow32') {or (sClassName = 'ToolbarWindow32')} then
          begin
            if UnknownControlList.ContainsKey(wParam) then
              UnknownControlList.Remove(wParam);
          end
          else
          if sClassName = 'SysListView32' then
          begin
            if SysListView32WndList.ContainsKey(wParam) then
              SysListView32WndList.Remove(wParam);
          end
          else
          if sClassName = 'ToolbarWindow32' then
          begin
            if ToolbarWindow32WndList.ContainsKey(wParam) then
              ToolbarWindow32WndList.Remove(wParam);
          end
          else
          if sClassName = 'Edit' then
          begin
            if EditWndList.ContainsKey(wParam) then
              EditWndList.Remove(wParam);
          end
          else
          if sClassName = 'Static' then
          begin
            if StaticWndList.ContainsKey(wParam) then
              StaticWndList.Remove(wParam);
          end
          else
          if sClassName = 'ComboBox' then
          begin
            if ComboBoxWndList.ContainsKey(wParam) then
              ComboBoxWndList.Remove(wParam);
          end
          else
          if sClassName = 'tooltips_class32' then
          begin
            if TooltipsWndList.ContainsKey(wParam) then
              TooltipsWndList.Remove(wParam);
          end
      end
      else
      if Code = HCBT_CREATEWND then
        begin
          CBTSturct := PCBTCreateWnd(lParam)^;
          sClassName := GetWindowClassName(wParam);
          //PopupMenu
          if Integer(CBTSturct.lpcs.lpszClass) = 32768 then
              PopupWndList.Add(wParam, TPopupWnd.Create(wParam))
          else
          //Dialog
          if Integer(CBTSturct.lpcs.lpszClass) = 32770 then
            begin
              if (CBTSturct.lpcs.cx <> 0) and (CBTSturct.lpcs.cy <> 0) then
                DialogWndList.Add(wParam, TDialogWnd.Create(wParam))
            end
          else
          if sClassName = 'Button' then
              BtnWndArrayList.Add(wParam, TButtonWnd.Create(wParam))
          else
          if (sClassName = 'ScrollBar') or (sClassName = 'ReBarWindow32') {or (sClassName = 'ToolbarWindow32')} then
              UnknownControlList.Add(wParam, TUnknownControlWnd.Create(wParam))
          else
          if sClassName = 'SysListView32' then
              SysListView32WndList.Add(wParam, TSysListView32Wnd.Create(wParam))
          else
          if sClassName = 'ToolbarWindow32' then
            begin
              if not UseLatestCommonDialogs then
                ToolbarWindow32WndList.Add(wParam, TToolbarWindow32Wnd.Create(wParam));
            end
          else
          if sClassName = 'Edit' then
              EditWndList.Add(wParam, TEditWnd.Create(wParam))
          else
          if sClassName = 'Static' then
            begin
              { This condition can solve the Edit animated cursor : see ColorDialog !! }
              if (CBTSturct.lpcs.Style and SS_ICON <> SS_ICON) and
                (CBTSturct.lpcs.Style and SS_BITMAP <> SS_BITMAP) and
                (CBTSturct.lpcs.Style and SS_GRAYRECT <> SS_GRAYRECT) and
                (CBTSturct.lpcs.Style and SS_GRAYFRAME <> SS_GRAYFRAME) then
                  StaticWndList.Add(wParam, TStaticWnd.Create(wParam));
            end
          else
          if sClassName = 'ComboBox' then
            ComboBoxWndList.Add(wParam, TComboBoxWnd.Create(wParam))
          else
          if sClassName = 'tooltips_class32' then
            TooltipsWndList.Add(wParam, TooltipsWnd.Create(wParam))
        end
    end;
  Result := CallNextHookEx(FHook, Code, wParam, lParam);
end;

procedure TThemedSysControls.InstallHook;
begin
  FHook := SetWindowsHookEx(WH_CBT, @TThemedSysControls.HookActionCallBack, 0, GetCurrentThreadId);
end;

procedure TThemedSysControls.RemoveHook;
begin
  if FHook <> 0 then
    UnhookWindowsHookEx(FHook);
end;

initialization

  ThemedSysControls:=nil;
  if StyleServices.Available then
    ThemedSysControls := TThemedSysControls.Create;

finalization

if Assigned(ThemedSysControls) then
    ThemedSysControls.Free;


end.

Menus

Standard TMainMenu with VCL Styles Enabled.
1

using the Vcl.Styles.SysControls unit
4

SysMenu with VCL Styles Enabled.

3

using the Vcl.Styles.SysControls unit

6

System menu with VCL Styles Enabled.

2

System menu using the Vcl.Styles.SysControls unit
5

Dialogs

Open Dialog With VCL Styles enabled

8

Open Dialog using the Vcl.Styles.SysControls unit
9

Even the shell menu inside of the dialog is themed

dialog_full

Others Dialogs

11

15

14

13

12

10

You can activate this functionality in your apps just adding the Vcl.Styles.SysControls unit to your project. Also a new sample project was added to test all the new features.

As always all your comments and suggestions are welcome.


DelphiTools.info: SamplingProfiler 1.8.1

$
0
0
A new version 1.8.1 is available from the SamplingProfiler page. This minor updates fixes the displayed source code for samples gathered on a generic method (“Show Source Location” option) and other minor fixes. Change log is as follows: Delphi XE4 path added to options. Display correct file for samples on generic methods. New Icon, cosmetic…

It's a blong, blong, blong road...: My CodeRage session files

$
0
0

At the time of writing my two sessions for CodeRage 8 are being broadcast around the Arpanet.

I’ve got two session this year, both related to Delphi mobile development, and both concerning how to reach out from the island that is the FM Application Framework (aka FMX aka FireMonkey) and gain access to the underlying mobile OS platform APIs.

The first session is Accessing the iOS API and looks at how Delphi-written iOS apps can talk to the CocoaTouch APIs and access additional iOS frameworks. We look at the Objective-C bridge and see how it is used to import iOS APIs, namely classes and protocols (Apple’s term for what we call interfaces), and how you can implement iOS interfaces and inherit from iOS classes. We also briefly look at how to pull in APIs that are not already imported by Delphi’s RTL. As a proof of concept we briefly see a Delphi iOS app that has no FMX code or units in it whatsoever, operating purely through the iOS APIs using the standard CocoaTouch model.

Files from the Accessing the iOS API session can be downloaded from here.

The second session is Accessing the Android API and looks at how Delphi-written Android apps can talk to the Android SDK classes. We look at the Java bridge and see how it is used to import Android APIs. We’ll also look at how to pull in APIs that are not already imported by Delphi’s RTL. We also look at how to add a splash screen to an Android app to cover up the startup time on anything other than the fastest devices, how to add Android menus to an app and how to launch external activities and get results back from them.

Files from the Accessing the Android API session can be downloaded from here. Take note that since several of the samples involve various required preliminary steps in order to function, as they step outside the comfort zone of Delphi XE5 RTM’s Android support, you should check the ReadMe.txt files supplied in the project directories of those projects.

[Update]

I plan to write up some of the subjects covered by these demos in further posts or articles as time and work schedules permit. However in the mean time I’ll respond to comments by expanding this post as necessary.

It appears that when the small Java source files get compiled, the Android dx tool expects them to be compiled by the JDK 1.6.x compiler as opposed to the JDK 1.7.x compiler. If you have JDK 1.7.x installed, you hit a problem with dx reporting:

bad class file magic (cafebabe) or version (0033.0000)

However, to avoid forcing a reinstall of JDK 1.6 you might like to modify my build.bat batch files and add in extra command line switches to the javac.exe command-lines. You need to insert this after the javac.exe command to force Java 1.6 byte code output, which is digestible by the Android dx command:

-source 1.6 -target 1.6

It's a blong, blong, blong road...: CodeRage 8 video replays are up

$
0
0

For anyone that’s been waiting for the replay videos from CodeRage to go up and has been getting impatient as the suggested 2 week window has come and gone, relief is now available as the replay videos are all there.

You can find them on YouTube on the Embarcadero TechNet page, or on the original CodeRage 8 session page.

Well, ok, maybe as I type one or two are still slowly dribbling onto the Internet and maybe the sessions page hasn’t quite got all the video links on board, but the majority are accessible in one way or another on YouTube at last.

I’ve updated my CodeRage 8 session files post to include the video links to my talks in case anyone wants to check them out. Enjoy!

Viewing all 1725 articles
Browse latest View live