2017年3月23日

RAD Studio/Delphi/C++Builder 10.2 Tokyoリリース

RAD Studio/Delphi/C++Builder 10.2 Tokyoがリリースされています。

RAD Studio 10.2 Tokyo ヘルプ (en)
リリース ノート (en)
インストール ノート (en)
新機能 (en)

List of new features and customer reported issues fixed in RAD Studio 10.2 Tokyo

30722 RAD Studio, Delphi, C++Builder 10.2 Tokyo Web Install
30724 RAD Studio, Delphi, C++Builder 10.2 Tokyo ISO

30752 BDE Installer for RAD Studio, Delphi, C++Builder 10.2 Tokyo
30728 FastReport VCL for RAD Studio, Delphi, C++Builder 10.2 Tokyo
30729 FastReport FMX for RAD Studio, Delphi, C++Builder 10.2 Tokyo
30730 IP*Works for RAD Studio, Delphi 10.2 Tokyo
30731 IP*Works for RAD Studio, C++Builder 10.2 Tokyo
30750 Codesite for RAD Studio, Delphi, C++Builder 10.2 Tokyo

GitHub - lynatan/StarterFix: Restore Form Designer Options for Starter edition.

【Delphi / C++Builder 10.2 Tokyo 新機能・改善点】C++ コンパイラ 周りの改善など - Qiita
【Delphi / C++Builder 10.2 Tokyo 新機能・改善点】FireDAC、データベース接続周りの改善など - Qiita
【Delphi / C++Builder 10.2 Tokyo 新機能・改善点】RAD Server の改善など - Qiita
【Delphi / C++Builder 10.2 Tokyo 新機能・改善点】IDEまわりの改善など - Qiita
【Delphi / C++Builder 10.2 Tokyo 新機能・改善点】ライブラリ周りの機能など - Qiita

What's New in C++Builder 10.2: Part 1 - The Linker
What's New in C++Builder 10.2: Part 2 - Code Generation
What's New in C++Builder 10.2: Part 3 - Debugging

Firebird 3.0.2

Firebird 3.0.2がリリースされています。

Firebird: Firebird 3.0.2
Firebird 3.0.2 Release Notes (PDF)

2017年3月22日

ジェネリックスのリストをアルゴリズムを指定してソートする

Delphi 2009で導入されたジェネリックスコンテナの一つであるTList<T>にはSortメソッドがあり、比較関数としてデフォルト以外のComparer(コンペアラ)も渡すことができるのですが、ソートアルゴリズムそのものはクイックソートしかありません。一般的には平均して性能が出るとされるクイックソートですが、安定ではないこと、苦手な状況が存在することなど、決して万能というわけではありません。ところがTList<T>.Sortは内部で保持しているTArray.Sortにソートを丸投げしており、ソートアルゴリズムを変更することができません。そこでアルゴリズムを指定してTList<T>(およびTObjectList<T: class>)をソートする方法を考えてみました。ただしDelphi 2009のTList<T>にはExchangeメソッドもMoveメソッドも存在していないため、Delphi 2010以降の対応になります。

まずソートを行うためのレコード型と、ソートアルゴリズムを実装するクラスの継承元クラスの宣言です。
{$IF RTLVersion <= 20.00}
{$MESSAGE ERROR 'Need Delphi 2010 or later'}
{$IFEND}

uses
{$IF RTLVersion >= 23.00}
  System.Rtti, System.Generics.Defaults, System.Generics.Collections;
{$ELSE}
  Rtti, Generics.Defaults, Generics.Collections;
{$IFEND}

type
  { Forward declarations }
  TSortAlgorithm<T> = class;

  { TGenericListSorter }
  TGenericListSorter = record
  private
    class function  GetComparer<T>(List: TList<T>; const AComparer: IComparer<T>): IComparer<T>; static;
  public
    class procedure Sort<T: record>(List: TList<T>; Algorithm: TSortAlgorithm<T>;
                                    const AComparer: IComparer<T>{$IF CompilerVersion >= 24.00} = nil{$IFEND}); overload; static;
{$IF CompilerVersion < 24.00}
    class procedure Sort<T: record>(List: TList<T>; Algorithm: TSortAlgorithm<T>); overload; static;
{$IFEND}
    class procedure Sort<T: class>(List: TObjectList<T>; Algorithm: TSortAlgorithm<T>;
                                   const AComparer: IComparer<T>{$IF CompilerVersion >= 24.00} = nil{$IFEND}); overload; static;
{$IF CompilerVersion < 24.00}
    class procedure Sort<T: class>(List: TObjectList<T>; Algorithm: TSortAlgorithm<T>); overload; static;
{$IFEND}
    class procedure Sort(List: TList<String>; Algorithm: TSortAlgorithm<String>;
                         const AComparer: IComparer<String>{$IF CompilerVersion >= 24.00} = nil{$IFEND}); overload; static;
{$IF CompilerVersion < 24.00}
    class procedure Sort(List: TList<String>; Algorithm: TSortAlgorithm<String>); overload; static;
{$IFEND}
  end;

  { TSortAlgorithm (abstract) }
  TSortAlgorithm<T> = class(TObject)
  public
    class function  Instance: TSortAlgorithm<T>; virtual; abstract;
    class procedure Sort(List: TList<T>; const AComparer: IComparer<T>); virtual; abstract;
  end;
