アプリケーションテザリング解説¶
アプリケーションテザリングとは¶
他のアプリケーションとデータを共有したり、他のアプリケーションを操作したりすることが簡単にできるコンポーネントです。
次のようなアプリケーションを簡単に作成できます。
パワーポイントのスライドをスマートフォンから操作する¶
Windowsパソコンのパワーポイントのスライドを、スマートフォンのアプリケーションから操作するアプリケーション。
アクションを共有する機能を使って、数行のコードを書くだけで作成できます。

さまざまな端末でグループチャット¶
Windows・MAC・iPhone・iPad・Androidスマートフォン・Androidタブレットなど、さまざまな端末で動作するチャットアプリケーションを一つのコードで作成できます。
複数の端末と共有することも簡単にできます。

コンポーネント¶
使用するコンポーネント¶
アプリケーションテザリングでは、次の2つのコンポーネントを使用します。

TTetheringManager
プロファイルの接続の管理を行います。
TTetheringAppProfile
共有する機能や資源の管理を行います。
アプリケーションテザリングの機能¶
アプリケーションテザリングを使用すると、次のことを簡単に実現できます。
- アプリケーションテザリングを使用している他のアプリケーションを検出して接続する
- アクションをリモートで実行する
- データを共有する
アプリケーションテザリングを使用している他のアプリケーションを検出して接続する¶
同一端末または同一LAN上で動作している他のアプリケーションを検出して接続できます。
接続元のアプリケーションも接続先のアプリケーションもIPアドレスやポート番号を意識する必要はありません。 パスワードによる接続の認証も可能です。
TTetheringManagerのAutoConnectメソッドは、検出から接続までのすべての処理を行います。 AutoConnectメソッドを呼び出すだけで、他のアプリケーションに接続できます。
TTetheringManagerのDiscoverManagersは検出だけを行います。 検出されたアプリケーションの中からどのアプリケーションに接続するかはプログラマが記述します。
アクションをリモートで実行する¶
他のアプリケーションのTActionを実行することができます。
この機能を使うことで、次のようなアプリケーションを簡単に作成できます。
- パソコンの動画をスマートフォンから操作する
- パワーポイントのスライドをスマートフォンから操作する
TTetheringAppProfileのActionsプロパティにアクションを設定すると、自動的に共有されます。 共有されたアクションを実行すると、リモートのアプリケーションのアクションを実行することができます。 リモートのアクションを実行するのに、ソースコードの記述は全く必要ありません。
TTetheringAppProfileのRunRemoteActionメソッドにリモートのアプリケーションとアクションの名前を指定して呼び出すと、リモートのアプリケーションのアクションを実行することができます。 プログラムで柔軟に呼び出す先を設定できます。
データを共有する¶
他のアプリケーションにデータを送信したり、データを受信することができます。
この機能を使うことで、次のようなアプリケーションを簡単に作成できます。
- スマートフォンのカメラの映像をパソコンに表示する
- WindowsパソコンのデスクトップをMacに表示する
- スマートフォンのファイルをパソコンに転送する
TTetheringAppProfileのResourcesプロパティにデータを登録すると、データを共有しているアプリケーションに変更の通知と登録されたデータが自動的に送信されます。 また、他のアプリケーションの共有データを要求することもできます。
TTetheringAppProfileのSendStringメソッドやSendStreamメソッドを呼び出すと、リモートのアプリケーションに文字列やバイト列を送信することができます。 プログラムで柔軟に送信先を設定できます。
接続する¶
対応している接続¶
同じ端末または同じローカルネットワーク(LAN)¶
接続できるアプリケーションは、同じ端末上にあるアプリケーションまたは同じローカルネットワーク(LAN)上にあるアプリケーションです。
接続できる台数¶
接続できるアプリケーションは1対1に限りません。複数のアプリケーションに接続することができます。
1対nの接続
1つの端末から複数の端末を操作・送信できます。
たとえば、複数のパソコンをまとめて操作するリモコンアプリケーションを作成できます。
n対1の接続
複数の端末から1つの端末を操作・送信できます。
n対nの接続
複数対複数の接続も可能です。
たとえば、チャットアプリケーションを作成できます。
Delphi XE6/C++Builder XE6では接続できる台数は最大20台までに制限されています。 (ソースコードに定数で設定されています。)
AutoConnectメソッドによる自動接続¶
TTetheringManagerのAutoConnectメソッドを呼び出すと、アプリケーションどうしで互いを自動的に検出し、Groupプロパティの値が同じTTetheringAppProfileをペアにします。

