このドキュメントでは、次のトピックについて説明します。
クリップボードおよびドラッグ/ドロップのデータ転送には、同じメソッドのセットで両方の要件を扱うことができる、Natural 言語レベルの論理的なクリップボードを利用します。 論理クリップボードを扱うための PROCESS GUI
アクションは、OPEN-CLIPBOARD
、SET-CLIPBOARD-DATA
、CLOSE-CLIPBOARD
、GET-CLIPBOARD-DATA
、および INQ-FORMAT-AVAILABLE
です。 各 Natural プロセスには 1 つずつ論理クリップボードがあります。そのため、製品ドキュメントでは "ローカル" クリップボードと呼ばれています。
OPEN-CLIPBOARD
は、論理クリップボードデータを構築するための最初の手順です。 OPEN-CLIPBOARD は、通常はデータを供給するコントロールのハンドルである、オプションパラメータ(オーナーウィンドウ)を使用します。 すでに何かが論理クリップボードにあれば、このアクションはそれを空にします。
Natural は、BEGIN-DRAG
イベント(下記参照)を起動する前に暗黙的にこの処理を行うので、ドラッグ & ドロップのためにこのアクションを呼び出す必要がないことに注意してください。
SET-CLIPBOARD-DATA
は、実際のデータを論理クリップボードに転送します。 最初のパラメータは、文字列として指定するクリップボードフォーマットです。 このフォーマットには、標準的なテキスト転送に使われる 2 つの事前定義フォーマット(CF-TEXT および CF-FILELIST
として NGULKEY1 に定義)とそれぞれに対応するファイルリスト(Windows エクスプローラやその他の多くのアプリケーションとのデータ交換に適切)があります。 また、任意の文字列(dgit で始まっていてはならない)を使用して、Natural
アプリケーションだけが理解できるプライベートクリップボードフォーマットを指定できます(データを取得するためにこのフォーマット文字列を GET-CLIPBOARD-DATA
に渡せるように、アプリケーションでは単にこの文字列を識別する必要があります)。 2 番目以降の引数は任意の数のデータオペランドです。 これらには、配列(添字範囲を含む)またはスカラ(ダイナミック変数およびラージ文字変数を含む)の任意の組み合わせを指定できます。
配列は個々の要素に内部的に展開され、その後、スカラが個別に処理されます。
例:
DEFINE DATA LOCAL 1 #ARR(A1/2,3) INIT (1,1)<'A'> (1,2)<'B'> (1,3)<'C'> (2,1)<'X'> (2,2)<'Y'> (2,3)<'Z'> END-DEFINE PROCESS GUI ACTION SET-CLIPBOARD-DATA WITH CF-TEXT #ARR(*,*)
上記のコーディングと下記のコーディングは同等です。
PROCESS GUI ACTION SET-CLIPBOARD-DATA WITH CF-TEXT 'A' 'B' 'C' 'X' 'Y' 'Z'
事前定義フォーマットの場合、オペランドは英数字(フォーマット A)である必要があります。 プライベートフォーマットの場合、ほぼすべてのタイプのデータ引数を指定できます。 例外:ハンドル変数(HANDLE OF OBJECT
を含む)はプロセス固有なので、サポートされません。 プライベートフォーマットのデータは "現状のまま"(変換なし)で保存されます。
必要なフォーマットごとに SET-CLIPBOARD-DATA
アクションを実行することにより、複数のデータフォーマットをクリップボードに転送できることに注意してください。 ただし、特定のフォーマットに対して SET-CLIPBOARD-DATA
を呼び出すと、すでにそのフォーマットで存在するデータはすべて置き換えられます。
データは Windows クリップボードには転送されないことにも注意してください。 これは論理クリップボードが閉じられるときに(下記参照)行われます。
CLOSE-CLIPBOARD
は、論理クリップボードを閉じて Windows クリップボードにデータを転送し、他のアプリケーションで貼り付けできるようにします。 CLOSE-CLIPBOARD を呼び出した後は、SET-CLIPBOARD-DATA
でデータを変更できません。 通常はドラッグしたデータを貼り付けできるようにする必要はないため、この呼び出しはドラッグ & ドロップでは必須ではないことに注意してください。 ドラッグ & ドロップは論理クリップボードで直接操作できます。
GET-CLIPBOARD-DATA
は、貼り付けを実行したり、ドロップターゲットとして動作したりするアプリケーションによって、ドラッグ & ドロップ操作中の場合はドラッグドロップクリップボードから、そうでない場合は Windows クリップボードからデータを取得するために使用されます。
ドラッグドロップクリップボードは、ソース Natural プロセスに属している論理クリップボードの同義語です。 SET-CLIPBOARD-DATA
では、クリップボードフォーマットを指定し、その後に(同じフォーマットタイプ制限の)任意のデータオペランドリストを続けます。 プライベートフォーマットの場合、オペランドは GET-CLIPBOARD-DATA
アクションで使用するのと同じフォーマットタイプである必要はありません。 例えば、クリップボードに整数を転送し、それをパック型数値(P)変数に読み込むことができます。 内部的に、MOVE
変換が行われます。 したがって、データの設定と取得に異なるフォーマットタイプを使用する場合、それらのフォーマットには MOVE
での互換性が必要です。
事前定義フォーマットの場合、個々のデータ項目は CR/LF(CF-TEXT フォーマットの場合)または NULL 終端文字(CF-FILELIST フォーマットの場合)のいずれかで区切られ、通常は受け取りフィールドごとに 1 つの項目のみが読み込まれます。
例外:最後の受け取りフィールドがダイナミック文字変数の場合、デリミタを含めて、残りのすべてのデータ項目がこの変数に格納されます。 この例外により、アプリケーションでは、(例えば)単一のダイナミック文字変数を使用して、複数行のデータまたは複数のファイル/ディレクトリ名を設定および取得できます。
使用するフォーマットに関係なく、指定された受け取りオペランドが多すぎる場合、余ったフィールドはリセットされます(RESET
ステートメントを参照)。 個々のデータフィールドは、nX
表記を使用するとスキップされることに注意してください。 例えば、5x
は 5 個のデータ項目をスキップします("データ項目" が CF-TEXT フォーマットに対する単一行の場合)。
INQ-FORMAT-AVAILABLE
は、指定したフォーマットでデータを使用できるかどうかをクエリするために使用します(構文の仕様を参照)。 通常、このアクションは、 コマンドを有効または無効にするか、あるいはドラッグ/ドロップ操作に対して "ドロップ禁止" カーソルを表示するかどうかを判断するために使用します。
実際のクリップボードデータ転送については、上記の説明を参照してください。 ただし、Natural では、(他の通常のコマンドと異なり)CLICK
イベントが発生しない特殊タイプの 、 、 、 、および のシグナル、メニュー項目、およびツールバー項目を定義できます。 入力フィールド、編集エリア、選択ボックス、およびテーブルコントロールに対して Natural が実行する必要がある処理は明確であるため、Natural は暗黙的にこれを実行します。
Natural では、これらのコマンドはリストボックスおよび ActiveX コントロールをサポートしています。 ただし、Natural がこれらのコマンドにどのように応答する必要があるかについてはあいまいであるため、この場合はメカニズムが異なります。
したがって、Natural では、アプリケーションからある程度の支援を受ける必要があります。 この支援は、6 個の新規イベント(CUT
、COPY
、PASTE
、DELETE
、UNDO
、および CLIPBOARD-STATUS
)の形を取ります。これらのイベントはすべて、新規属性 SUPPRESS-CUT-EVENT
、SUPPRESS-COPY-EVENT
、SUPPRESS-PASTE-EVENT
、SUPPRESS-DELETE-EVENT
、SUPPRESS-UNDO-EVENT
、および SUPPRESS-CLIPBOARD-STATUS-EVENT
によって抑制できます。 これらの 6 個のイベントはすべて、デフォルトで抑制されています。 CUT
、COPY
、PASTE
、DELETE
、および UNDO
の各イベントは、対応するコマンドが起動されると発生します。 対応するイベント抑制フラグは、ユーザーインターフェイスの対応するコマンド(複数可)を有効と無効のどちらにするかを判断するために、Natural によって使用されます。
CLIPBOARD-STATUS
イベントは、コンテキスト(例えば、アクティブな選択があるかどうか)に従って、アプリケーションでダイナミックにこれらのイベント抑制フラグを設定できるようにするために、アイドル処理中にフォーカスコントロールに送られます。 Natural では、クリップボードコマンドのステータスを更新するためにイベント抑制フラグをクエリする前に、このイベントが発生します。
これらの新規イベントは、(現時点では)リストボックスと ActiveX コントロールにのみ送られることに注意してください(これらのコントロールにフォーカスがある場合のみ)。 入力フィールドや選択ボックスなどは、現在でも暗黙的に処理されます。
CLIPBOARD-STATUS
イベントは、更新する必要があるクリップボードコマンドがユーザーインターフェイスに少なくとも 1 つある場合にのみ、発生します。
以下の例は、リストボックスコントロールの典型的な CLIPBOARD-STATUS
イベントを示しています。
DEFINE DATA LOCAL 1 #CONTROL HANDLE OF GUI 1 #FMT (A10) CONST<'MYDATAFMT'> 1 #AVAIL (L) END-DEFINE ... #CONTROL := *CONTROL /* /* Cut, Copy & Delete are enabled if an item is selected, /*or disabled otherwise /* IF #CONTROL.SELECTED-SUCCESSOR <> NULL-HANDLE #CONTROL.SUPPRESS-CUT-EVENT := NOT-SUPPRESSED #CONTROL.SUPPRESS-COPY-EVENT := NOT-SUPPRESSED #CONTROL.SUPPRESS-DELETE-EVENT := NOT-SUPPRESSEDELSE #CONTROL.SUPPRESS-CUT-EVENT := SUPPRESSED #CONTROL.SUPPRESS-COPY-EVENT := SUPPRESSED #CONTROL.SUPPRESS-DELETE-EVENT := SUPPRESSED END-IF /* /* Paste command is enabled if data is available in a /* recognized format, or disabled otherwise /* PROCESS GUI ACTION INQ-FORMAT-AVAILABLE WITH #FMT #AVAIL GIVING *ERROR /* IF #BOOL #CONTROL.SUPPRESS-PASTE-EVENT := NOT-SUPPRESSED ELSE #CONTROL.SUPPRESS-PASTE-EVENT := SUPPRESSED END-IF
ドラッグ & ドロップ操作は、自動的に(リストボックスおよびビットマップコントロールの場合)または手動で、新規 PERFORM-DRAG-DROP
アクション経由で(ActiveX コントロールの場合は通常、コントロール固有のマウスクリックまたはドラッグ開始イベントに応答して)起動できます。 自動的なドラッグ/ドロップでは、マウスカーソルはアクティブな選択(存在する場合)の上にある必要があります。
手動のドラッグ/ドロップでは、PERFORM-DRAG-DROP
のパラメータに、ドラッグ/ドロップイベントを受け取るコントロール(ドラッグソース)のハンドル、およびドラッグ & ドロップをすぐに始めるのか、またはユーザーがシステム定義の最小ピクセル数だけマウスを移動した後にのみ始めるのかを示すオプションフラグを指定します。
自動および手動のドラッグ/ドロップでは内部的に同じコードが使用されているので、いずれの場合も同じイベントを受け取ります。
ドラッグ/ドロップは、DRAG-MODE
(ドラッグソース用)と DROP-MODE
(ドロップターゲット用)の 2 つの新規 I4 属性によって制御されます。 これらの属性は、DM-NONE
(ドラッグ/ドロップ不可)、DM-COPY
(コピー可能)、DM-MOVE
(移動可能)、DM-COPYMOVE
(コピーと移動可能)、DM-LINK
(リンク可能)、DM-COPYLINK
(コピーとリンク可能)、DM-MOVELINK
(移動とリンク可能)、DM-COPYMOVELINK
(コピー、移動、リンク可能)の 8 個の値のいずれかに設定できます(NGULKEY1 に定義)。 リンク操作は、ドロップターゲットによってソースデータのコピーが作成されるのではなく、ソースデータへのリンクが作成されることを暗黙的に意味します。
ファイル操作については、通常はデスクトップショートカットが使用されます(現時点では Natural によって明示的にはサポートされていません)。 ソースの DRAG-MODE
属性がデフォルト値の DM-NONE
以外の値に設定されている場合にのみ、ドラッグ操作は開始されます。 また、アプリケーションは BEGIN-DRAG
イベント(下記参照)に応答する必要があります。
ドロップターゲットとして動作できるコントロールタイプには、ActiveX コントロール、ビットマップコントロール、リストボックス、コントロールボックス、編集エリア、およびダイアログがあります(タブコントロールとテーブルコントロールは将来的に対応が予定されていますが、現在はサポートされていません)。
ただし、DROP-MODE
属性がデフォルトの DM-NONE
以外の値に設定されている場合、これらのウィンドウはドロップターゲットとして OLE に登録されるだけです。 ドラッグ/ドロップ操作中、OLE は、ドロップターゲットとして登録されたウィンドウが見つかるまで、カーソルの真下にあるウィンドウから順に、ウィンドウ階層を上へ自動的に検索します。
このウィンドウが、OLE ドロップ通知を受け取るウィンドウになります。したがって、Natural ドラッグ/ドロップイベント(下記参照)を受け取るウィンドウでもあります。
新規ドラッグ/ドロップ関連イベントには、BEGIN-DRAG
、END-DRAG
、DRAG-ENTER
、DRAG-OVER
、および DRAG-LEAVE
があります。 また、既存の DRAG-DROP
イベント(ビットマップコントロールに対する簡単な非 OLE ドラッグ/ドロップサポート)も使用されます。 すべてのイベントは、適切なイベント抑制属性(SUPPRESS-BEGIN-DRAG-EVENT
など)によって抑制できます。これらの属性はデフォルトではすべて SUPPRESSED
に設定されています。
BEGIN-DRAG
イベントは(抑制されていない場合)、ドラッグ操作の開始時にドラッグソースに送られます。 アプリケーションでは、このイベントを退出する前に、SET-CLIPBOARD-DATA
アクションを使用してドラッグ/ドロップクリップボードにデータを転送する必要があります。転送しないと、ドラッグ/ドロップ操作はマウスカーソルを変更せずに暗黙的にキャンセルされます。 OPEN-CLIPBOARD
アクションまたは CLOSE-CLIPBOARD
アクションのどちらも呼び出す必要がないことに注意してください。
END-DRAG
イベントは(抑制されていない場合)、ドラッグ/ドロップ操作の終了後に(ドラッグ操作がキャンセルされた場合でも)ドラッグソースに送られます。 このイベントの主な使用目的は、移動操作が生じた場合にソースデータを削除することです。 アプリケーションでは、既存の
INQ-DRAG-DROP
アクションを呼び出すことによって、移動操作が発生しているかどうかを把握できます。INQ-DRAG-DROP アクションは機能拡張され、2 つの整数型の出力オプションパラメータが新しく追加されています。 これらの新規パラメータの 1 つ目は、現在押されているマウスボタンを示します(1
= 左ボタン、2 = 右ボタン、4 = 中央のボタン、またはその組み合わせ)。 2 つ目の新規パラメータが、ここで必要とされているもので、ドラッグ/ドロップ操作による最終的なドロップ効果を示します。ドロップが実行されなかった、または操作がキャンセルされた場合は
DM-NONE
、コピー操作が実行された場合は DM-COPY
、移動操作が実行された場合は DM-MOVE
、およびリンク操作が実行された場合は DM-LINK
が設定されます。
DRAG-ENTER
イベントは(抑制されていない場合)、ドロップターゲットによって占有されているリージョンにドラッグカーソルが(再度)入るときに、ドロップターゲットに送られます。 アプリケーションは通常、INQ-FORMAT-AVAILABLE
アクションを呼び出して互換データフォーマットがクリップボードで有効かどうかを確認し、その後 SUPPRESS-DRAG-DROP-EVENT
属性を適宜設定して、このイベントに応答します。 SUPPRESS-DRAG-DROP-EVENT
は、DRAG-DROP
イベントを発生させるかどうかを決定するだけでなく、ドロップを許可するかどうかを Natural に通知するため、重要です。 DRAG-ENTER
と DRAG-OVER
の各イベントを発生させた後、Natural は SUPPRESS-DRAG-DROP-EVENT
属性を確認して "ドロップ禁止" 記号を表示します。 それ以外に、ドロップ効果は、ドラッグソースの DRAG-MODE
値、ドロップターゲットの DROP-MODE
値、および現在押されている修飾キー(Shift キーと Ctrl キー)の組み合わせによって決まります。
DRAG-OVER
イベントは(抑制されていない場合)、ドラッグカーソルがドロップターゲットの上を移動するたびにドロップターゲットに送られます。 このイベントは、例えば、ユーザーがコントロール内の項目を横切るときにドロップの強調表示(行われている場合)を更新したり、ドロップ操作を実行できるかどうかがドロップターゲット内の位置に依存する場合に
SUPPRESS-DRAG-DROP-EVENT
属性を更新したりするために使用できます。
DRAG-LEAVE
イベントは(抑制されていない場合)、ドロップを発生させずに、ドロップターゲットによって占有されているリージョンをドラッグカーソルが離れるときに、ドロップターゲットに送られます。 このイベントは(使用されたとしても)主に DRAG-OVER
イベントで適用されたドロップの強調表示(行われている場合)を削除するために使用されます。
DRAG-DROP
イベントは(抑制されていない場合)、ユーザーがドロップを実行するときに、ドロップターゲットに送られます。 アプリケーションは、(必要であればコントロール内の現在の相対位置を使用して)貼り付け操作を効率よく実行して、これに応答する必要があります。
相対位置と操作タイプは両方とも INQ-DRAG-DROP
アクションを通して取得できます。 操作タイプは新規のオプションパラメータ "Drop Effect" に返されます(詳細は上記の END-DRAG
イベントを参照)。
リストボックスでは、新規の"挿入マーク(i)"スタイルを使用して、ドラッグカーソルがコントロール(ドロップターゲットだと想定)の上を移動するときに現在の挿入位置を示すために水平破線を使用するよう指定できます。 アプリケーションは挿入マーク位置を直接クエリできませんが、以下の例のように、INQ-DRAG-DROP
アクションでコントロール内の相対位置をクエリし、その後これらの座標を INQ-ITEM-BY-POSITION
アクションに渡すことにより、データをどこに挿入するかを確認できます。
DEFINE DATA LOCAL 1 #Y (I4) 1 #CONTROL HANDLE OF GUI 1 #ITEM HANDLE OF GUIEND-DEFINE ... /* DRAG-DROP event: PROCESS GUI ACTION INQ-DRAG-DROP WITH 4X #Y GIVING *ERROR * IF #Y < 0 #Y := 0 END-IF #CONTROL := *CONTROL PROCESS GUI ACTION INQ-ITEM-BY-POSITION WITH #CONTROL 0 #Y #ITEM GIVING *ERROR
上記のコードを実行すると、挿入位置にある項目のハンドルが変数 #ITEM
に設定されます。 その後、SUCCESSOR
属性を #ITEM
に設定して WITH PARAMETERS
節を指定した ADD
アクションを呼び出すことによって、この位置に 1 つ以上のリストボックス項目をダイナミックに挿入できます。
ドロップ位置がリストボックス上部の境界線上にある場合に対応するために、上記の例のように負の値の y 座標を修正する必要があることに注意してください。 ここで修正しない場合、#ITEM
は NULL-HANDLE
に設定され、上記のように SUCCESSOR
属性として #ITEM
を直接使用していると、新規リストボックス項目はリストの先頭ではなくリストの末尾に追加されます。
便宜上、Natural アプリケーションでのドラッグドロップを実装する手順の概要をここで説明します。
各ドラッグソース対して DRAG-MODE
を設定します。 ドラッグソースがビットマップコントロールの場合、DRAGGABLE
属性も TRUE
に設定する必要があります。
各ドラッグソースの BEGIN-DRAG
イベントで SET-CLIPBOARD-DATA
を使用して転送データを渡します。
各ドロップターゲットに対して DROP-MODE
を設定します。
DRAG-ENTER
イベントでは INQ-FORMAT-AVAILABLE
アクションを使用して、サポートされているクリップボードフォーマットが有効であれば SUPPRESS-DRAG-DROP-EVENT
属性を NOT-SUPPRESSED (0)
に、有効でなければ SUPPRESSED (1)
に設定します。 コントロールがドラッグソースとしても動作可能で、コントロール内でドラッグドロップ操作を禁止する必要がある場合、INQ-DRAG-DROP
を呼び出して、ソースコントロールハンドルを取得し、それを現在のコントロール(*CONTROL
)と比較します。どちらも同じであればドラッグドロップ操作を抑制します。
ドロップ効果がターゲットコントロール内で位置センシティブな場合、DRAG-OVER
イベント内で INQ-DRAG-DROP
アクションを使用して現在の位置を取得し、(INQ-ITEM-BY-POSITION
アクションなどを通じて)ドラッグカーソルの下の項目を判断して SUPPRESS-DRAG-DROP-EVENT
属性を適切に設定します。 必要に応じて現在の項目を強調表示します。
上記の手順 5 で現在の項目を強調表示した場合、DRAG-LEAVE
イベントおよび(場合によっては)DRAG-DROP
イベントで(必要に応じて)その強調表示を解除します。
DRAG-DROP
イベントで GET-CLIPBOARD-DATA
を使用して転送データを取得し、適切に処理します。
ドラッグソースに対する END-DRAG
イベントでは、INQ-DRAG-DROP
によって返されたドロップ効果が DM-MOVE
に設定されていた場合、ソースデータを削除します。
ドラッグソースが ActiveX コントロールの場合、(例えば)現在の選択内の位置がクリックされると、"MouseDown" イベントに応答してドラッグドロップ操作を開始するために PERFORM-DRAG-DROP
アクションを呼び出します。
ユーザーの操作に応答して Windows クリップボードまたはドラッグドロップクリップボードに置く必要のある、またはすでに置かれているデータの設定または取得の問題の 1 つが、ランタイム時に任意の大きさのデータに対処できるようにすることです。 例えば、ユーザーは、1 つ、少数、さらには数百または数千のリストボックス項目を、クリップボード操作やドラッグドロップ操作を実行する前に選択できます。 固定サイズの配列では、通常はわずかな割合しか使用されないことが多い場合でも、最悪の事態に対処するために非常に大きな配列を定義する必要があります。
Natural には、この問題に対する有効な解決方法が 2 つあります。 1 つ目の方法は、単一のダイナミック文字変数を使用して、設定または取得するすべての項目を格納することです。 つまり、アプリケーション側で、SET-CLIPBOARD-DATA
を呼び出す前にダイナミック変数に項目(デリミタを含む)を構築し、GET-CLIPBOARD-DATA
を呼び出した後にダイナミック変数から項目を抽出します。 プライベートフォーマットには区切りがないため、このアプローチはプライベートフォーマットには使用できません。
2 つ目のアプローチは、X-array を使用することです。 クリップボードデータを設定する場合、X-array は、特定の状況で必要な要素数を正確に格納するためにサイズを変更できる点を除き、固定サイズ配列と同様に動作します。 例えば、クリップボードに書き込む 17 個の項目がある場合、以下のように X-array を使用できます。
DEFINE DATA LOCAL 1 #X-ARR(A80/1:*) 1 #UPB (I4) INIT <17> END-DEFINE RESIZE ARRAY #X-ARR TO (1:#UPB) PROCESS GUI ACTION SET-CLIPBOARD-DATA WITH CF-TEXT #X-ARR(*)
下記のように、ごく一部しか使用されない、巨大な固定サイズ配列を使用する必要はありません。
DEFINE DATA LOCAL 1 #ARR(A80/10000) 1 #UPB (I4) INIT <17> END-DEFINE PROCESS GUI ACTION SET-CLIPBOARD-DATA WITH CF-TEXT ARR(1:#UPB)
クリップボードデータを取得する場合、アプリケーションではクリップボード上の項目数をあらかじめ把握できないため、X-array はさらに有効です。 すべての配列要素(上記の例では 10,000)を渡すと、未使用の要素もすべてリセットする必要があるため、かなり処理が遅くなります。
ただし、代わりに X-Array を使用すると、Natural は自動的に配列を (1:N) にサイズ変更します。N はクリップボードの(残りの)最小の項目数で、配列の最大上限(DEFINE-DATA
で定義されているように、"*" は可能な最大値を示します)になります。 GET-CLIPBOARD-DATA
とともに X-array を使用する際には次の 3 つの制限事項があることに注意してください。
X-array は最後(または唯一)のパラメータにする必要があります。
1 次元の X-array だけがサポートされています。
X-array の範囲定義には要素 1 を含んでいる必要があります。
以下は、ダイナミック X-array を使用してクリップボードデータを取得する方法を説明したプログラム例です。2 つ目の X-array はデータ長を保存および表示するために使用されています。
DEFINE DATA LOCAL 1 #FMT (A10) CONST<'MYDATAFMT'> 1 #X-ARR (A/1:*) DYNAMIC 1 #X-LEN (I4/1:*) 1 #UPB (I4) 1 #I (I4) END-DEFINE PROCESS GUI ACTION OPEN-CLIPBOARD GIVING *ERROR PROCESS GUI ACTION SET-CLIPBOARD-DATA WITH #FMT 'MIKE' 'FRED' 'JIM' 'LULU' 'FRANK' 'JANA' 'ELIZABETH' 'TONY' GIVING *ERROR PROCESS GUI ACTION CLOSE-CLIPBOARD GIVING *ERROR PROCESS GUI ACTION GET-CLIPBOARD-DATA WITH #FMT #X-ARR(*) GIVING *ERROR #UPB := *UBOUND(#X-ARR) RESIZE ARRAY #X-LEN TO (1:#UPB) FOR #I 1 #UPB #X-LEN(#I) := *LENGTH(#X-ARR(#I)) END-FOR DISPLAY #X-ARR(*) (AL=10) #X-LEN(*) / '*** END OF DATA ***' END