TGenericListSorterはソートを行うためのレコード型で、overloadされたpublicな3つ(XE2およびそれ以前は6つ、後述)のSortメソッドと、比較を行うコンペアラを決定するためのprivateなGetComparerメソッドを持ちます。Sortメソッドの1つめは値型用(レコード制約)、2つめはクラス型用(クラス制約)、3つめはこのどちらにも含まれない文字列型用です。IComparer<T>にデフォルトパラメータを指定できるのはDelphi XE3以降のため、それ以前のバージョンではコンペアラを指定しないオーバロードをさらに3つ用意しました。またTSortAlgorithm<T>はソートアルゴリズムを実装するためのクラスの継承元になります。実際にソートを行うSortメソッドと、シングルトンなインスタンスを取得するためのInstanceメソッドを持ちます。TGenericListSorterの実装は次のようになります。
class procedure TGenericListSorter.Sort<T>(List: TList<T>; Algorithm: TSortAlgorithm<T>;
                                           const AComparer: IComparer<T>);
var
  Comparer: IComparer<T>;
begin

  if (List = nil) or (List.Count <= 1) then
  begin
    Exit;
  end;

  Comparer := GetComparer<T>(List,AComparer);

  Algorithm.Sort(List,Comparer);

end;

{$IF CompilerVersion < 24.00}
class procedure TGenericListSorter.Sort<T>(List: TList<T>; Algorithm: TSortAlgorithm<T>);
var
  Comparer: IComparer<T>;
begin

  if (List = nil) or (List.Count <= 1) then
  begin
    Exit;
  end;

  Comparer := GetComparer<T>(List,nil);

  Algorithm.Sort(List,Comparer);

end;
{$IFEND}

class procedure TGenericListSorter.Sort<T>(List: TObjectList<T>; Algorithm: TSortAlgorithm<T>;
                                           const AComparer: IComparer<T>);
var
  Comparer: IComparer<T>;
  OwnsObjects: Boolean;
begin

  if (List = nil) or (List.Count <= 1) then
  begin
    Exit;
  end;

  Comparer := GetComparer<T>(List,AComparer);

  OwnsObjects := List.OwnsObjects;
  try
    List.OwnsObjects := False;
    Algorithm.Sort(List,Comparer);

  finally
    List.OwnsObjects := OwnsObjects;
  end;

end;

{$IF CompilerVersion < 24.00}
class procedure TGenericListSorter.Sort<T>(List: TObjectList<T>; Algorithm: TSortAlgorithm<T>);
var
  Comparer: IComparer<T>;
  OwnsObjects: Boolean;
begin

  if (List = nil) or (List.Count <= 1) then
  begin
    Exit;
  end;

  Comparer := GetComparer<T>(List,nil);

  OwnsObjects := List.OwnsObjects;
  try
    List.OwnsObjects := False;
    Algorithm.Sort(List,Comparer);

  finally
    List.OwnsObjects := OwnsObjects;
  end;

end;
{$IFEND}

class procedure TGenericListSorter.Sort(List: TList<String>; Algorithm: TSortAlgorithm<String>;
                                        const AComparer: IComparer<String>);
var
  Comparer: IComparer<String>;
begin

  if (List = nil) or (List.Count <= 1) then
  begin
    Exit;
  end;

  Comparer := GetComparer<String>(List,AComparer);

  Algorithm.Sort(List,Comparer);

end;

{$IF CompilerVersion < 24.00}
class procedure TGenericListSorter.Sort(List: TList<String>; Algorithm: TSortAlgorithm<String>);
var
  Comparer: IComparer<String>;
begin

  if (List = nil) or (List.Count <= 1) then
  begin
    Exit;
  end;

  Comparer := GetComparer<String>(List,nil);

  Algorithm.Sort(List,Comparer);

end;
{$IFEND}

class function TGenericListSorter.GetComparer<T>(List: TList<T>; const AComparer: IComparer<T>): IComparer<T>;
var
  ctx: TRttiContext;
begin

  Result := AComparer;
  if Result = nil then
  begin
    Result := ctx.GetType(List.ClassType).GetField('FComparer').GetValue(List).AsType<IComparer<T>>;
  end;