// 接続する
TetheringManager1.AutoConnect();
AutoConnectメソッドは引数にタイムアウトの時間をとることができます。
// 接続する(タイムアウトの時間は3000ミリ秒)
TetheringManager1.AutoConnect(3000);
AutoConnectメソッドの処理が終了すると、OnEndAutoConnectイベントが発生します。
procedure TForm1.TetheringManager1EndAutoConnect(Sender: TObject);
begin
ShowMessage('接続しました。');
end;
DiscoverManagersメソッドによる手動接続¶
TTetheringManagerのDiscoverManagersメソッドを呼び出すと、アプリケーションテザリングを使用している他のアプリケーションの検出をします。
検出が完了すると、このマネージャのOnEndManagersDiscoveryイベントが発生します。
OnEndManagersDiscoveryイベントでは、検出したリモートマネージャのリストを読み取り、TTetheringManager.PairManagerを呼び出して、希望するものとペアにします。
procedure TForm1.TetheringManager1EndManagersDiscovery(const Sender: TObject;
const RemoteManagers: TTetheringManagerInfoList);
var
I: Integer;
begin
for I := 0 to RemoteManagers.Count - 1 do
if RemoteManagers[I].ManagerText = 'MyTetheringManager' then
TetheringManager1.PairManager(RemoteManagers[I]);
end;
ローカルマネージャをリモートマネージャとペアにするたびに、ローカルマネージャのOnEndProfilesDiscoveryイベントが発生します。
OnEndProfilesDiscoveryイベントの引数RemoteProfilesはペアになったリモートマネージャのプロファイルのリストです。 ローカルプロファイルのConnectを呼び出して、希望するものに接続します。
procedure TForm1.TetheringManager1EndProfilesDiscovery(const Sender: TObject;
const RemoteProfiles: TTetheringProfileInfoList);
var
Info: TTetheringProfileInfo;
I: Integer;
begin
for I := 0 to TetheringManager1.RemoteProfiles.Count - 1 do
begin
Info := TetheringManager1.RemoteProfiles[I];
if TetheringAppProfile1.Text = Info.ProfileText then
// リモートプロファイルに接続する
if TetheringAppProfile1.Connect(Info) then
Break;
end;
end;
パスワードで認証する¶
意図しないアプリケーションとの接続を防ぐため、パスワードを使って認証することができます。
リモートマネージャのPasswordプロパティにパスワードが設定されている場合、TTetheringManagerコンポーネントのOnRequestManagerPasswordイベントが発生します。
OnRequestManagerPasswordイベントの引数Passwordにパスワードを代入します。
procedure TForm1.TetheringManager1RequestManagerPassword(const Sender: TObject;
const RemoteIdentifier: string; var Password: string);
begin
Password := '1234';
end;
- 注意点
- 送信されるパスワードは暗号化されていません。
接続状況を知る¶
TTetheringManagerコンポーネントのRemoteProfilesプロパティで接続しているプロファイルのリストを取得できます。
接続しているアプリケーションが終了すると、RemoteProfilesプロパティは自動的に更新されます。
procedure TForm1.CheckRemoteProfiles;
begin
if TetheringManager1.RemoteProfiles.Count > 0 then
begin
// 接続しているときの処理
end
else
begin
// 接続していないときの処理
end;
end;
次のコードはTTimerコンポーネントを使用して、接続状況をラベルに表示します。
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if TetheringManager1.RemoteProfiles.Count > 0 then
begin
LabelConnect.Text := '接続中';
end
else
begin
LabelConnect.Text := '接続していません。';
end;
end;
アクションを共有する¶
TTetheringAppProfileのActionsプロパティ¶
共有するアクションは、TTetheringAppProfileのActionsプロパティに設定します。
TTetheringAppProfileのActionsプロパティ登録するTLocalActionには、次の項目を設定します。
- 実行するTAction(Actionプロパティ)
- アクション名(Nameプロパティ)
- 実行するのはローカルのアクションかリモートのアクションか(Kindプロパティ)
KindプロパティがMirrorであるTLocalActionを実行すると、同じNameプロパティを持つTLocalActionが実行されます。

