Quantcast
Channel: Tips, Tricks and Techniques - Embarcadero Community
Viewing all 182 articles
Browse latest View live

RAD Studio 10.2 Tokyo Release 1 ist verfügbar (10.2.1)

$
0
0

Release Notes:

http://docwiki.embarcadero.com/RADStudio/Tokyo/de/10.2_Tokyo_-_Release_1

Download ISO:

https://cc.embarcadero.com/item/30786  (jedermann/frau) oder

https://cc.embarcadero.com/Item/30785  (registrierte Benutzer)

(Beide ISOs sind gleich.... )

Download Webinstaller:

https://cc.embarcadero.com/Item/30783

Beschreibung / Neuerungen

10.2 Tokyo – Release 1 ist ein Update für Delphi 10.2 Tokyo, C++Builder 10.2 Tokyo und RAD Studio 10.2 Tokyo, das für alle Kunden mit einem aktiven Update-Abonnement erhältlich ist.

10.2 Tokyo – Release 1 enthält die folgenden neuen Leistungsmerkmale, Verbesserungen und Fehlerkorrekturen:

  • Leistungsverbesserungen für den Delphi-Linux-Server für RAD Server und DataSnap.
  • Updates für Delphi- und C++-Compiler und -Linker, die Probleme beim Laden von Packages, insbesondere beim Debugging, auf Windows 10 Creators Update beheben.
  • Unterstützung für die neuesten Versionen von iOS und Xcode (iOS 10.3 und XCode 8.3.2) für den iOS App Store.
  • FireDAC-Unterstützung für MSSQL 2012, 2014, 2016 und ODBC-Treiber 13.
  • Wichtige Verbesserungen für den C++-Linker für das Linken großer Projekte.
  • Korrekturen und Verbesserungen für die Laufzeitbibliothek und die VCL.
  • Weitere Android-Verbesserungen zu Rendering und Leistung von Steuerelementen und Korrekturen von Problemen mit TEdit bei Android N.
  • FireDAC-Unterstützung für Exclusive Isolation Level (EN) und Transaction Wait Time (EN) von InterBase 2017.
  • Korrekturen für mehr als 140 von Kunden in Quality Portal berichtete Probleme.

Release 1 enthält auch Verbesserungen für "Tokyo Toolchain Hotfix" (veröffentlicht am 3. Mai 2017) und "Android Compatibility Patch" (veröffentlicht am 22. Juni 2017). Klicken Sie hier, um eine vollständige Liste der Features und Fehlerkorrekturen anzuzeigen.

Hinweis: Das 10.2 Tokyo – Release 1 kann nur von Kunden mit einem aktiven Update-Abonnement heruntergeladen und installiert werden.

Installation:

De/Neuinstallation mit der Möglichkeit die Einstellungen zu behalten.


Tech Tipp #8: iOS und macOS SDK Versionen

$
0
0

Frage: Ich habe das neueste Xcode installiert (hier: 8.3.3) und das Release 1 von Tokyo 10.2. Dennoch wird mir beim Importieren des SDKs nur angezeigt

  • iPhoneOS 10.3.1 bzw
  • MacOSX 10.12.4

Mein iPhone/iPad/iOS-Gerät hat aber die iOS Version 10.3.3 bzw macOS ist auf Version 10.12.6.

Das verwirrt mich!

Antwort: Das verwirrt mich auch. Die Lösung ist aber relativ einfach: Die Xcode-Version korreliert nicht mit der iOS/macOS-SDK-Version. Es gibt zur Zeit kein neueres SDK innerhalb von Xcode (veröffentlichte Versionen). Auch, wenn sich die Betriebssystemversion (iOS/macOS) erhöht, heisst das nicht zwangsläufig, daß es eine neuere SDK Version gibt.

Auf der Mac-Seite kann man das (im Terminal) schnell und leicht feststellen:

Last login: Wed Aug  9 09:13:59 on ttys000
MacBookPro:~ meissing$ xcodebuild -sdk -version

Was eine solche Ausgabe erzeugt (gekürzt):

iPhoneOS10.3.sdk - iOS 10.3 (iphoneos10.3)
SDKVersion: 10.3
Path: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk
PlatformVersion: 10.3
PlatformPath: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform
ProductBuildVersion: 14E8301
ProductCopyright: 1983-2017 Apple Inc.
ProductName: iPhone OS
ProductVersion: 10.3.1

MacOSX10.12.sdk - macOS 10.12 (macosx10.12)
SDKVersion: 10.12
Path: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk
PlatformVersion: 1.1
PlatformPath: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform
ProductBuildVersion: 16E185
ProductCopyright: 1983-2017 Apple Inc.
ProductName: Mac OS X
ProductUserVisibleVersion: 10.12.4
ProductVersion: 10.12.4

Also alles im grünen Bereich.

Apple hat die Xcode/SDK-Versionen hier dokumentiert:
https://developer.apple.com/library/content/releasenotes/DeveloperTools/RN-Xcode/Chapters/Introduction.html

Ältere Xcode Versionen und die damit enthaltenen SDKs findet man hier:
https://developer.apple.com/download/more/?name=Xcode