end;
Sortメソッドはいずれもコンペアラを確定し、指定されたソートアルゴリズムのインスタンスのSortメソッドを呼び出しています。ただしTObjectList<T>用のオーバロードはソートを行っている間、一時的にOwnsObjectsをFalseに変更しています。これはOwnsObjectsがTrueだと(以下の例のマージソートのように)Items[]に代入を行ったときに、もともと格納されているTのインスタンスを解放してしまうためで、ソートアルゴリズムのクラスで直接ソートを行うのではなく、レコード型TGenericListSorterの3つのオーバロードに処理を分けて、そこから間接的に呼び出すようになっているのはこれが理由です。またGetComparerメソッドはコンペアラが指定されていない(=nil)ときに、TList<T>の持つデフォルトのコンペアラを(RTTIを使って)取得します。 次に実際のソートアルゴリズムを実装したクラスですが、まずコムソートを実装してみます。
type
  TCombSort<T> = class(TSortAlgorithm<T>)
  protected
    class var
      FInstance: TSortAlgorithm<T>;
  public
    class destructor Destroy;
    class function   Instance: TSortAlgorithm<T>; override;
    class procedure  Sort(List: TList<T>; const AComparer: IComparer<T>); override;
  end;

class destructor TCombSort<T>.Destroy;
begin

  FInstance.Free;

end;

class function TCombSort<T>.Instance: TSortAlgorithm<T>;
begin

  if FInstance = nil then
  begin
    FInstance := Self.Create;
  end;

  Result := FInstance;

end;

class procedure TCombSort<T>.Sort(List: TList<T>; const AComparer: IComparer<T>);
const
  SHRINK_FACTOR = 1.247330950103979;
var
  Index: Integer;
  Gap: Integer;
  Swapped: Boolean;
begin

  Gap := List.Count;
  Swapped := True;

  while (Gap > 1) or (Swapped = True) do
  begin
    if Gap > 1 then
    begin
      Gap := Trunc(Gap / SHRINK_FACTOR);
    end;

    if Gap < 1 then
    begin
      Gap := 1;
    end;

    Swapped := False;
    Index := 0;

    while (Gap + Index) < List.Count do
    begin
      if AComparer.Compare(List.Items[Index],List.Items[Index + Gap]) > 0 then
      begin
        List.Exchange(Index,Index + Gap);
        Swapped := True;
      end;
      Index := Index + 1;
    end;
  end;

end;
前述の通り(TGenericListSorterとは異なり)1種類の<T>に対してのみSortを実装すればよいようになっています。またSortメソッド以外にシングルトンなインスタンスを取得するためのInstanceメソッドと、そのインスタンスを解放するためのクラスデストラクタを用意します。これで例えばInteger型のリストに対しては
var
  I: Integer;
  Value: Integer;
  List: TList<Integer>;
begin
  List := TList<Integer>.Create;
  try
    for I := 0 to 999 do
    begin
      List.Add(Random(100000));
    end;

    TGenericListSorter.Sort<Integer>(List,TCombSort<Integer>.Instance,TComparer<Integer>.Construct(
      function(const Left, Right: Integer): Integer
      begin
        Result := Left - Right;
      end));

    for Value in List do
    begin
      Memo1.Lines.Add(IntToStr(Value));
    end;

  finally
    List.Free;
  end
end;
このような形でソートを呼び出すことができます。 同じようにその他のソートアルゴリズムを実装していきます。ノームソートです。
type
  TGnomeSort<T> = class(TSortAlgorithm<T>)
  protected
    class var
      FInstance: TSortAlgorithm<T>;
  public
    class destructor Destroy;
    class function   Instance: TSortAlgorithm<T>; override;
    class procedure  Sort(List: TList<T>; const AComparer: IComparer<T>); override;
  end;

class destructor TGnomeSort<T>.Destroy;
begin

  FInstance.Free;

end;

class function TGnomeSort<T>.Instance: TSortAlgorithm<T>;
begin

  if FInstance = nil then
  begin
    FInstance := Self.Create;
  end;

  Result := FInstance;

end;

class procedure TGnomeSort<T>.Sort(List: TList<T>; const AComparer: IComparer<T>);
var
  Index: Integer;
begin

  Index := 0;
  while Index < List.Count do
  begin
    if (Index = 0) or (AComparer.Compare(List.Items[Index],List.Items[Index - 1]) >= 0) then
    begin
      Index := Index + 1;
    end
    else
    begin
      List.Exchange(Index,Index - 1);
      Index := Index - 1;
    end;
  end;

end;
選択ソートです。
type
  TSelectionSort<T> = class(TSortAlgorithm<T>)
  protected
    class var
      FInstance: TSortAlgorithm<T>;
  public
    class destructor Destroy;
    class function   Instance: TSortAlgorithm<T>; override;
    class procedure  Sort(List: TList<T>; const AComparer: IComparer<T>); override;
  end;

class destructor TSelectionSort<T>.Destroy;
begin

  FInstance.Free;

end;

class function TSelectionSort<T>.Instance: TSortAlgorithm<T>;
begin

  if FInstance = nil then
  begin
    FInstance := Self.Create;
  end;

  Result := FInstance;

end;