アクションを実行する¶
ローカルのTActionを実行すると、対応するリモートのアクションが実行されます。
RunRemoteActionを使ってリモートアクションを実行する¶
TTetheringAppProfileコンポーネントのRunRemoteActionメソッドを使うと、リモートアクションを実行することができます。
RunRemoteActionメソッドは引数にリモートアプリケーションプロファイルとアクションの名前をとります。
リモートアプリケーションプロファイルはTTetheringManagerのRemoteProfilesプロパティから取得できます。
function TTetheringAppProfile.RunRemoteAction(
(* リモートアプリケーションプロファイル *)
const AProfile: TTetheringProfileInfo;
(* アクションの名前 *)
const AnActionName: string
): Boolean;
もう一つは引数にTRemoteActionのインスタンスをとります。
TRemoteActionのインスタンスはリモートアプリケーションプロファイルとアクション名から取得できます。
function TTetheringAppProfile.RunRemoteAction(
(* TRemoteActionのインスタンス *)
const AnAction: TRemoteAction
): Boolean;
コード例¶
次のコードは、Groupプロパティが’APP_TEST1’でTextプロパティが’TetheringAppProfile1’であるリモートプロファイルの’ActionAddLine1’アクションを実行します。
var
RemoteProfile: TTetheringProfileInfo;
RemoteActions: TList<TRemoteAction>;
RemoteAction: TRemoteAction;
begin
for RemoteProfile in TetheringManager1.RemoteProfiles do
begin
if (RemoteProfile.ProfileGroup = 'APP_TEST1') and
(RemoteProfile.ProfileText = 'TetheringAppProfile1') then
begin
RemoteActions := TetheringAppProfile1.GetRemoteProfileActions
(RemoteProfile);
if RemoteActions <> nil then
begin
for RemoteAction in RemoteActions do
begin
if RemoteAction.Name = 'ActionAddLine1' then
begin
TetheringAppProfile1.RunRemoteAction(RemoteAction);
end;
end;
end;
end;
end;
end;
データを共有する¶
共有できるデータのデータ型¶
アプリケーションテザリングでは、次のデータ型のデータを共有できます。
- 標準データ型
- Boolean
- Integer
- Int64
- Single
- Double
- String
- TStream
データを共有する方法¶
データを共有する方法には、大きく分けて「一時リソースとして送信する」方法と「リソースを共有する」方法の2種類あります。
一時リソースとして送信する
リソースを共有する
「リソースを共有する」方法では、データを接続先に送信する方法と、接続先のデータを要求する方法の2種類があります。
ローカルリソースの変更を通知して送信する
リモートリソースを要求する
一時リソースとして送信する¶
TTetheringAppProfileコンポーネントのSendStringメソッドやSendStreamメソッドを使用して、文字列やストリームを接続されたアプリケーションに送信することができます。
受信すると、TTetheringAppProfileコンポーネントのOnResourceReceivedイベントが発生します。