Pro-Tipp: Im Ordner Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/ finden sich alle SDKs der installierten Xcode-Version (normalerweise nur eins). Hier kann man (unsupported! Apple möchte, daß man immer mit dem aktuellsten SDK entwickelt) auch ältere SDKs aus älteren Xcode Versionen unterschieben (dazu muss man das alte Xcode installiert haben und die SDKs aus diesem extrahieren (Time Machine, separater Mac, macOS-VM, Kollege, ...)

Delphi 10.2 での Linux アプリ開発時にアプリをPAServerとは別のターミナルで実行する [JAPAN]

$
0
0

Delphi 10.2 では Linux 向けにサーバ用アプリを開発できるようになりました。そして開発には IDE から Linux 上でのリモート実行、リモートデバッグのために PAServer を使用します。PAServer は macOS / iOS アプリ開発でも使用しますが、Linux 向け開発が macOS / iOS アプリ開発と異なるのは「サーバ向けアプリ開発なのでアプリはGUIを持たない」ことです。従って作成したアプリへの入出力には stdin, stdout を使用することになります。


しかし PAServer 経由の操作では PAServer 自体も stdin, stdout を使用していますので、PAServer 経由でリモート実行するアプリと標準入出力を取り合うことになります。

これは少々不便なので、PAServer とは別のターミナルでアプリを実行することで、標準入出力の取り合いを回避する方法を説明します。

Tech Tipp #9: InterBase local, RAD Studio und "unavailable database"

$
0
0

Frage: Ich nutze ein lokal installiertes InterBase. Ich möchte über Datenbankzugriffskomponenten darauf zugreifen. Aber sowohl FireDAC, als auch InterBase Express/IBX geben mir diese Nachricht:

FireDAC:

InterBase Express/IBX:

Folgende Beobachtungen habe ich gemacht:

  • Das passiert nur in der IDE - In der IBConole kann ich auf die Datenbanken zugreifen
  • Die Dateien sind definitiv vorhanden
  • Benutzernamen und -kennwort habe ich richtig eingegeben
  • Stelle ich in IBX auf "Remote" um (mit "localhost") funktioniert es
  • Stelle ich in FireDAC auf "TCPIP" um (mit server=localhost) funktioniert es

Wodran liegt das?

Antwort: Das liegt wahrscheinlich an den Umgebungsvariablen in der IDE vom RAD Studio/Delphi/C++Builder. Es gibt zwei Variablen, die hier zum Tragen kommen und vom RAD Studio für die Verbindung genommen werden. 

  • INTERBASE - Das Verzeichnis der InterBase Installation; 
  • IB_PROTOCOL - Der Instanzname; normalerweise/default "gds_db". Dies ist auch hier weiter dokumentiert. Faktisch ist das die Port-Nummer default:3050) von InterBase

Normalerweise sind diese nicht gesetzt; können aber (gerade bei Mehrfach-Instanzen von InterBase) das Ganze etwas durcheinander bringen. Man muss dann die Variablen setzen bzw ändern.

Generell können die Variablen unter "Tools | Optionen | Umgebungsoptionen | Umgebungsvariablen" gesetzt werden. Normalerweise ist dies nicht nötig, da es nur eine Instanz von InterBase gibt, aber das RAD Studio/Delphi/C++Builder kann man für die Standardwerte hier anpassen

INTERBASE
C:\Program Files\Embarcadero\InterBase
IB_PROTOCOL
gds_db

Nach dem Ändern der Umgebungsvariablen ist ein Neustart der IDE notwendig!


 

Eine andere Möglichkeit für den "unavailable database" Fehler kann InterBase selbst sein: Wenn man die "Developer-Edition" benutzt, nimmt diese nach 48 Stunden keine Verbindungen mehr an. Ein Neustart des InterBase Servers behebt dann auch das Problem.

 

Tech Tipp #10: ClearType von Delphi aus/einschalten

$
0
0

Frage: Ich möchte (aus welchen Gründen auch immer) für den aktuell angemeldeten Benutzer das ClearType von Windows ausschalten. Wie geht das?

Antwort: ClearType lässt sich unter Windows 7/8/10 mittels ClearType-Textoptimierungs-Program (cctune.exe) über die Bordmittel von Windows ein- bzw ausschalten und konfigurieren:

Dabei handelt es sich um eine Pro-User-Einstellung. Microsoft selbst stellt dafür den WinAPI-Befehl SystemParametersInfo bereit; mittels passender Aktion kann man hier das ClearType Verhalten beeinflussen.

Quick-and-Dirty Lösung (bitte weiter lesen!):

Ausschalten:

  SystemParametersInfo(SPI_SETFONTSMOOTHING,0,0,0);
  InvalidateRect(0, nil, True);

Einschalten:

  SystemParametersInfo(SPI_SETFONTSMOOTHING,1,0,0);
  InvalidateRect(0, nil, True);

Das jeweilige Absetzung von InvalidateRect(0, nil, True); erzeugt dabei einen kompletten Screen-Refresh....

Die Original-Paramter sind

BOOL WINAPI SystemParametersInfo(
  _In_    UINT  uiAction,
  _In_    UINT  uiParam,
  _Inout_ PVOID pvParam,
  _In_    UINT  fWinIni
);

Man kann, sollte das etwas besser gestalten

Einschalten:

  SystemParametersInfo(SPI_SETFONTSMOOTHING, Cardinal(true), 0, SPIF_UPDATEINIFILE OR SPIF_SENDCHANGE);
  SystemParametersInfo(SPI_SETFONTSMOOTHINGTYPE, FE_FONTSMOOTHINGCLEARTYPE, 0, SPIF_UPDATEINIFILE OR SPIF_SENDCHANGE);

Ausschalten:

  SystemParametersInfo(SPI_SETFONTSMOOTHING, Cardinal(false), 0, SPIF_UPDATEINIFILE OR SPIF_SENDCHANGE);

Dadurch erreicht man beim Einschalten vier Dinge:

  • Cardinaltype wird richtig/leserlicher gesetzt
  • Durch SPIF_UPDATEINIFILE wird das auch persistent in der Windows-Umgebung gespeichert
  • Durch SPIF_SENDCHANGE wird auch gleich die Message zur Aktualisierung der Oberfläche gesendet (ein InvalidateRect ist nicht mehr nötig)
  • Durch eine zusätzliche "Action" SPI_SETFONTSMOOTHINGTYPE wird der Type des ClearType gesetzt (siehe MSDN-Doku-Link weiter oben)

Beim Ausschalten erreicht man nur bessere/konformere Lesbarkeit und das senden der Window-Message zur Aktualisierung.

 

 

Video Tutorial #2/#3: CodeSite Express / Beyond Compare

$
0
0

Zwei weitere Videos aus meiner Video-Tipp-Reihe:


[YoutubeButton url='https://www.youtube.com/watch?v=EgZLt5l0mHM']

[YoutubeButton url='https://www.youtube.com/watch?v=QbkuOluQw2k']

Wi-Fi management from applications using C++Builder

$
0
0

Using C++Builder 10.2 Tokyo, explain how to switch Wi-Fi on Android.