class procedure TSelectionSort<T>.Sort(List: TList<T>; const AComparer: IComparer<T>);
var
  Index1: Integer;
  Index2: Integer;
  MinIndex: Integer;
  Temp: T;
begin

  for Index1 := 0 to List.Count - 2 do
  begin
    MinIndex := Index1;
    Temp := List.Items[MinIndex];

    for Index2 := Index1 + 1 to List.Count - 1 do
    begin
      if AComparer.Compare(List.Items[Index2],Temp) < 0 then
      begin
        MinIndex := Index2;
        Temp := List.Items[MinIndex];
      end;
    end;

    if MinIndex <> Index1 then
    begin
      List.Move(MinIndex,Index1);
    end;
  end;

end;
挿入ソートです。
type
  TInsertionSort<T> = class(TSortAlgorithm<T>)
  protected
    class var
      FInstance: TSortAlgorithm<T>;
  public
    class destructor Destroy;
    class function   Instance: TSortAlgorithm<T>; override;
    class procedure  Sort(List: TList<T>; const AComparer: IComparer<T>); override;
  end;

class destructor TInsertionSort<T>.Destroy;
begin

  FInstance.Free;

end;

class function TInsertionSort<T>.Instance: TSortAlgorithm<T>;
begin

  if FInstance = nil then
  begin
    FInstance := Self.Create;
  end;

  Result := FInstance;

end;

class procedure TInsertionSort<T>.Sort(List: TList<T>; const AComparer: IComparer<T>);
var
  Comparer: IComparer<T>;
  Index1: Integer;
  Index2: Integer;
  Temp: T;
begin

  for Index1 := 1 to List.Count - 1 do
  begin
    Temp := List.Items[Index1];
    Index2 := Index1 - 1;

    while (Index2 >= 0) and (AComparer.Compare(List.Items[Index2],Temp) > 0) do
    begin
      Index2 := Index2 - 1;
    end;

    List.Move(Index1,Index2 + 1);
  end;

end;
クイックソートです。
type
  TQuickSort<T> = class(TSortAlgorithm<T>)
  protected
    class var
      FInstance: TSortAlgorithm<T>;
    class procedure  InternalSort(List: TList<T>; Left: Integer; Right: Integer;
                                  const AComparer: IComparer<T>);
    class function   Partition(List: TList<T>; Left: Integer; Right: Integer;
                               const AComparer: IComparer<T>): Integer;
  public
    class destructor Destroy;
    class function   Instance: TSortAlgorithm<T>; override;
    class procedure  Sort(List: TList<T>; const AComparer: IComparer<T>); override;
  end;

class destructor TQuickSort<T>.Destroy;
begin

  FInstance.Free;

end;

class function TQuickSort<T>.Instance: TSortAlgorithm<T>;
begin

  if FInstance = nil then
  begin
    FInstance := Self.Create;
  end;

  Result := FInstance;

end;

class procedure TQuickSort<T>.Sort(List: TList<T>; const AComparer: IComparer<T>);
var
  Comparer: IComparer<T>;
begin

  InternalSort(List,0,List.Count - 1,AComparer);

end;

class procedure TQuickSort<T>.InternalSort(List: TList<T>; Left: Integer; Right: Integer;
                                           const AComparer: IComparer<T>);
var
  Pivot: Integer;
begin

  if Left < Right then
  begin
    Pivot := Partition(List,Left,Right,AComparer);

    InternalSort(List,Left,     Pivot,AComparer);
    InternalSort(List,Pivot + 1,Right,AComparer);
  end;

end;

class function TQuickSort<T>.Partition(List: TList<T>; Left: Integer; Right: Integer;
                                       const AComparer: IComparer<T>): Integer;
var
  Index1: Integer;
  Index2: Integer;
  Pivot: T;
begin

  Pivot := List.Items[(Left + Right) div 2];
  Index1 := Left  - 1;
  Index2 := Right + 1;

  while True do
  begin
    repeat
      Index1 := Index1 + 1;
    until (AComparer.Compare(List.Items[Index1],Pivot) >= 0);

    repeat
      Index2 := Index2 - 1;
    until (AComparer.Compare(List.Items[Index2],Pivot) <= 0);

    if Index1 >= Index2 then
    begin
      Result := Index2;
      Exit;
    end;

    List.Exchange(Index1,Index2);
  end;

end;
ヒープソートです。
type
  THeapSort<T> = class(TSortAlgorithm<T>)
  protected
    class var
      FInstance: TSortAlgorithm<T>;
    class procedure  BuildHeap(List: TList<T>; const AComparer: IComparer<T>);
    class procedure  Heapify(List: TList<T>; Index: Integer; Max: Integer;
                             const AComparer: IComparer<T>);
  public
    class destructor Destroy;
    class function   Instance: TSortAlgorithm<T>; override;
    class procedure  Sort(List: TList<T>; const AComparer: IComparer<T>); override;
  end;

class destructor THeapSort<T>.Destroy;
begin

  FInstance.Free;

