Packt Publishingで注文した
Mastering Delphi Programming: A Complete Reference Guide (Amazon US, Amazon JP)/Primož Gabrijelčič著/Packt Publishing/ISBN 9781838989118/44.99USD(printed+ebook)
が配送されてきました(今回の配送もDHLで、インドのチェンナイからの発送でした)。2019/12/16に注文して9日目の到着、44.99USD=5,042JPY(1USD=112.07JPY)でした。
2019年12月24日
2019年12月21日
RAD Studio/Delphi/C++Builder 10.3.3 Rio Android Services Patch
RAD Studio/Delphi/C++Builder 10.3.3 RioのAndroid Services Patchがリリースされています。AAB(Android App Bundle)としてパッケージ化されたアプリケーションでネイティブライブラリをロードできずにAndroidサービスが実行できない問題を修正します。
30905 RAD Studio 10.3.3 Android Services Patch
RAD Studio 10.3.3 Androidサービスパッチ (en)
30905 RAD Studio 10.3.3 Android Services Patch
RAD Studio 10.3.3 Androidサービスパッチ (en)
2019年12月20日
WindowsのNTFSでハードリンクを扱う
このアーティクルはDelphi Advent Calendar 2019の20日目の記事です(1日ぶり6回目)。
Windows上でファイル/ディレクトリに対してリンク(複数のエントリを用意する)する方法にはシンボリックリンク、ジャンクション、ハードリンクがありますが、ここではDelphiからハードリンクを扱います。
ハードリンクはNTFS上のファイル本体に対するディレクトリエントリを複数用意する(あるいはファイル本体に複数のパス名をつける)、というもので、一般のユーザ権限で作れ、NTFS以外にSMB3.0でもサポート(ReFSは不可)されていますが、ディレクトリを扱うことができず、同一ボリューム上にしかリンクを作ることができません。また最大のリンク数が1023に制限されています。
Windowsのシンボリックリンクとジャンクションとハードリンクの違い:Tech TIPS - @IT
普通に(CreateFile関数で)作成したファイルはリンク数が1になっており、ハードリンクを作成する毎にリンク数が増え、逆にハードリンクをDeleteFile関数で削除する毎にリンク数は減っていき、リンク数が0になるとそのファイルの実体も削除されます。
ここではハードリンクの作成と、指定されたファイルのハードリンクの数と一覧の取得をDelphiから行います。以下のコードは(System.)IOUtilsユニットのTPathレコード型や無名メソッドを使っているためにDelphi 2010以降の対応になっていますが、それ以前のバージョンであっても適当に修正すれば動くはずです。
ハードリンクはCreateHardLink関数で作成し、リンク数はGetFileInformationByHandle関数で取得したBY_HANDLE_FILE_INFORMATION構造体のnNumberOfLinksで知ることができます。またハードリンクの一覧はFindFirstFileName関数/FindNextFileName関数/FindClose関数で取得できます。このときFindFirstFilename関数/FindNextFileName関数を一旦LinkName=nilで呼び出して必要なサイズを取得し、ファイル名の格納に必要な領域を確保してからもう一度FindFirstFilename関数/FindNextFileName関数を呼び出しています。
→WindowsのNTFSでハードリンクを扱う(Gist)
Windows上でファイル/ディレクトリに対してリンク(複数のエントリを用意する)する方法にはシンボリックリンク、ジャンクション、ハードリンクがありますが、ここではDelphiからハードリンクを扱います。
ハードリンクはNTFS上のファイル本体に対するディレクトリエントリを複数用意する(あるいはファイル本体に複数のパス名をつける)、というもので、一般のユーザ権限で作れ、NTFS以外にSMB3.0でもサポート(ReFSは不可)されていますが、ディレクトリを扱うことができず、同一ボリューム上にしかリンクを作ることができません。また最大のリンク数が1023に制限されています。
Windowsのシンボリックリンクとジャンクションとハードリンクの違い:Tech TIPS - @IT
普通に(CreateFile関数で)作成したファイルはリンク数が1になっており、ハードリンクを作成する毎にリンク数が増え、逆にハードリンクをDeleteFile関数で削除する毎にリンク数は減っていき、リンク数が0になるとそのファイルの実体も削除されます。
ここではハードリンクの作成と、指定されたファイルのハードリンクの数と一覧の取得をDelphiから行います。以下のコードは(System.)IOUtilsユニットのTPathレコード型や無名メソッドを使っているためにDelphi 2010以降の対応になっていますが、それ以前のバージョンであっても適当に修正すれば動くはずです。
interface
{$IF RTLVersion < 21.0}
{$MESSAGE ERROR 'Delphi 2010 or later is required.'}
{$IFEND}
uses
{$IF RTLVersion < 23.0}
Windows, SysUtils, Classes, IOUtils;
{$ELSE}
Winapi.Windows,
System.SysUtils, System.Classes, System.IOUtils;
{$IFEND}
type
{ THardLink }
THardLink = record
private
class procedure DoGetFileList(const Filename: String; EnumProc: TProc); static;
public
class procedure Create(const LinkFile: String; const SourceFile: String); static;
class function GetFileList(const Filename: String): TArray; overload; static;
class procedure GetFileList(const Filename: String; Strings: TStrings); overload; static;
class function GetNumberOfLinks(const Filename: String): Integer; static;
end;
implementation
{ HANDLE FindFirstFileNameW(LPCWSTR lpFileName, DWORD dwFlags, LPDWORD StringLength, PWSTR LinkName); }
function FindFirstFileNameW(const lpFileName: PWideChar; dwFlags: DWORD; var StringLength: DWORD; LinkName: PWideChar): THandle; stdcall; external kernel32;
{$EXTERNALSYM FindFirstFileNameW}
{ BOOL FindNextFileNameW(HANDLE hFindStream, LPDWORD StringLength, PWSTR LinkName); }
function FindNextFileNameW(hFindStream: THandle; var StringLength: DWORD; LinkName: PWideChar): BOOL; stdcall; external kernel32;
{$EXTERNALSYM FindNextFileNameW}
class procedure THardLink.Create(const LinkFile: String; const SourceFile: String);
begin
if CreateHardLink(PChar(LinkFile),PChar(SourceFile),nil) = False then
begin
RaiseLastOSError;
end;
end;
class function THardLink.GetFileList(const Filename: String): TArray;
var
Files: TArray;
begin
SetLength(Files,0);
DoGetFileList(Filename,
procedure (Filename: String)
begin
{$IF RTLVersion >= 28.0}
Files := Files + [Filename];
{$ELSE}
SetLength(Files,Length(Files) + 1);
Files[Length(Files) - 1] := Filename;
{$IFEND}
end);
Result := Files;
end;
class procedure THardLink.GetFileList(const Filename: String; Strings: TStrings);
begin
Strings.Clear;
DoGetFileList(Filename,
procedure (Filename: String)
begin
Strings.Add(Filename);
end);
end;
class function THardLink.GetNumberOfLinks(const Filename: String): Integer;
var
hFile: THandle;
FileInformation: TByHandleFileInformation;
begin
hFile := CreateFile(PChar(Filename),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if hFile = INVALID_HANDLE_VALUE then
begin
RaiseLastOSError;
end;
try
if GetFileInformationByHandle(hFile,FileInformation) = False then
begin
RaiseLastOSError;
end;
Result := FileInformation.nNumberOfLinks;
finally
CloseHandle(hFile);
end;
end;
class procedure THardLink.DoGetFileList(const Filename: String; EnumProc: TProc);
var
hFindStream: THandle;
Len: DWORD;
Buffer: String;
Root: String;
begin
Root := ExcludeTrailingPathDelimiter(TPath.GetPathRoot(Filename));
{ Retrieve buffer size }
Len := 0;
FindFirstFilenameW(PWideChar(Filename),0,Len,nil);
if GetLastError <> ERROR_MORE_DATA then
begin
RaiseLastOSError;
end;
SetLength(Buffer,Len);
{ Get first filename without drive letter }
hFindStream := FindFirstFilenameW(PWideChar(Filename),0,Len,PWideChar(Buffer));
if hFindStream = INVALID_HANDLE_VALUE then
begin
RaiseLastOSError;
end;
try
while True do
begin
{ Adjust buffer size }
SetLength(Buffer,Len - 1);
{ Callback }
EnumProc(Root + Buffer);
{ Retrieve buffer size }
Len := 0;
FindNextFileNameW(hFindStream,Len,nil);
case GetLastError of
ERROR_HANDLE_EOF:
begin
Break;
end;
ERROR_MORE_DATA:
begin
end;
else
begin
RaiseLastOSError;
end;
end;
{ Get next filename without drive letter }
SetLength(Buffer,Len);
if FindNextFileNameW(hFindStream,Len,PWideChar(Buffer)) = False then
begin
RaiseLastOSError;
end;
end;
finally
{ Close }
{$IF RTLVersion >= 23.0}Winapi.{$IFEND}Windows.FindClose(hFindStream);
end;
end;
ハードリンクはCreateHardLink関数で作成し、リンク数はGetFileInformationByHandle関数で取得したBY_HANDLE_FILE_INFORMATION構造体のnNumberOfLinksで知ることができます。またハードリンクの一覧はFindFirstFileName関数/FindNextFileName関数/FindClose関数で取得できます。このときFindFirstFilename関数/FindNextFileName関数を一旦LinkName=nilで呼び出して必要なサイズを取得し、ファイル名の格納に必要な領域を確保してからもう一度FindFirstFilename関数/FindNextFileName関数を呼び出しています。
→WindowsのNTFSでハードリンクを扱う(Gist)
2019年12月19日
Windowsのユーザ名とSIDを相互に変換する
このアーティクルはDelphi Advent Calendar 2019の19日目の記事です(2年ぶり5回目)。またDelphi Programming Tipsカテゴリの記念すべき(かどうかは微妙)100本目の記事になります。
Windows上のユーザはそれぞれ固有のSID(Security Identifier/セキュリティ識別子)で管理されています。
オブジェクトを識別するSIDとは?:Tech TIPS - @IT
ユーザ名とSIDを相互に変換するにはWin32APIのLookupAccountName関数とLookupAccountSid関数を使用します。ところがこれらの関数でSIDは文字列ではなくSID構造体で扱う必要があります。ということで文字列表現のSIDとSID構造体を相互に変換する必要がありますが、これを行うのがConvertSidToStringSid関数とConvertStringSidToSid関数になります。
それではまずユーザ名をSIDに変換するほうから。
次にSIDをユーザ名に変換します。
使用しているWin32APIのうち、LookupAccountSid関数/LookupAccountName関数はDelphi 2009で、ConvertStringSidToSid関数/ConvertSidToStringSid関数はDelphi XE7で(Win32API.)Windowsユニットに関数宣言が追加されたため、それ以前のバージョンでは明示的に定義が必要です。
→Windows上のユーザ名とSIDを相互変換(Gist)
Windows上のユーザはそれぞれ固有のSID(Security Identifier/セキュリティ識別子)で管理されています。
オブジェクトを識別するSIDとは?:Tech TIPS - @IT
ユーザ名とSIDを相互に変換するにはWin32APIのLookupAccountName関数とLookupAccountSid関数を使用します。ところがこれらの関数でSIDは文字列ではなくSID構造体で扱う必要があります。ということで文字列表現のSIDとSID構造体を相互に変換する必要がありますが、これを行うのがConvertSidToStringSid関数とConvertStringSidToSid関数になります。
それではまずユーザ名をSIDに変換するほうから。
uses
{$IF RTLVersion < 23.0}
Windows, SysUtils;
{$ELSE}
Winapi.Windows, System.SysUtils;
{$IFEND}
{$IF RTLVersion < 28.0}
{ Win32API ConvertSidToStringSid }
{$IFNDEF Unicode}
function ConvertSidToStringSid(Sid: PSID; var StringSid: LPSTR): BOOL; stdcall; external advapi32 name 'ConvertSidToStringSidA';
{$ELSE}
function ConvertSidToStringSid(Sid: PSID; var StringSid: LPWSTR): BOOL; stdcall; external advapi32 name 'ConvertSidToStringSidW';
{$ENDIF}
{$EXTERNALSYM ConvertSidToStringSid}
{$IFEND}
{$IF RTLVersion < 19.0}
{ Win32API LookupAccountName }
{$IFNDEF Unicode}
function LookupAccountName(lpSystemName, lpAccountName: LPCSTR;
Sid: PSID; var cbSid: DWORD; ReferencedDomainName: LPSTR;
var cbReferencedDomainName: DWORD; var peUse: SID_NAME_USE): BOOL; stdcall; external advapi32 name 'LookupAccountNameA';
{$ELSE}
function LookupAccountName(lpSystemName, lpAccountName: LPCWSTR;
Sid: PSID; var cbSid: DWORD; ReferencedDomainName: LPWSTR;
var cbReferencedDomainName: DWORD; var peUse: SID_NAME_USE): BOOL; stdcall; external advapi32 name 'LookupAccountNameW';
{$ENDIF}
{$EXTERNALSYM LookupAccountName}
{$IFEND}
function UsernameToSid(const AUsername: String): String;
var
PSID: Pointer;
SidSize: DWORD;
Domain: String;
DomainLen: DWORD;
SidName: SID_NAME_USE;
SidStr: PChar;
begin
PSID := nil;
SidStr := nil;
try
SidSize := 0;
DomainLen := 0;
LookupAccountName(nil,PChar(AUsername),nil,SidSize,nil,DomainLen,SidName);
if GetLastError <> ERROR_INSUFFICIENT_BUFFER then
begin
RaiseLastOSError;
end;
PSID := Pointer(LocalAlloc(LPTR,SidSize));
SetLength(Domain,DomainLen);
if LookupAccountName(nil,PChar(AUsername),PSID,SidSize,PChar(Domain),DomainLen,SidName) = False then
begin
RaiseLastOSError;
end;
ConvertSidToStringSid(PSID,SidStr);
SetString(Result,SidStr,StrLen(SidStr));
finally
if PSID <> nil then
begin
{$IF RTLVersion >= 32.0}
if LocalFree(PSID) <> nil then
{$ELSE}
{$IFNDEF WIN64}
if LocalFree(DWORD(PSID)) <> 0 then
{$ELSE}
if LocalFree(UInt64(PSID)) <> 0 then
{$ENDIF}
{$IFEND}
begin
RaiseLastOSError;
end;
end;
if SidStr <> nil then
begin
{$IF RTLVersion >= 32.0}
if LocalFree(SidStr) <> nil then
{$ELSE}
{$IFNDEF WIN64}
if LocalFree(DWORD(SidStr)) <> 0 then
{$ELSE}
if LocalFree(UInt64(SidStr)) <> 0 then
{$ENDIF}
{$IFEND}
begin
RaiseLastOSError;
end;
end;
end;
end;
まずLookupAccountName関数でユーザ名に対応するSIDをSID構造体に取得し、これをConvertSidToStringSid関数で文字列に変換します。このときLookupAccountName関数を一旦SID=nil、ReferencedDomainName=nilで呼び出して必要なサイズを取得し、SIDはLocalAlloc関数で、ReferencedDomainNameは(文字列なので)SetLengthで領域を確保して、もう一度LookupAccountName関数を呼ぶようにしているのと、LocalAlloc関数、ConvertSidToStringSid関数で確保された領域はLocalFree関数で解放しなければならない、というところに気をつける必要があります(DelphiのバージョンによってLocalFree関数の宣言に差異があるので$IF RTLVersionと$IFNDEF WIN64で分岐しています)。次にSIDをユーザ名に変換します。
{$IF RTLVersion < 28.0}
{ Win32API ConvertStringSidToSid }
{$IFNDEF Unicode}
function ConvertStringSidToSid(StringSid: LPCSTR; var Sid: PSID): BOOL; stdcall; external advapi32 name 'ConvertStringSidToSidA';
{$ELSE}
function ConvertStringSidToSid(StringSid: LPCWSTR; var Sid: PSID): BOOL; stdcall; external advapi32 name 'ConvertStringSidToSidW';
{$ENDIF}
{$EXTERNALSYM ConvertStringSidToSid}
{$IFEND}
{$IF RTLVersion < 19.0}
{ Win32API LookupAccountSid }
{$IFNDEF Unicode}
function LookupAccountSid(lpSystemName: LPCSTR; Sid: PSID;
Name: LPSTR; var cbName: DWORD; ReferencedDomainName: LPSTR;
var cbReferencedDomainName: DWORD; var peUse: SID_NAME_USE): BOOL; stdcall; external advapi32 name 'LookupAccountSidA';
{$ELSE}
function LookupAccountSid(lpSystemName: LPCWSTR; Sid: PSID;
Name: LPWSTR; var cbName: DWORD; ReferencedDomainName: LPWSTR;
var cbReferencedDomainName: DWORD; var peUse: SID_NAME_USE): BOOL; stdcall; external advapi32 name 'LookupAccountSidW';
{$ENDIF}
{$EXTERNALSYM LookupAccountSid}
{$IFEND}
function SidToUsername(const ASID: String): String;
var
PSID: Pointer;
UserNameLen: DWORD;
Domain: String;
DomainLen: DWORD;
SidName: SID_NAME_USE;
begin
PSID := nil;
try
if ConvertStringSidToSid(PChar(ASID),PSID) = False then
begin
RaiseLastOSError;
end;
UserNameLen := 0;
DomainLen := 0;
LookupAccountSid(nil,PSID,nil,UserNameLen,nil,DomainLen,SidName);
if GetLastError <> ERROR_INSUFFICIENT_BUFFER then
begin
RaiseLastOSError;
end;
SetLength(Result,UserNameLen);
SetLength(Domain,DomainLen);
if LookupAccountSid(nil,PSID,PChar(Result),UserNameLen,PChar(Domain),DomainLen,SidName) = False then
begin
RaiseLastOSError;
end;
SetLength(Result,StrLen(PChar(Result)));
finally
if PSID <> nil then
begin
{$IF RTLVersion >= 32.0}
if LocalFree(PSID) <> nil then
{$ELSE}
{$IFNDEF WIN64}
if LocalFree(DWORD(PSID)) <> 0 then
{$ELSE}
if LocalFree(UInt64(PSID)) <> 0 then
{$ENDIF}
{$IFEND}
begin
RaiseLastOSError;
end;
end;
end;
end;
こちらはまずConvertStringSidToSid関数でSIDの文字列をSID構造体に変換し、LookupAccountSid関数でユーザ名に変換します。こちらもLookupAccountSid関数をName=nil、ReferencedDomainName=nilで呼び出して必要なサイズを取得し、SetLengthで領域を確保してからもう一度LookupAccountSid関数を呼び出しています。またConvertStringSidToSid関数で確保したSID構造体はLocalFree関数で解放します。使用しているWin32APIのうち、LookupAccountSid関数/LookupAccountName関数はDelphi 2009で、ConvertStringSidToSid関数/ConvertSidToStringSid関数はDelphi XE7で(Win32API.)Windowsユニットに関数宣言が追加されたため、それ以前のバージョンでは明示的に定義が必要です。
→Windows上のユーザ名とSIDを相互変換(Gist)
2019年12月14日
RAD Studio/Delphi/C++Builder 10.3.3 Rio Android Debugger Patch
RAD Studio/Delphi/C++Builder 10.3.3 RioのAndroid Debugger Patchがリリースされています。これはAndroid上でのデバッグに関係するいくつかの問題を修正します。
Delphi 10.3.3 Android デバッグパッチ (en)
- [RSP-23698] dsymlink gives abnormal program termination
- [RSP-26704] Debugging 64 bit Android application hangs the IDE
- [RSP-26824] Breakpoints do not work in Android 64 project
- [RSP-26774] Unable to start GDB kernel after switching from debugging 32 to 64 Android
- 内部的に報告された、値の評価、Androidデバイスとの接続、デバッガでアタッチしているときにデバッグ対象のアプリケーションの動作が遅くなる、非常に大きなソースファイルの扱い、スレッドビューからのスレッドの切替、CPUビューでのメモリの表示などの問題
Delphi 10.3.3 Android デバッグパッチ (en)
RAD Studio/Delphi/C++Builder 10.3.3 Rio IDE and VCL Patch
RAD Studio/Delphi/C++Builder 10.3.3 RioのIDE and VCL Patchがリリースされています。これはコード補完ウィンドウのスクロールバーの表示が残ってしまう問題(RSP-26731)とTActionManager/TPopupActionBarコンポーネントを使用しているとコンパイルに失敗する問題(RSP-27035)を修正します。
30903 RAD Studio 10.3.3 IDE and VCL Patch
RAD Studio 10.3.3 IDE/VCLパッチ、ローカリゼーションパッチ (en)
30903 RAD Studio 10.3.3 IDE and VCL Patch
RAD Studio 10.3.3 IDE/VCLパッチ、ローカリゼーションパッチ (en)
2019年12月11日
2019年12月9日
RAD Studio/Delphi/C++Builder 10.3.3 Rio localization patch
RAD Studio/Delphi/C++Builder 10.3.3 Rioのlocalization patchがリリースされています。これはローカライズ(DE/FR/JA)の問題を解決するものです。
30901 RAD Studio 10.3.3 localization patch (DE/FR)
30902 RAD Studio 10.3.3 localization patch (JA)
RAD Studio 10.3.3 IDE/VCLパッチ、ローカリゼーションパッチ (en)
30901 RAD Studio 10.3.3 localization patch (DE/FR)
30902 RAD Studio 10.3.3 localization patch (JA)
RAD Studio 10.3.3 IDE/VCLパッチ、ローカリゼーションパッチ (en)
2019年12月6日
RAD Studio/Delphi/C++Builder 10.3.3 Rio iOS Linking Patch
RAD Studio/Delphi/C++Builder 10.3.3 RioのiOS Linking Patchがリリースされています。これはiOSアプリケーションをDebugビルドでリンクしようとするとエラーになる問題(RSP-23698)を解決するものです。
30900 RAD Studio 10.3.3 iOS Linking Patch
30900 RAD Studio 10.3.3 iOS Linking Patch
2019年12月1日
2019/12開催のセミナー
- Web Seminar
- 2019/12/05 16:00-16:45(JST) Webセミナー「DelphiユーザーのためのSencha入門」 第2回 - 実践編
- Live Seminar
- Community Event
- 2019/12/05 19:00-21:00(JST) 【初心者歓迎】ゆるふぁい#24 - Delphi のゆる~い集まり (東京都千代田区)
登録:
投稿 (Atom)