Manage Wi-Fi switching using JWifiManager

I use di_JWifiManager which wrapped WifiManager.
di_JWifiManager is the Delphi interface.
Set the variable. _di_JWifiManager f_WifiManager; use it like this.

Required headers

Header file for using WifiManager.

#include <Androidapi.JNI.Net.hpp>
#include <Androidapi.Helpers.hpp>
#include <Androidapi.JNI.GraphicsContentViewText.hpp>
#include <Androidapi.JNIBridge.hpp>

Display design

It is a design for displaying on Android.


TEditTSwitchTTimerTLabel, was placed.

 

When the main form creation

Create _di_JWifiManager using TJWifiManager.

//---------------------------------------------------------------------------
void __fastcall Tfm_main_wifistatus::FormCreate(TObject *Sender)
{
    //Form creation.Using TAndroidHelper, get the WIFI_SERVICE.
    _di_JObject obj = TAndroidHelper::Activity->getSystemService(TJContext::JavaClass->WIFI_SERVICE);
    if (obj != nullptr)
    {
        //Wrap to TJWifiManager.
        f_WifiManager = TJWifiManager::Wrap(_di_ILocalObject(obj)->GetObjectID());
        if (f_WifiManager != nullptr)
        {
            Timer1->Enabled = true;
        }
    }
}

Monitor Wi-Fi status at Timer1 event.

void __fastcall Tfm_main_wifistatus::Timer1Timer(TObject *Sender)
{
    //Use a timer event to monitor the Wi-Fi state.
    //Write state change to Edit1->Text. and It also reflects Switch1->IsChecked.
    Timer1->Enabled = false;
    if (f_WifiManager != nullptr)
    {
        Switch1->IsChecked = f_WifiManager->isWifiEnabled();
        UnicodeString wifistr;
        (Switch1->IsChecked)?wifistr = "true": wifistr = "false";
        Edit1->Text = "f_WifiManager->isWifiEnabled() = " + wifistr;
    }
    Timer1->Enabled = true;
}

When you tap the Switch1.

Change the Wi-Fi status when tapping the Switch1.
This uses the setWifiEnabled() function.

void __fastcall Tfm_main_wifistatus::Switch1Switch(TObject *Sender)
{
    //This is a Switch1 change event.
    Timer1->Enabled = false;
    //Set the value of Switch1->IsChecked to setWifiEnabled()
    f_WifiManager->setWifiEnabled(Switch1->IsChecked);
    TThread::CreateAnonymousThread([this]()
    {
        sleep(1);
        TThread::Synchronize(TThread::CurrentThread, [this]()
        {
            Timer1->Enabled = true;
        });
    })->Start();
}

 

https://github.com/mojeld/cpp_builder_firemonkey_wifi

 

New in 10.2.1: Debug visualisers for Delphi generics

$
0
0

Debug visualisers are a type of IDE plugin that allows you to change the display of a variable in the various debug windows (Local Variables, Watches, Inspector, and Evaluate/Modify.) For example, the TDateTime visualiser takes the double value that represents time and instead displays that time converted to a string. You register a debug visualiser for a type, so all variables of that type, and optionally descendants of that type, go through your visualiser.

In previous versions, this type was specified by a plain string, such as 'TComponent', and there was no way to handle a generic type. If you registered 'MyGeneric<T>', the visualiser would never be called, because the concrete instantiations of that type do not use T - they might be 'MyGeneric<Integer>', 'MyGeneric<TButton>', and so forth.

In 10.2.1, we have introduced support for registering a visualiser for a generic type. Your visualizer can implement IOTADebuggerVisualizer250 as well as the prior IOTADebuggerVisualizer, where the GetSupportedType method allows you to specify that the type string is a generic:

 

.
  IOTADebuggerVisualizer250 = interface(IOTADebuggerVisualizer)
    ['{DC0C8D82-B783-4205-B3F4-D325BA8B3EEB}']
    { Return the Index'd Type.  TypeName is the type.  AllDescendants indicates
      whether or not types descending from this type should use this visualizer
      as well. IsGeneric indicates whether this type is a generic type. }
    procedure GetSupportedType(Index: Integer; var TypeName: string;
      var AllDescendants: Boolean; var IsGeneric: Boolean); overload;
  end;

This means you can register for MyGeneric<T> and your visualiser will be called for all MyGeneric<>s. This is all generic types, ie interfaces as well as classes. 

One note is that we do not yet support registering for descendants of a generic type, meaning that if you have MyDesc<T> = class(MyGeneric<T>) or MyDesc = class(MyGeneric<T>), you need to register a visualiser for MyDesc separately. This is because of some complexities in the internal evaluator.

Generics are widely used, especially for collections like dictionaries and lists, and in third-party libraries like Spring4D. We hope you will find visualiser support for generics useful!

Update: here is a code snippet demonstrating a template visualizer


To get the NetworkInfo using the ConnectivityManager of Android

$
0
0

 

Using ConnectivityManager with C++Builder

With C++Builder 10.2 Tokyo Android ConnectivityManager class is available.
Use the ConnectivityManager, you can get NetworkInfo
NetworkInfo see various network information.
inside that, The getType() function is Reports the type of network.
The getType() function return is int.

int type
0x00000000 TYPE_MOBILE
0x00000001 TYPE_WIFI
0x00000006 TYPE_WIMAX
0x00000009 TYPE_ETHERNET
0x00000007 TYPE_BLUETOOTH

I tried ways to get NetworkInfo.

Declare _di_JConnectivityManager variable.

_di_JConnectivityManager is the ConnectivityManager class interface.

 _di_JConnectivityManager    f_ConnectivityManager;

It creates to use '_di_JConnectivityManager'.

template <typename T1, typename T2> void __fastcall Tfm_main_wifistatus::getService(_di_JObject obj, T1& iobj)
{
    if (obj != nullptr)
    {
        iobj = T2::Wrap(_di_ILocalObject(obj)->GetObjectID());
    }
}
void __fastcall Tfm_main_wifistatus::FormCreate(TObject *Sender)
{
    //Form creation.Using TAndroidHelper, get the CONNECTIVITY_SERVICE.
    getService<_di_JConnectivityManager, TJConnectivityManager>(
        TAndroidHelper::Context->getSystemService(TJContext::JavaClass->CONNECTIVITY_SERVICE), f_ConnectivityManager);
}