end;

class function THeapSort<T>.Instance: TSortAlgorithm<T>;
begin

  if FInstance = nil then
  begin
    FInstance := Self.Create;
  end;

  Result := FInstance;

end;

class procedure THeapSort<T>.Sort(List: TList<T>; const AComparer: IComparer<T>);
var
  Index: Integer;
begin

  BuildHeap(List,AComparer);

  for Index := List.Count - 1 downto 1 do
  begin
    List.Exchange(0,Index);

    Heapify(List,0,Index,AComparer);
  end;

end;

class procedure THeapSort<T>.BuildHeap(List: TList<T>; const AComparer: IComparer<T>);
var
  Index: Integer;
begin

  for Index := (List.Count div 2) - 1 downto 0 do
  begin
    Heapify(List,Index,List.Count,AComparer);
  end;

end;

class procedure THeapSort<T>.Heapify(List: TList<T>; Index: Integer; Max: Integer;
                                     const AComparer: IComparer<T>);
var
  Left: Integer;
  Right: Integer;
  Largest: Integer;
begin

  Left  := Index * 2 + 1;
  Right := Index * 2 + 2;

  if (Left < Max) and (AComparer.Compare(List.Items[Left],List.Items[Index]) > 0) then
  begin
    Largest := Left;
  end
  else
  begin
    Largest := Index;
  end;

  if (Right < Max) and (AComparer.Compare(List.Items[Right],List.Items[Largest]) > 0) then
  begin
    Largest := Right;
  end;

  if Largest <> Index then
  begin
    List.Exchange(Index,Largest);

    Heapify(List,Largest,Max,AComparer);
  end;

end;
マージソートです。
type
  TMergeSort<T> = class(TSortAlgorithm<T>)
  protected
    class var
      FInstance: TSortAlgorithm<T>;
    class procedure  InternalSort(List: TList<T>; var Work: array of T;
                                  Left: Integer; Right: Integer;
                                  const AComparer: IComparer<T>);
  public
    class destructor Destroy;
    class function   Instance: TSortAlgorithm<T>; override;
    class procedure  Sort(List: TList<T>; const AComparer: IComparer<T>); override;
  end;

class destructor TMergeSort<T>.Destroy;
begin

  FInstance.Free;

end;

class function TMergeSort<T>.Instance: TSortAlgorithm<T>;
begin

  if FInstance = nil then
  begin
    FInstance := Self.Create;
  end;

  Result := FInstance;

end;

class procedure TMergeSort<T>.Sort(List: TList<T>; const AComparer: IComparer<T>);
var
  WorkArea: array of T;
begin

  SetLength(WorkArea,List.Count);
  try
    InternalSort(List,WorkArea,0,List.Count - 1,AComparer);

  finally
    SetLength(WorkArea,0);
  end;

end;

class procedure TMergeSort<T>.InternalSort(List: TList<T>; var Work: array of T;
                                           Left: Integer; Right: Integer;
                                           const AComparer: IComparer<T>);
var
  Index1: Integer;
  Index2: Integer;
  Index3: Integer;
  Mid: Integer;
begin

  if Left >= Right then
  begin
    Exit;
  end;

  Mid := (Left + Right) div 2;
  InternalSort(List,Work,Left,   Mid,  AComparer);
  InternalSort(List,Work,Mid + 1,Right,AComparer);

  for Index1 := Left to Mid do
  begin
    Work[Index1] := List.Items[Index1];
  end;

  Index2 := Right;
  for Index1 := Mid + 1 to Right do
  begin
    Work[Index1] := List.Items[Index2];
    Index2 := Index2 - 1;
  end;

  Index1 := Left;
  Index2 := Right;
  for Index3 := Left to Right do
  begin
    if AComparer.Compare(Work[Index1],Work[Index2]) > 0 then
    begin
      List.Items[Index3] := Work[Index2];
      Index2 := Index2 - 1;
    end
    else
    begin
      List.Items[Index3] := Work[Index1];
      Index1 := Index1 + 1;
    end;
  end;

end;
シェルソートです。
type
  TShellSort<T> = class(TSortAlgorithm<T>)
  protected
    class var
      FInstance: TSortAlgorithm<T>;
    class procedure  InternalSort(List: TList<T>; Gap: Integer;
                                  const AComparer: IComparer<T>);
  public
    class destructor Destroy;
    class function   Instance: TSortAlgorithm<T>; override;
    class procedure  Sort(List: TList<T>; const AComparer: IComparer<T>); override;
  end;

class destructor TShellSort<T>.Destroy;
begin

  FInstance.Free;

end;

class function TShellSort<T>.Instance: TSortAlgorithm<T>;
begin

  if FInstance = nil then
  begin
    FInstance := Self.Create;
  end;

  Result := FInstance;

end;

class procedure TShellSort<T>.Sort(List: TList<T>; const AComparer: IComparer<T>);
var
  Gap: Integer;