一時リソースの文字列を送信するコード¶
TTetheringAppProfileのSendStringメソッドを呼び出すと文字列を送信することができます。 引数には送信先のプロファイル・ヒント文字列・送信文字列を指定します。
var
RemoteProfile: TTetheringProfileInfo;
begin
for RemoteProfile in TetheringManager1.RemoteProfiles do
begin
if (RemoteProfile.ProfileGroup = 'APP_TEST1') and
(RemoteProfile.ProfileText = 'TetheringAppProfile2') then
begin
// 文字列を送信する
TetheringAppProfile1.SendString(RemoteProfile,
'送信テスト', //受信側はAResource.Hintで取得する
'送信文字列' //受信側はAResource.Value.AsStringで取得する
);
Exit;
end;
end;
end;
ストリームを送信する場合はTTetheringAppProfileのSendStreamメソッドを呼び出します。 引数には送信先のプロファイル・ヒント文字列・送信するTStreamを指定します。
一時リソースの文字列を受信するコード¶
文字列やストリームが送信されると、TTetheringAppProfileのOnResourceReceivedイベントが発生します。
procedure TForm1.TetheringAppProfile1ResourceReceived(const Sender: TObject;
const AResource: TRemoteResource);
begin
…
end;
引数のAResourceのHintプロパティに送信されたヒント文字列が、Valueプロパティに送信されたデータが格納されています。
AResourceはResTypeプロパティで、送信されたデータが基本型とストリームのどちらかであるかを取得できます。
送信されたデータが基本型の場合は、ValueプロパティはDataTypeプロパティで送信されたデータの型を取得できます。 AsXXXメソッドを呼び出して指定した型でデータを受け取ることができます。
case AResource.Value.DataType of
TResourceType.Integer:
S := IntToStr(AResource.Value.AsInteger);
TResourceType.Single:
S := FloatToStr(AResource.Value.AsSingle);
TResourceType.Double:
S := FloatToStr(AResource.Value.AsDouble);
TResourceType.Int64:
S := IntToStr(AResource.Value.AsInt64);
TResourceType.Boolean:
S := BoolToStr(AResource.Value.AsBoolean);
TResourceType.String:
S := AResource.Value.AsString;
end;
送信されたデータがストリームの場合は、ValueプロパティのAsStreamプロパティでストリームを取得できます。
procedure TForm1.TetheringAppProfile1Resources1ResourceReceived
(const Sender: TObject; const AResource: TRemoteResource);
begin
Image1.Bitmap.LoadFromStream(AResource.Value.AsStream);
end;
次のコードでは送信された文字列をメモコンポーネントに出力します。 送信されたデータが文字列であることがわかっているため、データ型の識別はしていません。
procedure TForm1.TetheringAppProfile1ResourceReceived(const Sender: TObject;
const AResource: TRemoteResource);
begin
TThread.Synchronize(nil,procedure
begin
Memo1.Lines.Add(AResource.Hint); //=> '送信テスト'
Memo1.Lines.Add(AResource.Value.AsString); //=> '送信文字列'
end);
end;
リソースを共有する¶
リソースを共有するには、共有するリソースを定義します。
共有リソースにデータを登録すると、アプリケーションに共有リソースの変更が通知され、登録されたデータが送信されます。
また、共有リソースに登録されているデータを要求することもできます。
共有リソースを定義する¶
TTetheringAppProfileのResourcesプロパティに、共有するリソース(TLocalResource)を追加します。

Kindプロパティ
送信側か受信側かを指定します。
送信側のときは「Shared」、受信側の時は「Mirror」を指定します。
Nameプロパティ
送信側・受信側ともに同じ名前をつけます。
ResTypeプロパティ
送受信するデータ型を指定します。
標準データ型のときは「Data」、TStreamのときは「Stream」を指定します。

データを送信する¶
データを送信するには、TTetheringAppProfileのResourcesプロパティに定義したTLocalResourceのValueプロパティに、送信するデータを設定します。
データを登録すると、リモートのTLocalResourceに変更が通知されOnResourceReceivedイベントが呼び出されます。
TLocalResourceのValueプロパティに設定したデータは、リモート側からの要求によって送信することもできます。
基本データ型を送信する¶
ResourcesプロパティのFindByNameメソッドでTLocalResourceを取得して、Valueプロパティに送信するデータを設定します。
FindByNameメソッドは引数にリソースのNameプロパティを指定します。
TetheringAppProfile1.Resources.FindByName('SharedText').Value := '送信テスト';
TStreamを送信する¶
基本データ型を送信するるときと同様に、ResourcesプロパティのFindByNameメソッドでTLocalResourceを取得して、Valueプロパティに送信するデータを設定します。
登録したストリームは、登録後に解放してはいけません。保持し続ける必要があります。
次のコードでは登録するストリーム(FStream)はメンバ変数になっています。
begin
if FStream <> nil then
FStream.Free;
FStream:= TMemoryStream.Create;
FStream.LoadFromFile('C:\test\home_256_h.png');
FStream.Position := 0;
TetheringAppProfile1.Resources.FindByName('SharedImage').Value := FStream;
end;
データを受信する¶
送信側のTLocalResourcesのValueプロパティが変更されると、TTetheringAppProfileコンポーネントのOnAcceptResourceイベントが発生します。 受信したくない場合はOnAcceptResourceイベントで受信を拒否できます。
受信を受け入れた場合はOnResourceReceivedイベントが発生します。 このイベントの中で受信したデータを処理します。