Get the _di_JNetworkInfo using the getActiveNetworkInfo() function.

//TJConnectivityManager::JavaClass->TYPE_WIFI;
#define TYPE_WIFI 0x00000001
//TJConnectivityManager::JavaClass->TYPE_MOBILE;
#define TYPE_MOBILE 0x00000000
//TJConnectivityManager::JavaClass->TYPE_VPN;
#define TYPE_VPN 0x00000011
//TJConnectivityManager::JavaClass->TYPE_WIMAX;
#define TYPE_WIMAX 0x00000006

void __fastcall Tfm_main_wifistatus::Timer1Timer(TObject *Sender)
{
        UnicodeString net_str;
        _di_JNetworkInfo n_info = f_ConnectivityManager->getActiveNetworkInfo();
        if (n_info != nullptr)
        {
            switch (n_info->getType())
            {
            case TYPE_WIFI:
                net_str = L"(TYPE_WIFI)";    break;
            case TYPE_MOBILE:
                net_str = L"(TYPE_MOBILE)";  break;
            case TYPE_VPN:
                net_str = L"(TYPE_VPN)"; break;
            }
        }
        else
            net_str = L"(nullptr)";
}

You can get the status of a network interface.

Save Paradox Blob format to a file using BDE

$
0
0

C++Builder 10.2 Tokyo does not have BDE installed.
So, Install BDE separately in C++Builder 10.2 Tokyo.
It is after the end of the all of the installation.

 

Download BDE Installer for RAD Studio, Delphi, C++Builder 10.2 Tokyo

Download the installer from the URL below.
ID: 30752, BDE Installer for RAD Studio, Delphi, C++Builder 10.2 Tokyo 

 

Check the Paradox data.

Use the sample file named biolife.db.
This is sample data of Paradox.
I brought it from C++Builder 5 sample data.

There is a "Graphic" field in biolife.db. "Graphic" is Blob type.

 

Save the Blob data in the JPEG format using the BDE.

In VCL, JPEG can be processed using TJPEGImage.

#include <Vcl.Imaging.jpeg.hpp>

Use TTable to get all of biolife.db.

//---------------------------------------------------------------------------
void __fastcall TfmMain::bde_biofish_save()
{
    // created a new TTable and set the biolife table.
    std::auto_ptr<TTable> l_table( new TTable(this));
    l_table->DatabaseName    = "DBDEMOS";
    l_table->TableName      = "biolife.db";
    l_table->Active         = true;
    l_table->FindFirst();
    //Loop for acquiring all data.
    while (! l_table->Eof)
    {
        std::tr1::shared_ptr<TJPEGImage> l_jpeg(new TJPEGImage());
        std::tr1::shared_ptr<TMemoryStream> l_ms(new TMemoryStream());

        //Using the CreateBlobStream() function will create a new TStream.
        //Instances created with TStream need to be deleted.
        std::tr1::shared_ptr<TStream> ss(l_table->CreateBlobStream(
            l_table->FieldByName("Graphic"), TBlobStreamMode::bmRead));
        ss->Position = 8;
        l_ms->CopyFrom(ss.get(), ss->Size-8);
        l_ms->Position = 0;
        std::tr1::shared_ptr<TBitmap> b(new TBitmap());
        b->LoadFromStream(l_ms.get());
        //Convert calling Bitmap data to jpeg.
        l_jpeg->Assign(b.get());

        //When saving JPEG, the file name is "Species No" and "Species Name".
        l_jpeg->SaveToFile(l_table->FieldByName("Species No")->AsString + "_" +
            StringReplace(l_table->FieldByName("Species Name")->AsString, " ", "_", TReplaceFlags() <<rfReplaceAll) +
            ".jpeg");
        //Move to the next record.
        l_table->Next();
    }
}

Make the file name "Species No" + "Species Name" + ". Jpeg".
"Species No" + "Species Name" exists in DB field.

 

 

 

Confirm the output JPEG data

Back to the Future: Rückblick Forentage in Hamburg und EKON in Köln

$
0
0

In den letzten Tagen war es hier etwas ruhig..... Konferenzen und Urlaub muss auch mal sein.

Hier einige Eindrücke von den Forentagen in Hamburg:

Sebastian Gingter

Haupt-Session-Raum / Panorama

Die Vortragenden:

David Millington, Stefan Glienke, Bernd Ott, Sebastian Gingter, Volker Hillmann, Christina Kruse, Bernd Ua, Ulf Klarmann, Frank Lauter, Bruno Fierens, Uwe Raabe, ....

Und natürlich von der EKON aus Köln:

Marco Cantus Keynote

Bernd Ua Keynote

Einer meiner Vorträge

Mit insgesamt weit über 250 Teilnehmern wirklich tolle und erfolgreiche Veranstaltungen.

 

Debug visualizers for C++ templates

$
0
0

A few weeks ago, I wrote about how RAD Studio 10.2.1 supports debug vizualizers for Delphi generics:

Debug visualisers are a type of IDE plugin that allows you to change the display of a variable in the various debug windows (Local Variables, Watches, Inspector, and Evaluate/Modify.) For example, the TDateTime visualiser takes the double value that represents time and instead displays that time converted to a string. You register a debug visualiser for a type, so all variables of that type, and optionally descendants of that type, go through your visualiser.

In previous versions, as with generics, there was no way to register a visualizer for "MyTemplate<T, U>".  The visualizer would never fire because there would be no type in the compiled app named "MyTemplate<T, U>" - it would be a specific instantiation, such as MyTemplate<int, std::string>.

In 10.2.1, we have introduced support for registering a visualizer for C++ templates.  In fact, it works exactly the same as Delphi: the only trick to be aware of is that sometimes a C++ template has more parameters than you may be aware of.  This is important when implementing the visualizer's GetSupportedType() method which returns the type name.