begin

  Gap := List.Count div 2;
  while Gap > 0 do
  begin
    InternalSort(List,Gap,AComparer);

    Gap := Gap div 2;
  end;

end;

class procedure TShellSort<T>.InternalSort(List: TList<T>; Gap: Integer;
                                           const AComparer: IComparer<T>);
var
  Index1: Integer;
  Index2: Integer;
begin

  for Index1 := Gap to List.Count - 1 do
  begin
    Index2 := Index1 - Gap;
    while Index2 >= 0 do
    begin
      if AComparer.Compare(List.Items[Index2 + Gap],List.Items[Index2]) > 0 then
      begin
        Break;
      end;

      List.Exchange(Index2,Index2 + Gap);
      Index2 := Index2 - Gap;
    end;
  end;

end;
Instanceメソッドとクラスデストラクタを毎回書かなければならないことを除けば、ソートのコードを1つ書くだけで値型に対するTList<T>(TList<String>を含む)、クラスに対するTObjectList<T>のどちらであってもソートを行うことができます。

ジェネリックスのリストをアルゴリズムを指定してソートする(Gist)

2017年3月15日

DELPHI / C++BUILDER 0315 IN TOKYO

本日13:30から次期RAD Studio/Delphi/C++Builder(10.2 Tokyo)のお披露目となるDELPHI / C++BUILDER 0315 IN TOKYOが東京ミッドタウン・カンファレンスで行われます。UStreamによる中継も行われます。

レセプションも含め終了しました。参加者、関係者の皆さん、お疲れさまでした。

今日のアバウトなまとめ
  • RAD Studio/Delphi/C++Builderの次期バージョンは"10.2 Tokyo"で、2017/03/28販売開始予定
  • 主な新機能はLinux(Intel x64)サポート(C++Builderは次のアップデートにあたる"10.2.1"でサポート)
  • LinuxサポートはEnt SKU以上が必要(Add-on Packなどは今のところなし)
  • 勉強会やりましょう

Microsoft Monthly Update 2017/03

今日はMicrosoftのセキュリティアップデートの日です。
2017年03月のマイクロソフトセキュリティ情報の概要
MS17-006
MS17-007
MS17-008
MS17-009
MS17-010
MS17-011
MS17-012
MS17-013
MS17-014
MS17-015
MS17-016
MS17-017
MS17-018
MS17-019
MS17-020
MS17-021
MS17-022
MS17-023

2017年3月9日

InterBase 2017リリース

InterBase 2017(13.0.0.129)がリリースされています。現時点(2017/03/09)でDeveloper EditionとServer Edition(トライアル版)のみダウンロード可能です。ODSは17になっています。

30748 InterBase 2017 Server Ed., Windows/Linux (13.0.0.129, Japanese)
30749 InterBase 2017 Server Ed., Windows/Linux (13.0.0.129, English)
30736 InterBase 2017 (13.0.0.129) Developer Edition, Japanese
30738 InterBase 2017 (13.0.0.129) Developer Edition, English

30756 InterBase 2017 ToGo Ed., Windows/Linux/macOS/iOS/Android

Readme - InterBase (en)
InterBase 2017 の新機能 - InterBase(en)

InterBase 2017 - Now available • DelphiABall

2017/03/10追記: Server Editionもダウンロードできるようになっています。

2017/03/24追記: ToGo Editionもダウンロードできるようになっています。

2017年3月7日

Adobe Reader(X以降)で指定したファイルの指定したページを開く

以前Adobe Acrobat/Readerで指定したPDFファイルの指定したページを開く方法について書きましたが、コメントでおかぽんさんからAdobe Reader X以降ではこの方法が使えなくなっているとの指摘をいただきました。

...DDEを使った方法ですが、Acrobat X から、DDEのサービス名が変更されています。...
調べてみると、Actobat/ReaderのVersion 10(X)以降で、DDEのサービス名が Acroview + [A|R] + <MajorVersion> に変更されたことが原因とのことです。というわけでこれに対応してみました。
uses
{$IF RTLVersion >= 23.00}
  Winapi.Windows, System.SysUtils, System.Win.Registry, System.AnsiStrings,
  Vcl.DdeMan;
{$ELSE}
  Windows, SysUtils, Registry, {$IFDEF UNICODE}AnsiStrings, {$ENDIF}DdeMan;
{$IFEND}

function GetAcrobatPathname: String;
begin

  with TRegistry.Create do
  begin
    try
      RootKey := HKEY_CLASSES_ROOT;
      OpenKeyReadOnly('Software\Adobe\Acrobat\Exe');
      try
        Result := AnsiDequotedStr(ReadString(''),'"');

      finally
        CloseKey;
      end;

    finally
      Free;
    end;
  end;

end;

procedure OpenPDF(const Filename: String; Page: Integer);
const
  CDdeCommand: AnsiString = '[DocOpen("%s")][DocGoTo(NULL,%d)]';