受信を受け入れる¶
受信を拒否するときはOnAcceptResourceイベントの引数AcceptResourceにFalseを設定します。 OnAcceptResourceイベントを実装しない場合は自動的に受信します。
procedure TForm1.TetheringAppProfile1AcceptResource(const Sender: TObject;
const AProfileId: string; const AResource: TCustomRemoteItem;
var AcceptResource: Boolean);
begin
// Falseにすると受信しない
AcceptResource := False;
end;
受信するとTLocalResourcesのOnResourceReceivedイベントが発生します。
基本型のデータを受信する¶
TResourceValueのDataTypeプロパティで送信されたデータのデータ型を取得します。
case AResource.Value.DataType of
…
データ型に応じて、AsInteger、AsSingle、AsDouble、AsInt64、AsBoolean、AsStringプロパティを使用してデータを取得します。
procedure TForm1.TetheringAppProfile1Resources0ResourceReceived
(const Sender: TObject; const AResource: TRemoteResource);
var
S: string;
begin
case AResource.Value.DataType of
TResourceType.Integer:
S := IntToStr(AResource.Value.AsInteger);
TResourceType.Single:
S := FloatToStr(AResource.Value.AsSingle);
TResourceType.Double:
S := FloatToStr(AResource.Value.AsDouble);
TResourceType.Int64:
S := IntToStr(AResource.Value.AsInt64);
TResourceType.Boolean:
S := BoolToStr(AResource.Value.AsBoolean);
TResourceType.String:
S := AResource.Value.AsString;
end;
…
end;
Streamを受信する例¶
StreamはAsStreamプロパティで取得します。
procedure TForm1.TetheringAppProfile1Resources1ResourceReceived
(const Sender: TObject; const AResource: TRemoteResource);
begin
TThread.Synchronize(nil,procedure
begin
Image1.Bitmap.LoadFromStream(AResource.Value.AsStream);
end);
end;
リモートリソースを要求する¶
TTetheringAppProfileコンポーネントのGetRemoteResourceValueメソッドを使用して、リモートリソースを要求することができます。
GetRemoteResourceValueメソッドは、引数にリモートリソースを含んだリモートアプリケーションプロファイルとリモートリソースの名前、またはリモートリソースのインスタンスをとります。
function TTetheringAppProfile.GetRemoteResourceValue(
(* リモートリソースを含んだリモートアプリケーションプロファイル *)
const AProfile: TTetheringProfileInfo;
(* リモートリソースの名前 *)
const ARemoteResName: string
): TRemoteResource;
function TTetheringAppProfile.GetRemoteResourceValue(
(* リモートリソースのインスタンス *)
const ARemoteRes: TRemoteResource
): TRemoteResource;
次のコードでは、Textプロパティが’TetheringAppProfile1’であるTTetheringProfileを検索して、Nameプロパティが’RequiredText’であるリモートリソースにデータを要求します。
procedure TForm1.ButtonRequiredTextClick(Sender: TObject);
var
AProfile: TTetheringProfileInfo;
AResources: TList<TRemoteResource>;
AResource, RemoteResource: TRemoteResource;
begin
// リモートリソースを探す
for AProfile in TetheringManager1.RemoteProfiles do
begin
if AProfile.ProfileText = 'TetheringAppProfile1' then
begin
AResources := TetheringAppProfile1.GetRemoteProfileResources(AProfile);
if AResources <> nil then
begin
for AResource in AResources do
begin
if AResource.Name = 'RequiredText' then
begin
// リモートリソースを要求する
RemoteResource := TetheringAppProfile1.GetRemoteResourceValue(AResource);
Memo1.Lines.Add(RemoteResource.Value.AsString);
Exit;
end;
end;
end;
end;
end;
end;