For example, you may want to register a visualizer for a vector, and use the typename "std::vector<T>".  When the visualizer is installed, you won't see it have any effect and will realize it's not being called for vectors.  You actually need to return a typename with two generic parameters (the name of each doesn't matter), such as "std::vector<T, Allocator>".  Similarly, a std::map is a template with not only key and value template params, but comparison and allocator params too, so the correct type string is something like "std::map<K, V, Compare, Allocator>" (again, the exact names of the parameters doesn't matter.)

Unlike visualizers for a normal type, the visualizer is called only for an instantiation of the type with the type string specified, not descendants of the type.  If you need to alter display for descendants of a generic, you will need to register for those descendants too.

Finally, here is a code snippet demonstrating a template visualizer

Templates are widely used in C++ and we hope being able to register a visualizer for them will be useful for you!

Code snippet: IDE debug visualizer plugin for generic and template types

$
0
0

In RAD Studio 10.2.1 we added support for debug visualizers for Delphi generic and C++ template types.  A debug visualizer is an IDE plugin that allows you to change the display of a variable in the various debug windows, such as Local Variables and Watches.

"Great!", you may think, "but how do I actually write one of these visualizers?"

Pretty easily, as it turns out.

A debug vizualiser is an interfaced class that implements some specific Open Tools API interfaces (see toolsapi.pas), located in a DLL or package, and an instance of which is registered with the IDE when the package is loaded.  Those interfaces are:

  • IOTADebuggerVisualizer, IOTADebuggerVisualizer250: name and description of the visualizer, list of types it's interested in; version 250 adds support for generics or templates by allowing you to specify that a type string is for a generic or template type.
  • IOTADebuggerVisualizerValueReplacer: this lets you replace the result of an expression returned by the debug evaluator with some other content - whatever you want.  You can get more advanced than this, such as showing an external window for the results.  This is just a simple example.
  • IOTAThreadNotifier, IOTAThreadNotifier160: let you handle an evaluation completing.  A notifier, by convention in the ToolsAPI, also always has four other methods to do with saving, destroying and modification that are not meaningful in this example.

Generic and template debug visualizer example

Here's a complete visualizer code snippet.  To test this out, create a new package, and add designide to the Requires. Then add a unit called GenericVisualizer.pas to it and paste in the following source code.  To test it out, just right-click and Install, and then it's running right there inside your local IDE instance.  (You can also debug the IDE with IDE if you want to do some more advanced work and load it while debugging an instance of the IDE with your first copy of the IDE.)

Source code

.
unit GenericVisualizer;

interface

procedure Register;

implementation

uses
  Classes, SysUtils, ToolsAPI;

type
  TGenericVisualizer = class(TInterfacedObject, IOTADebuggerVisualizer,
    IOTADebuggerVisualizer250, IOTADebuggerVisualizerValueReplacer,
    IOTAThreadNotifier, IOTAThreadNotifier160)
  private
    FCompleted: Boolean;
    FDeferredResult: string;
  public
    { IOTADebuggerVisualizer }
    function GetSupportedTypeCount: Integer;
    procedure GetSupportedType(Index: Integer; var TypeName: string;
      var AllDescendants: Boolean); overload;
    function GetVisualizerIdentifier: string;
    function GetVisualizerName: string;
    function GetVisualizerDescription: string;
    { IOTADebuggerVisualizer250 }
    procedure GetSupportedType(Index: Integer; var TypeName: string;
      var AllDescendants: Boolean; var IsGeneric: Boolean); overload;
    { IOTADebuggerVisualizerValueReplacer }
    function GetReplacementValue(const Expression, TypeName,
      EvalResult: string): string;
    { IOTAThreadNotifier }
    procedure EvaluateComplete(const ExprStr: string; const ResultStr: string;
      CanModify: Boolean; ResultAddress: Cardinal; ResultSize: Cardinal;
      ReturnCode: Integer);
    procedure ModifyComplete(const ExprStr: string; const ResultStr: string;
      ReturnCode: Integer);
    procedure ThreadNotify(Reason: TOTANotifyReason);
    procedure AfterSave;
    procedure BeforeSave;
    procedure Destroyed;
    procedure Modified;
    { IOTAThreadNotifier160 }
    procedure EvaluateComplete(const ExprStr: string; const ResultStr: string;
      CanModify: Boolean; ResultAddress: TOTAAddress; ResultSize: LongWord;
      ReturnCode: Integer);
  end;

type
  TGenericVisualierType = record
    TypeName: string;
    IsGeneric: Boolean;
  end;

const
  GenericVisualizerTypes: array [0 .. 4] of TGenericVisualierType = (
    (TypeName: 'MyGenericType.IGenericInterface<T,T2>'; IsGeneric: True),
    (TypeName: 'MyGenericType.TGenericClass<System.Integer>'; IsGeneric: False),
    (TypeName: 'MyGenericType.TGenericClass<T>'; IsGeneric: True),
    (TypeName: 'std::vector<T, Allocator>'; IsGeneric: True),
    (TypeName: 'std::map<K, V, Compare, Allocator>'; IsGeneric: True)
  );

  { TGenericVisualizer }

procedure TGenericVisualizer.AfterSave;
begin
  // don't care about this notification
end;

procedure TGenericVisualizer.BeforeSave;
begin
  // don't care about this notification
end;

procedure TGenericVisualizer.Destroyed;
begin
  // don't care about this notification
end;

procedure TGenericVisualizer.Modified;
begin
  // don't care about this notification
end;

procedure TGenericVisualizer.ModifyComplete(const ExprStr, ResultStr: string;
  ReturnCode: Integer);
begin
  // don't care about this notification
end;

procedure TGenericVisualizer.EvaluateComplete(const ExprStr, ResultStr: string;
  CanModify: Boolean; ResultAddress, ResultSize: Cardinal; ReturnCode: Integer);
begin
  EvaluateComplete(ExprStr, ResultStr, CanModify, TOTAAddress(ResultAddress),
    LongWord(ResultSize), ReturnCode);
end;