var
  Macro: AnsiString;
  Pathname: String;
  ServiceName: String;
  MajorVersion: Integer;
  AcrobatType: String;
begin

  Macro := {$IFDEF UNICODE}{$IF RTLVersion >= 23.00}System.{$IFEND}AnsiStrings.{$ENDIF}
           Format(CDdeCommand,[Filename,Page - 1]);

  Pathname := GetAcrobatPathname;

  ServiceName := 'Acroview';
  MajorVersion := GetFileVersion(Pathname) shr 16;
  if MajorVersion >= 10 then
  begin
    if CompareText(ExtractFileName(Pathname),'AcroRd32.exe') = 0 then
    begin
      AcrobatType := 'R';
    end
    else
    begin
      AcrobatType := 'A';
    end;

    ServiceName := ServiceName + Format('%s%d',[AcrobatType,MajorVersion]);
  end;

  with TDdeClientConv.Create(nil) do
  begin
    try
      ConnectMode := ddeManual;
      ServiceApplication := ChangeFileExt(Pathname,'');
      SetLink(ServiceName,'Control');
      if (OpenLink or ((MajorVersion >= 15) and OpenLink)) = True then
      begin
        ExecuteMacro(PAnsiChar(Macro),False);
        CloseLink;
      end;

    finally
      Free;
    end;
  end;

end;
Acrobat/Readerの実行ファイルの場所をレジストリの"HKEY_CLASSES_ROOT\Software\Adobe\Acrobat\Exe"から取得し、SysUtils.GetFileVersionで問い合わせたバージョン情報の上位16ビット(メジャーバージョン)とファイル名からサービス名を組み立て、DDEをTDdeClientConv.OpenLinkで呼び出してTDdeClientConv.ExecuteMacroでマクロ実行することでファイルを開きページを移動する、という手順になります。またAcrobat/Reader DCの場合TDdeClientConv.OpenLinkの内部でWinExec(en)を使用して起動した直後にDdeConnect(en)を呼び出すと失敗するようなので、リトライするようにしています。

おかぽんさん、情報ありがとうございました。

Adobe Reader(X以降)で指定したファイルの指定したページを開く(Gist)

2017年3月5日

[ebook]Dependency Injection In Delphi

Leanpub

Dependency Injection In Delphi/Nick Hodges著/Leanpub/ISBN978-1-941266-19-9/29.99USD

を購入(PDF/EPUB/MOBIをダウンロード可能)。

2017年3月1日

2017年2月24日

[書籍]Optimized C++

紀伊國屋書店新宿本店Optimized C++ (amazon US)の翻訳である

Optimized C++ (amazon)/Kurt Guntheroth著/黒川利明訳/島敏博技術監修/オライリージャパン/4,320円/ISBN978-4-87311-792-8

を購入。

2017年2月22日

Microsoft OOB Update 2017/02

Microsoftの定例外のセキュリティアップデートがリリースされています。
MS17-005

2017年2月18日

2017年2月15日

Microsoft Monthly Update 2017/02 is canceled

今日はMicrosoftのセキュリティアップデートの日、の予定だったのですが、

we discovered a last minute issue that could impact some customers and was not resolved in time for our planned updates today.
After considering all options, we made the decision to delay this month’s updates.


とのことで、更新プログラムのリリースは延期になっています。この後のリリーススケジュールは現時点(2017/02/15)で未定とのことです。

2017/02/16追記: 2017/02のセキュリティ更新プログラムはキャンセルとなった模様です。

3 月の月例セキュリティ更新プログラム公開 (2017 年 3 月 14 日 (米国日付)) の一部として更新プログラムを配信する予定です。

Adobe Flash Playerには既知のセキュリティホールが存在していますので、Windows 8.1/10、Windows Server 2012/2012R2/2016、Windows RT 8.1上のInternet ExplorerおよびEdgeではFlash Playerを無効化するか、代替のwebブラウザを使用することを強くお勧めします。

2017/02/22追記: IE/EdgeのAdobe Flash Playerの更新プログラムがリリースされています。

Adobe Flash Player の脆弱性を修正するセキュリティ更新プログラムを定例外で公開 – 日本のセキュリティチーム
マイクロソフト セキュリティ情報 MS17-005 - 緊急 Adobe Flash Player のセキュリティ更新プログラム (4010250)

2017年2月1日

[書籍]なっとく!アルゴリズム

紀伊國屋書店新宿本店Grokking Algorithms (amazon US)の翻訳である

なっとく!アルゴリズム (amazon)/Aditya Bhargava著/株式会社クイープ監訳/翔泳社/ISBN 9784798143354/2,700円

を購入。

[書籍]プログラミング作法

紀伊國屋書店新宿本店The Practice of Programming (amazon US)の翻訳である

プログラミング作法 (amazon)/Brian W. KernighanRob Pike著/福崎俊博訳/KADOKAWA/ISBN 978-4-04-893052-9/3,024円

を購入。

2017/02開催のセミナー

2017年1月12日

RAD Studio/Delphi/C++Builder 10.1 Berlin Hotfix 11 Jan 2017

RAD Studio 10.1 BerlinのHotfixがリリースされています。macOS 10.12 Sierra上でのデプロイ/デバッグの問題(RSP-16322)、macOS 10.12 Sierra上のiOS Simulatorでの実行/デバッグの問題(RSP-16368)、iOS 10上での32ビットアプリケーションのデバッグの問題(RSP-16324)を修正するものです。

30680 RAD Studio 10.1 Berlin Hotfix: 11 Jan 2017

Debugger Hotfix for macOS Sierra and the iOS Simulator
macOS Sierra および iOS Simulator 向けの Debugger Hotfix がリリースされました [JAPAN]

2017年1月11日

2016年12月26日

[書籍]アルゴリズムクイックリファレンス 第2版

啓文堂書店 渋谷店Algorithms in a Nutshell, 2nd Edition (amazon US)の翻訳である

アルゴリズムクイックリファレンス 第2版 (amazon)/George T. HeinemanGary Pollice、Stanley Selkow著/黒川利明、黒川洋訳/オライリージャパン/ISBN978-4-87311-785-0/3,888円

を購入。

2016年12月21日

RAD Studio/Delphi/C++Builder 10.1 Berlin Debugger Hotfix for iOS

RAD Studio 10.1 BerlinのHotfixがリリースされています。iOS 10上でiOS 32ビットアプリケーションをデバッグするときの問題を修正するもののようです。

30673 Debugger Hotfix for 10.1 Berlin for iOS 32-bit debugging

2017/01/12追記: このhotfix(30673)は新しいhotfix(30680 RAD Studio 10.1 Berlin Hotfix: 11 Jan 2017)に含まれているため、30680のhotfixのみを適用すればOKです。

2016年12月18日

[書籍]やさしく学べるMySQL運用・管理入門

紀伊國屋書店新宿本店

やさしく学べるMySQL運用・管理入門 (amazon)/山崎由章、梶山隆輔著/インプレス/ISBN9784295000198/2,808円

を購入。

2016年12月9日

第33回エンバカデロ・デベロッパーキャンプ

本日10:00から第33回エンバカデロ・デベロッパーキャンプEBiS 303カンファレンススペースで行われます。今回もUStreamによるライブ中継が行われます。

2016年12月1日

2016/12開催のセミナー

2016年11月24日

RAD Studio/Delphi/C++Builder 10 Seattle November 2016 Update

RAD Studio/Delphi/C++Builder 10 SeattleのNovember 2016 Updateがリリースされています。有効なアップデートサブスクリプションが必要です。

30663 November 2016 Seattle Update Subscription Update

Fall 2016 XE8 and 10 Seattle Updates - Embarcadero Community

RAD Studio/Delphi/C++Builder XE8 October 2016 Update

RAD Studio/Delphi/C++Builder XE8のOctober 2016 Updateがリリースされています。有効なアップデートサブスクリプションが必要です。また事前にDecember 2015 Updateを適用しておく必要があります。

30662 October 2016 XE8 Update Subscription Update

Fall 2016 XE8 and 10 Seattle Updates - Embarcadero Community

2016年11月23日

[書籍]Cクイックリファレンス 第2版

ブックファースト新宿店C in a Nutshell, 2nd Edition (amazon US)の翻訳である

Cクイックリファレンス 第2版 (amazon)/Peter Prinz、Tony Crawford著/黒川利明訳/島敏博技術監修/オライリージャパン/ISBN978-4-87311-781-2/4,968円

を購入。

2016年11月16日

[書籍]MVVM in Delphi

Apressで注文した

MVVM in Delphi (amazon US)/John Kouraklis著/Apress/ISBN978-1-4842-2213-3/26.99EUR

が配送されてきました(今回の発送地は日本(大日本印刷が発送代行)、配送は西濃運輸でした)。2016/11/09に注文して7日目の到着、26.99EUR=3,005JPY3,173JPY(暫定、1EUR=111.35JPY1EUR=117.562JPY)でした。

2016年11月9日

2016年11月3日

[書籍]新装版 達人プログラマー

紀伊國屋書店新宿本店The Pragmatic Programmer (amazon US)の翻訳であり、ピアソンエデュケーション版(amazon)の改稿版である

新装版 達人プログラマー (amazon)/Andrew HuntDavid Thomas著/村上雅章訳/オーム社/ISBN978-4-274-21933-7/3,456円

を購入。

2016年11月1日

2016/11開催のセミナー

2016年10月25日

第33回エンバカデロ・デベロッパーキャンプ開催決定

第33回エンバカデロ・デベロッパーキャンプはいつもとは逆順ですが東京と大阪のダブル開催で、2016年12月09日(東京)および2016年12月13日(大阪)に開催されます。

開催概要