procedure TGenericVisualizer.EvaluateComplete(const ExprStr, ResultStr: string;
  CanModify: Boolean; ResultAddress: TOTAAddress; ResultSize: LongWord;
  ReturnCode: Integer);
begin
  FCompleted := True;
  if ReturnCode = 0 then
    FDeferredResult := ResultStr;
end;

procedure TGenericVisualizer.ThreadNotify(Reason: TOTANotifyReason);
begin
  // don't care about this notification
end;

function TGenericVisualizer.GetReplacementValue(const Expression, TypeName,
  EvalResult: string): string;
begin
  Result := 'Generic visualizer:' + '; ' +
    'Expression: ' + Expression + '; ' +
    'Type name: ' + TypeName + '; ' +
    'Evaluation: ' + EvalResult;
end;

function TGenericVisualizer.GetSupportedTypeCount: Integer;
begin
  Result := Length(GenericVisualizerTypes);
end;

procedure TGenericVisualizer.GetSupportedType(Index: Integer;
  var TypeName: string; var AllDescendants: Boolean);
begin
  AllDescendants := True;
  TypeName := GenericVisualizerTypes[index].TypeName;
end;

procedure TGenericVisualizer.GetSupportedType(Index: Integer;
  var TypeName: string; var AllDescendants: Boolean; var IsGeneric: Boolean);
begin
  AllDescendants := True;
  TypeName := GenericVisualizerTypes[index].TypeName;
  IsGeneric := GenericVisualizerTypes[index].IsGeneric;
end;

function TGenericVisualizer.GetVisualizerDescription: string;
begin
  Result := 'Sample on how to register a generic visualizer';
end;

function TGenericVisualizer.GetVisualizerIdentifier: string;
begin
  Result := ClassName;
end;

function TGenericVisualizer.GetVisualizerName: string;
begin
  Result := 'Sample Generic Visualizer';
end;

var
  GenericVis: IOTADebuggerVisualizer;

procedure Register;
begin
  GenericVis := TGenericVisualizer.Create;
  (BorlandIDEServices as IOTADebuggerServices).RegisterDebugVisualizer(GenericVis);
end;

procedure RemoveVisualizer;
var
  DebuggerServices: IOTADebuggerServices;
begin
  if Supports(BorlandIDEServices, IOTADebuggerServices, DebuggerServices) then
  begin
    DebuggerServices.UnregisterDebugVisualizer(GenericVis);
    GenericVis := nil;
  end;
end;

initialization

finalization
  RemoveVisualizer;

end.

 

To test

For Delphi

Define some types:

.
type
  IGenericInterface<T,T2> = interface
  ['{2395EEA7-7E2E-485E-B6D3-C424A12FAE7F}']
  end;

  TGenericClassFromInterface<T,T2> = class(TInterfacedObject, IGenericInterface<T,T2>)
  end;


  TGenericClass<T> = class(TObject)
  end;

  TGenericClassDescendant<T> = class(TGenericClass<T>)
  end;

  TGenericClassDescendantInt = class(TGenericClass<Integer>)
  end;

This example is longer than the C++ one, because it demonstrates both generic classes and interfaces.  It also shows some descendant types, where you need to register the descendant type separately. (For a non-generic-type debug visualizer, the visualizer is called for descendants of the registered type automatically.)

And create a new console app, giving it the contents:

.
procedure foo;
var
  a: TGenericClassFromInterface<Integer, string>;
  a1: IGenericInterface<Integer, string>;
  b: TGenericClass<string>;
  c: TGenericClass<Integer>;
  d: TGenericClassDescendant<string>;
  e: TGenericClassDescendantInt;
begin
  a := TGenericClassFromInterface<Integer, string>.Create;
  a1 := a;

  b := TGenericClass<string>.Create;
  c := TGenericClass<Integer>.Create;
  d := TGenericClassDescendant<string>.Create;
  e := TGenericClassDescendantInt.Create;

  writeln('abc'); // set breakpoint here
end;

begin
  try
    foo;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

For C++

Create a new console app (and some shiny new template types as well, if you wish) and give it the contents:

.
int _tmain(int argc, _TCHAR* argv[])
{
	std::vector<int> myVec;
	std::map<int, std::string> myMap;


	return 0;    // BP here
}

To extend

This is the exciting bit!  Try changing the data returned from GetReplacementValue(), and also try evaluating expressions yourself in the visualizer to use in the returned replacement.

Have fun!

 

iPhone X, Face ID und Delphi

$
0
0

Apple bietet für das iPhone X eine neue Autorisierungsmöglichkeit an: Face ID. Generell ist Face ID, als Nachfolger von Touch ID (dem Fingerabdrucksensor seit dem iPhone 5S) auf API Ebene kompatibel zu Touch ID. Also sollte die kleine Unit von https://bitbucket.org/allesbeste/ios-touchid-wrapper-for-delphi auch hier mit Face ID funktionieren.

Und die Unit funktioniert auch mit Delphi und Face ID auf dem iPhone X:

Generell kapselt die Unit iOSapi.LocalAuthentication (vom oben angegeben Link) die absoluten, aber ausreichenden Grundfunktionalitäten aus dem LocalAuthetication-Framework: Die Fallback-Methode habe ich etwas umgeschrieben. Hier wird die Statusbar (ein anderes Thema für iPhone X) einfach rot oder grün gefärbt:

uses
[...] iOSapi.LocalAuthentication [...]


procedure TFormIrgendwas.TouchIDReply(success, error: Pointer); var bSuccess: Boolean; begin bSuccess := false; if not Assigned(error) AND Assigned(success) then begin bSuccess := ((Integer(success)) = 1); end; if bSuccess then begin // hat geklappt! Autorisiert self.SystemStatusBar.BackgroundColor := TAlphaColorRec.Darkgreen; end else begin // keine Autorisierung! self.SystemStatusBar.BackgroundColor := TAlphaColorRec.Darkred; end; // Form neu zeichnen self.Invalidate; end;

Tech Tipp #11: Lizenzserver ELC unter Windows Server 2016

$
0
0

In den letzten Tagen bekomme ich häufiger diese Frage:

Frage: Ich möchte den Lizenzserver ELC unter Windows Server 2016 installieren. Aber schon während der Installation bekomme ich einen hässlichen Fehler. Ich benutze dazu die Installationsdatei von http://altd.embarcadero.com/download/ELC/win64/ELC532_64.exe, wie hier beschrieben:
http://docwiki.embarcadero.com/ELC/53/en/ELC_Quick_Start

Antwort: Nutzen Sie bitte diese Installationsdatei

http://altd.embarcadero.com/download/ELC/win64/ELC531_64.exe

Die geht


RAD Studio 10.2.2 Released Today

$
0
0

I am excited to announce that RAD Studio 10.2.2 was released today. 10.2 Tokyo, Release 2 (also known as 10.2.2) is an update of Delphi 10.2 Tokyo, C++Builder 10.2 Tokyo and RAD Studio 10.2 Tokyo available for any active Update Subscription customer.

 

10.2.2 Registered User Download Links:

Docwiki: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/10.2_Tokyo_-_Release_2  

 

Several key new features were added, including FireMonkey Quick Edit support, a number of new VCL controls, a new dark themed IDE option, a RAD Server single site deployment license in Enterprise and Architect editions, installer and welcome page enhancements and more.

 

Also included is newly added support for macOS High Sierra, and enhanced platform support for iOS 11 (including iPhone X), Android 8, Windows 10, and Linux, additional enhancements throughout various product areas, and over quality improvements to over 150 publicly reported issues.

 

 

Key RAD Studio 10.2.2 Features:

The new dark theme is designed for night-time work or lengthy use, with updated component icons that complement both the light and dark theme. Easily toggle between the newly added dark theme and the existing light theme through a newly provided option on the desktop toolbar in the IDE.

 

 

Improve developer productivity with the new Quick Edit feature for FireMonkey, allowing you to quickly perform common actions in the FireMonkey Form Designer.

 

 

 

Also new in 10.2.2 are four new VCL Windows GUI controls, designed with Windows 10 in mind.

  • TCardPanel: The new Card Panel is a specialized component that manages a collection of cards.
  • TStackPanel: The Stack Panel is a new container control that allows you to automatically align all parented controls vertically or horizontally while retaining each control's custom height and width settings.
  • TDatePicker and TTimePicker are modern date and time picker controls with support for multiple formatting options, a custom drop-down count and ok and cancel date and time selection buttons.

 

 

Also new is an updated IDE Welcome Page with new sample projects, videos from our YouTube channel, and a calendar of local and global events to help new users get started quickly.

 

Delphi, C++Builder and RAD Studio Enterprise and Architect editions now include a RAD Server Single Site/Single Server deployment license. Also covered by the included single site RAD Server license is BeaconFence deployment for a single location with unlimited users, and no square footage limitation

 

We've also enhanced our JavaScript client support for Sencha Ext JS with RAD Server through TDataSet JSON mapping.

 

Click on our new 10.2.2 product video below to see the key new features in action:


[YoutubeButton url='https://www.youtube.com/watch?v=iGnJANX18uw']

 

New to RAD Studio? Download the RAD Studio 10.2.2 Trial today!

Webinaraufzeichnungen: RAD Studio 10.2 Release 2 / Akademische Lizenzen / Delphi und Linux

$
0
0

In den letzten Tagen habe ich einige Webinare durchgeführt. Selbstverständlich gibt es davon Aufzeichnungen auf dem Embarcadero Germany Channel auf YouTube.

  • Delphi als Lehr und Lernsprache

    [YoutubeButton url='https://www.youtube.com/watch?v=fmRPL9LVJOk']
  • Delphi 10.2 Release 2 Neuerungen

    [YoutubeButton url='https://www.youtube.com/watch?v=PUfZ_Vv3-s0']
  • Delphi und Linux Entwicklung
    Grundlagen

    [YoutubeButton url='https://www.youtube.com/watch?v=NMfdzzt9YWY']

    FMX Linux

    [YoutubeButton url='https://www.youtube.com/watch?v=5ZN5CGp-dCU']

Tech Tipp #12: Android 8.x und Debugging

$
0
0

Frage: Ich kann mit dem RAD Studio/Delphi/C++Builder  10.2 auf meinem Android 8.0 Gerät nicht debuggen. Wodran liegt das?

Antwort: Google ist mit dem Android 8.0 Release "etwas" über das Ziel hinausgeschossen..... Google hat mit dem Release von Android 8.0 in diesem Sommer (war das ein Sommer?) einige Sicherheitsfeatures nachgeschärft. Leider ist dadurch das Debugging flöten gegangen. "Can't open socket: Permission denied.".

Dazu gibt es auch einige Diskussionen hier und hier.

Die gute Nachricht: Google hat das mit Android 8.1 geradegebogen. Viel Glück an die Android-User ein Oreo 8.1 Update zu erhalten.

Quelle: http://blog.marcocantu.com/blog/2017-december-delphi-android81-debugging.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+marcocantublog+%28marcocantu.blog%29

 

It is a new function of 10.2.2, and it can be outputted by Ext JS store definition.

$
0
0

New in 10.2.2 TFDBatchMoveJSONWriter was added.

TFDBatchMoveJSONWriter is a Writer that combines with TFDBatchMove to out to a simple JSON. But,  TFDBatchMoveJSONWriter has the function of generating Model definition of Ext JS.
I tried with a field dynamically created with TFDMemTable.

code

The code below is a simple 64-bit console application.
I wrote this code using C++Builder.

umain.cpp
#include <vcl.h>
#include <windows.h>

#pragma hdrstop
#pragma argsused
#pragma link "dbrtl.a"
#pragma link "FireDAC.a"
#pragma link "FireDACCommonDriver.a"
#pragma link "FireDACCommon.a"

#include <tchar.h>
#include <iostream>
#include <System.JSON.hpp>
#include <FireDAC.Stan.Intf.hpp>
#include <FireDAC.Stan.Option.hpp>
#include <FireDAC.Stan.Param.hpp>
#include <FireDAC.Stan.Error.hpp>
#include <FireDAC.DatS.hpp>
#include <FireDAC.Phys.Intf.hpp>
#include <FireDAC.DApt.Intf.hpp>
#include <FireDAC.Comp.BatchMove.JSON.hpp>
#include <FireDAC.Comp.BatchMove.hpp>
#include <FireDAC.Comp.BatchMove.DataSet.hpp>
#include <Data.DB.hpp>
#include <FireDAC.Comp.DataSet.hpp>
#include <FireDAC.Comp.Client.hpp>
#include <FireDAC.Stan.StorageJSON.hpp>
#include <functional>
#include <string>
#include <sstream>

struct dbs
{
    TFDMemTable* f_MemTable1;
    TFDBatchMove* f_BatchMove1;
    TFDBatchMoveDataSetReader* f_DataSetReader1;
    TFDBatchMoveJSONWriter* f_JSONWriter1;
    TFDStanStorageJSONLink* f_JSONLink1;
    dbs(std::function<void(TFDMemTable*)> func)
    {
        f_MemTable1         = new TFDMemTable(nullptr);
        f_BatchMove1        = new TFDBatchMove(nullptr);
        f_DataSetReader1    = new TFDBatchMoveDataSetReader(nullptr);
        f_JSONWriter1       = new TFDBatchMoveJSONWriter(nullptr);
        f_JSONLink1         = new TFDStanStorageJSONLink(nullptr);
        f_DataSetReader1->DataSet   = f_MemTable1;
        f_BatchMove1->Reader        = *f_DataSetReader1;
        f_BatchMove1->Writer        = *f_JSONWriter1;
        func(f_MemTable1);
    };
    static inline String IToString(int iin)
    {
        std::wostringstream ss;
        ss << iin;
        return ss.str().c_str();
    }

    ~dbs()
    {
        delete f_MemTable1;
        delete f_BatchMove1;
        delete f_DataSetReader1;
        delete f_JSONWriter1;
        delete f_JSONLink1;
    };
};

int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        TStringList* alist = new TStringList();
        try
        {
            dbs adbs([](TFDMemTable* memt)
                {
                    //Field definition of TFDMemTable* instance.
                    //Create five fields.
                    for (int i = 0; i < 5; i++)
                    {
                        TStringField* aField    = new TStringField(nullptr);
                        aField->FieldName       = "Column" + dbs::IToString(i);
                        aField->Size            = 50;
                        memt->Fields->Add(aField);
                    }
                });
            //Then execute the GenerateExtJSModel() method.
            //This GenerateExtJSModel() is a TFDBatchMoveJSONWriter class that has been added than 10.2.2.
            adbs.f_JSONWriter1->GenerateExtJSModel("Table1", true, alist);
            //Console out.
            std::wcout << alist->Text.c_str() << std::endl;
        }
        __finally
        {
            delete alist;
        }

    }
    catch(...)
    {

    }
    return 0;
}

result GenerateExtJSModel()

The output store definition is as follows.

Ext.define('Table1', {
  extend: 'Ext.data.Model',
  requires: [
    'Ext.data.field.Field'
  ],
  fields: [
    { name: 'Column0', type: 'string' },
    { name: 'Column1', type: 'string' },
    { name: 'Column2', type: 'string' },
    { name: 'Column3', type: 'string' },
    { name: 'Column4', type: 'string' }
  ]
});

It can be output in Ext JS store definition.
2018-01-011450.png

C++Builder 10.2.2 新コンポーネントTCardPanel[JAPAN]

$
0
0

あけましておめでとうございます。2018年が皆様にとって、飛躍の年であるよう祈っております。新しい年の始まりにあたり、Eショップ各社にて、新春初売りキャンペーンを実施します。幅広い製品ラインナップが18% OFF!1月31日までの期間限定です。この機会をぜひご活用ください。

 

C++Builder 10.2 Release 2 TCardPanelについて

TCardPanel概要

TCardPanelは、複数のTCardとセットで利用します。
IDEのデザイナ上でTCardを作成し管理する事ができ、TCardPanelを配置した上にTButtonなどのコンポーネントをドラッグ&ドロップすると自動でTCardが作られその配下にTButtonが配置されます。
TCardはフォーム上に作られるが、TCardPanel内部ではTList<TCard>を作って管理している。


TCardPanel機能

TCardを管理する為のいくつかの機能があります。

CreateNewCard();

新しくTCardを作成し、アクティブにする。

 TCard* acard = CardPanel1->CreateNewCard();
    TButton* b1 = new TButton(this);
    b1->Parent =  acard;

 

DeleteCard(int Index);

TCardを削除する。コンテナから消すだけではなくインスタンスもdeleteする。

 //アクティブなカード番号を取得しカードを削除
    CardPanel1->DeleteCard(CardPanel1->ActiveCardIndex);

 

FindNextCard(int Index, bool GoForward, bool CheckCardVisible);

順方向または逆方向に順番に次のカードのインデックスを取得する。

引数名 内容
Index 開始位置
GoForward false =前, true=後
CheckCardVisible false = visibleカードだけを検索
 int i = CardPanel1->FindNextCard(0,true,false);

 

NextCard();

次のカードに移動

 CardPanel1->NextCard();

 

PreviousCard();

前のカードに移動

 CardPanel1->PreviousCard();

 

プロパティ ActiveCardIndex

アクティブなカード番号を取得

 int i = CardPanel1->ActiveCardIndex;

 

プロパティ ActiveCard

アクティブなカード取得

 TCard* acard = CardPanel1->ActiveCard;

 

プロパティ CardCount

TCardPanel上のカード数

 int acount = CardPanel1->CardCount;

 

プロパティ Cards[int Index]

TCardPanel上カード個別取得

 TCard* acard = CardPanel1->Cards[0];

 

プロパティ Loop

ナビゲートするときにNextCardおよびPreviousCardのメソッドがカードリストの反対側にループするかどうかを制御します。

 CardPanel1->Loop = true;

 

イベント OnCardChange

アクティブなカードが別のカードに変更された場合に発生します。

typedef void __fastcall (__closure *TCardChangeEvent)(System::TObject* Sender, TCard* PrevCard, TCard* NextCard);

 

Viewing all 182 articles
Browse latest View live




Latest Images