Marco Cantù's
Essential Pascal Chapter 8
Memory
 
第8章 メモリ
 
Author's Note: This chapter will cover memory handling, discuss the various memory areas, and introduce dynamic arrays. Temporarily only this last part is available.
 
訳注 : この章は、現在執筆中で、最後の動的配列のみ、公開されています。
 
Delphi 4 Dynamic Arrays
 
Delphi 4 の動的配列
 
Traditionally, the Pascal language has always had fixed-size arrays. When you declare a data type using the array construct, you have to specify the number of elements of the array. As expert programmers probably know, there were a few techniques you could use to implement dynamic arrays, typically using pointers and manually allocating and freeing the required memory.
 
伝統的に、Pascal では配列は範囲が決まっている。 配列を使ってデータ型を宣言する時には、必ず配列の要素の数を指定する必要がある。 エキスパートなら、動的配列を使うテクニックも知っているだろう。 ポインタを使って、メモリを指定したり、解放したりするのが、それだ。
 
Delphi 4 introduces a very simple implementation of dynamic arrays, modeling them after the dynamic long string type I've just covered. As long strings, dynamic arrays are dynamically allocated and reference counted, but they do not offer a copy-on-write technique. That's not a big problem, as you can deallocate an array by setting its variable to nil.
 
Delphi 4 では、非常に簡単な動的配列を導入した。 この一例が、動的な長い文字列型だ。 長い文字列と同様に、動的配列というのは参照カウントされる。 ただ、コピー時書き込みというテクニックは使わない。 これについては、配列を初期化する時には、その変数を nil にすればいいんだから、大きな問題にはならない。
 
You can now simply declare an array without specifying the number of elements and then allocate it with a given size using the SetLength procedure. The same procedure can also be used to resize an array without losing its content. There are also other string-oriented procedures, such as the Copy function, that you can use on arrays.
 
要素の数を明確にしないでも、配列が宣言でき、SetLength 手続きを使って指定のサイズ分メモリに配置できる。 この手続きを使うと、その中身を失わないで、配列のサイズを変えることができる。 他にも String に適した手続きがあり、Copy 関数は、配列にも使える。
 
Here is a small code excerpt, underscoring the fact that you must both declare and allocate memory for the array before you can start using it:
 
配列を使うときには、まず宣言し、メモリに配置することが絶対に必要だ、ということを分かってもらうために、小さなコードを書いてみよう。
 
procedure TForm1.Button1Click(Sender: TObject);
var
 Array1: array of Integer;
begin
 Array1 [1] := 100; // error エラー
 SetLength (Array1, 100);
 Array1 [99] := 100; // OK OK
 ...
end;
 
As you indicate only the number of elements of the array, the index invariably starts from 0. Generic arrays in Pascal account for a non-zero low bound and for non-integer indexes, two features that dynamic arrays don't support. To learn the status of a dynamic array, you can use the Length, High, and Low functions, as with any other array. For dynamic arrays, however, Low always returns 0, and High always returns the length minus one. This implies that for an empty array High returns -1 (which, when you think about it, is a strange value, as it is lower than that returned by Low).
 
配列の要素数のみ宣言した場合、インデックスは必ず 0 から始まる。 オリジナルの Pascal 配列は、ゼロ以外で始まり、非整数も使えるが、動的配列ではこの特徴はサポートされない。 動的配列の状態を見るには、Length、High、Low 関数を使えばいい。 動的配列では、Low は必ず 0 で、High は配列の長さからひとつ減算して返す。 ということは、空の配列では、High は -1 を返す、ということだ。 Low よりも小さくなるので、ちょっと不思議な気はするけどね。
 
Figure 8.1: The form of the DynArr example
 
図 8.1 : DynArr サンプルのフォーム
 
After this short introduction I can show you a simple example, called DynArr and shown in Figure 8.1. It is indeed simple because there is nothing very complex about dynamic arrays. I'll also use it to show a few possible errors programmers might make. The program declares two global arrays and initializes the first in the OnCreate handler:
 
簡単な説明はこれくらいで、簡単なサンプルを示す。 DynArr という名前で、図 8.1 だ。 動的配列については何も複雑なことは無いので、本当にシンプルだ。 ついでに、プログラマが間違いやすい点についても取り上げてある。 このプログラムでは、ふたつのグローバル配列を宣言し、OnCreate ハンドラで最初の配列を初期化する。
 
var
 Array1, Array2: array of Integer;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
 // allocate 割付け
 SetLength (Array1, 100);
end;
 
This sets all the values to zero. This initialization code makes it possible to start reading and writing values of the array right away, without any fear of memory errors. (Assuming, of course, that you don't try to access items beyond the upper bound of the array.) For an even better initialization, the program has a button that writes into each cell of the array:
 
これで、すべてゼロに初期化する。 初期化コードは、そのまま配列の値を読み書きした時にメモリ・エラーが発生しないようにするものだ。 当然、配列の上限以上の項目にアクセスしてはいけないことは、知ってるね。 もっと賢い初期化をするために、プログラムには配列の各セルに書き込みをするコードがある。
 
procedure TForm1.btnFillClick(Sender: TObject);
var
 I: Integer;
begin
 for I := Low (Array1) to High (Array1) do
  Array1 [I] := I;
end;
 
The Grow button allows you to modify the size of the array without losing its contents. You can test this by using the Get value button after pressing the Grow button:
 
Grow という名前のボタンを使うと、その内容を失わないで配列のサイズを変更できる。 Grow ボタンを押した後で、Get ボタンを押してみるといい。
 
procedure TForm1.btnGrowClick(Sender: TObject);
begin
 // grow keeping existing values 現在の値を保持したまま、拡張
 SetLength (Array1, 200);
end;
 
procedure TForm1.btnGetClick(Sender: TObject);
begin
 // extract 値を抽出
 Caption := IntToStr (Array1 [99]);
end;
 
The only slightly complex code is in the OnClick event of the Alias button. The program copies one array to the other one with the := operator, effectively creating an alias (a new variable referring to the same array in memory). At this point, however, if you modify one of the arrays, the other is affected as well, as they both refer to the same memory area:
 
ちょっとややこしいのが、Alias ボタンの OnClick イベントだ。 プログラムは、:= オペレータで、ある配列を別の配列にコピーする。 つまりエリアスを生成する。 メモリ上の同じ配列を参照する新しい変数、ということだ。 しかし、配列のひとつを変化させると、他の配列も影響を受ける。 どちらも、同じメモリ領域を参照しているからね。
 
procedure TForm1.btnAliasClick(Sender: TObject);
begin
 // alias エリアス
 Array2 := Array1;
 // change one (both change) どちらかを変える ( 両方変わる )
 Array2 [99] := 1000;
 // show the other もうひとつのものを表示
 Caption := IntToStr (Array1 [99]);
 
The btnAliasClick method does two more operations. The first is an equality test on the arrays. This tests not the actual elements of the structures but rather the memory areas the arrays refer to, checking whether the variables are two aliases of the same array in memory:
 
btnAliasClick メソッドは、あとふたつ、他の処理もする。 最初のものは、配列の同一性のテストを行う。 このテストは、ふたつのエリアスが、メモリ上の同一配列であるかどうかをチェックするもので、配列の構造に関して、というのではなく、配列が参照しているメモリ領域に関して、ということだ。 
 
procedure TForm1.btnAliasClick(Sender: TObject);
begin
 ...
 if Array1 = Array2 then
  Beep;
 // truncate first array 最初の配列を整理
 Array1 := Copy (Array2, 0, 10);
end;
 
The second is a call to the Copy function, which not only moves data from one array to the other, but also replaces the first array with a new one created by the function. The effect is that the Array1 variable now refers to an array of 11 elements, so that pressing the Get value or Set value buttons produces a memory error and raises an exception (unless you have range-checking turned off, in which case the error remains but the exception is not displayed). The code of the Fill button continues to work fine even after this change, as the items of the array to modify are determined using its current bounds.
 
二番目のものは、Copy 関数と呼ばれるもので、データをある配列から別の配列に移すだけでなく、最初の配列を、この関数で生成した新しい配列で上書きする。 結果として、Array1 変数は11 要素の配列を参照することになり、Get value ボタンや Set value ボタンを押すと、メモリエラーになり、例外が発生する。 ただこれは、範囲チェックを外してている場合は、エラーそのものは残るが、例外は表示されない。 Fill ボタンのコードは、この変更後も働くが、これは自分の上下限を利用しているからだ。
 
Conclusion
 
結論
 
This chapter temporarily covers only dynamic arrays, certainly an important element for memory management, but only a portion of the entire picture. More material will follow.
 
この章では、しばらくの間、動的配列のみ扱った。 動的配列自体、メモリマネジメントの重要なポイントだが、全体から見れば、ほんの一部に過ぎない。 しばらく待っていてほしい。
 
The memory structure described in this chapter is typical of Windows programming, a topic I'll introduce in the next chapter (without going to the full extent of using the VCL, though).
 
この章で扱ったメモリ構造は、Windows プログラミングの代表的なもので、次章ではこの Windows プログラミングについて扱う。 ただし、VCL を使ったプログラミングについては、一部にとどめる。
 
Next Chapter: Windows Programming
 
次章 : Windows プログラミング
 
© Copyright Marco Cantù, Wintech Italia Srl 1995-2000
 
 
Marco Cantu's
Essential Pascal Chapter 9:
Windows Programming
 
第9章 Windows プログラミング
 
Delphi provides a complete encapsulation of the low-level Windows API using Object Pascal and the Visual Component Library (VCL), so it is rarely necessary to build Windows applications using plain Pascal and calling Windows API functions directly. Nonetheless, programmers who want to use some special techniques not supported by the VCL still have that option in Delphi. You would only want to take this approach for very special cases, such as the development of new Delphi components based on unusual API calls, and I don't want to cover the details. Instead, we'll look at a few elements of Delphi's interaction with the operating system and a couple of techniques that Delphi programmers can benefit from.
 
Delphi では低レベルの Windows API は、Object Pascal と Visual Component Library (VCL) を使って完全にカプセル化されているので、Windows アプリケーションを作るときに、オブジェクト指向でない Pascal を使ったり、直接 Windows API 関数を呼んだりする必要は、ほとんど無い。 それでも、VCL でサポートされていない特別なテクニックを使いたい、というプログラマのために、Delphi ではこのオプションも準備してある。 ただ、これは非常に特殊な場合、たとえば一般的で無い API を使った、新しい Delphi コンポーネントの開発、などという場合だけなので、あまり深くは取り上げない。 その代わり、Delphi がOS とやり取りしている方法や、Delphi プログラマが知っておくと便利なことだけ、いくつか取り上げてみよう。
 
Windows Handles
 
Windows ハンドル
 
Among the data types introduced by Windows in Delphi, handles represent the most important group. The name of this data type is THandle, and the type is defined in the Windows unit as:
 
 
Delphi の扱う、Windows 固有のデータ型の中で、ハンドルは、もっとも重要なグループだ。 このデータ型には THandle という名前が付けられ、Windows ユニットで定義されている。
 
type
 THandle = LongWord;
 
Handle data types are implemented as numbers, but they are not used as such. In Windows, a handle is a reference to an internal data structure of the system. For example, when you work with a window (or a Delphi form), the system gives you a handle to the window. The system informs you that the window you are working with is window number 142, for example. From that point on, your application can ask the system to operate on window number 142洋oving it, resizing it, reducing it to an icon, and so on. Many Windows API functions, in fact, have a handle as the first parameter. This doesn't apply only to functions operating on windows; other Windows API functions have as their first parameter a GDI handle, a menu handle, an instance handle, a bitmap handle, or one of the many other handle types.
 
ハンドルは、数値になっているが、数値として使われるのではない。 Windows では、ハンドルはシステムの内部データ構造に対する参照になっている。 たとえば、ウィンドウ ( または Delphi のフォーム ) を扱っているときには、システムはそのウィンドウのハンドルを、ユーザーに示す。 あなたの扱っているウィンドウは、ウィンドウ番号 142 です、という具合だ。 この情報を得ることで、システムにウィンドウ番号 142 を動かしたり、サイズを変えたり、アイコン化したり、という指示ができる。 多くの Windows API 関数では、その第一パラメータは、ハンドルになっている。 また、ウィンドウを操作する関数にだけハンドルはあるのではなく、GDI ハンドル、メニュー・ハンドル、インスタンス・ハンドル、ビットマップ・ハンドル、その他、多数のハンドル型が、多くの Windws API 関数に使われている。
 
In other words, a handle is an internal code you can use to refer to a specific element handled by the system, including a window, a bitmap, an icon, a memory block, a cursor, a font, a menu, and so on. In Delphi, you seldom need to use handles directly, since they are hidden inside forms, bitmaps, and other Delphi objects. They become useful when you want to call a Windows API function that is not supported by Delphi.
 
つまり、ハンドルというのは、ウィンドウ、ビットマップ、アイコン、メモリ・ブロック、カーソル、フォント、メニューなど様々な、システムが扱う要素を参照できる内部コードなのだ。 Delphi では、このハンドルを直接使うことは、あまり無い。 というのも、ハンドルは、フォーム、ビットマップ、その他 Delphi オブジェクトの内部に、隠されているからだ。 ハンドルは、Delphi でサポートされていない、Windows API 関数を呼び出す時に必要になる。
 
To complete this description, here is a simple example demonstrating Windows handles. The WHandle program has a simple form, containing just a button. In the code, I respond to the OnCreate event of the form and the OnClick event of the button, as indicated by the following textual definition of the main form:
 
Windows ハンドルの実例を見てみよう。 WHandle プログラムは、フォームにボタンがひとつ乗っている、という簡単なものだ。 コードは、単にフォームの OnCreate、ボタンの OnClick についてのみ書いてある。 メイン・フォームの定義は、下記だけだ。
 
object FormWHandle: TFormWHandle
 Caption = 'Window Handle'
 OnCreate = FormCreate
 object BtnCallAPI: TButton
  Caption = 'Call API'
  OnClick = BtnCallAPIClick
 end
end
 
As soon as the form is created, the program retrieves the handle of the window corresponding to the form, by accessing the Handle property of the form itself. We call IntToStr to convert the numeric value of the handle into a string, and we append that to the caption of the form, as you can see in Figure 9.1:
 
プログラムをスタートしてフォームが生成されると、このプログラムは、フォーム自体のHandle プロパティから、フォームに該当するウィンドウのハンドルを取得する。 ハンドルは数値なので、IntToStr で String に変換し、それをフォームの現在の Caption に追記する。 図 9.1 を見て欲しい。
 
procedure TFormWHandle.FormCreate(Sender: TObject);
begin
 Caption := Caption + ' ' + IntToStr (Handle);
end;
 
Because FormCreate is a method of the form's class, it can access other properties and methods of the same class directly. Therefore, in this procedure we can simply refer to the Caption of the form and its Handle property directly.
 
FormCreate は、フォーム・クラスのメソッドなので、同じクラスのプロパティやメソッドに直接アクセスできる。 だからこの場合は、ただ、フォームの Caption や Handle を直接参照すればいい。
 
Figure 9.1: The WHandle example shows the handle of the form window. Every time you run this program you'll get a different value.
 
図 9.1 : フォーム・ウィンドウのハンドルを示す、WHandle プログラム。 実行する毎に、別のハンドル値が得られる。
 
If you run this program several times you'll generally get different values for the handle. This value, in fact, is determined by Windows and is sent back to the application. (Handles are never determined by the program, and they have no predefined values; they are determined by the system, which generates new values each time you run a program.)
 
一般的には、プログラムを実行する毎に、別のハンドル値が得られる。 この値は、Windows によって決定され、アプリケーションに通知される。 ハンドルがプログラムで決定されることは絶対に無いし、事前に割り当てられてもいない。 プログラムを実行する毎に、システムがハンドル値を決定している。
 
When the user presses the button, the program simply calls a Windows API function, SetWindowText, which changes the text or caption of the window passed as the first parameter. To be more precise, the first parameter of this API function is the handle of the window we want to modify:
 
ボタンを押すと、プログラムは Window API 関数、SetWindowText を呼び出し、第一パラメータで渡されるウィンドウのテキスト、または Caption を変える。 もっと正確に言えば、この API 関数の第一パラメータは、君が操作したい、と思っているウィンドウのハンドルなのだ。
 
procedure TFormWHandle.BtnCallAPIClick(Sender: TObject);
begin
 SetWindowText (Handle, 'Hi');
end;
 
This code has the same effect as the previous event handler, which changed the text of the window by giving a new value to the Caption property of the form. In this case calling an API function makes no sense, because there is a simpler Delphi technique. Some API functions, however, have no correspondence in Delphi, as we'll see in more advanced examples later in the book.
 
このコードでは、前のイベント・ハンドラと同じ結果が得られる。 フォームの Caption プロパティに新しい値を与えることで、ウィンドウのテキストを変更する、というものだ。 ただこの場合、API 関数を呼ぶというのは、本当はあまり賢いことではない。 Delphi では、もっと簡単なやり方があるからだ。 ただ、この本の後ろのところで書いているような、もっと高度な例では、Delphi が扱っていないような、API 関数も存在することを、覚えておこう。
 
External Declarations
 
外部宣言
 
Another important element for Windows programming is represented by external declarations. Originally used to link the Pascal code to external functions that were written in assembly language, the external declaration is used in Windows programming to call a function from a DLL (a dynamic link library). In Delphi, there are a number of such declarations in the Windows unit:
 
もうひとつ、Windows プログラミングにとって重要なことがある。 それが外部宣言だ。 元々は、アセンブリで書かれた外部関数と Pascal コードとをリンクさせるために考えられたもので、Windows プログラミングでは、DLL ( ダイナミック・リンク・ライブラリ ) の関数を呼び出すのに使う。 Delphi では、Windows ユニットに、この宣言がいくつか書かれている。
 
// forward declaration 事前宣言
 
function LineTo (DC: HDC; X, Y: Integer): BOOL; stdcall;
 
// external declaration (instead of actual code) 外部宣言 ( 実際のコードに代えて )
function LineTo; external 'gdi32.dll' name 'LineTo';
 
This declaration means that the code of the function LineTo is stored in the GDI32.DLL dynamic library (one of the most important Windows system libraries) with the same name we are using in our code. Inside an external declaration, in fact, we can specify that our function refer to a function of a DLL that originally had a different name.
 
この宣言の意味は、LineTo という関数のコードは、GDI32.DLL ( Windows システム・ライブラリの一番重要なもののひとつ ) に、このコードで使っているのと同じ名前で納められている、ということを表している。 実のところ、外部宣言の内部では、元は別名になっていた DLL の関数を参照させることもできる。
 
You seldom need to write declarations like the one just illustrated, since they are already listed in the Windows unit and many other Delphi system units. The only reason you might need to write this external declaration code is to call functions from a custom DLL, or to call undocumented Windows functions.
 
ただ、上のような宣言を書く必要は、ほとんど無い。 というもの、これらは Windows ユニットや、他の Delphi システム・ユニットに書かれているからだ。 外部宣言が必要な場合というのは、カスタム DLL の関数や、Windows 関数で、ドキュメントが公開されていないものだけだ。
 
Note: In the 16-bit version of Delphi, the external declaration used the name of the library without the extension, and was followed by the name directive (as in the code above) or by an alternative index directive, followed by the ordinal number of the function inside the DLL. The change reflects a system change in the way libraries are accessed: Although Win32 still allows access to DLL functions by number, Microsoft has stated this won't be supported in the future. Notice also that the Windows unit replaces the WinProcs and WinTypes units of the 16-bit version of Delphi.
 
注:16 ビット Delphi では、外部宣言は識別子無しのライブラリ名を使っていて、その後ろに ( このコードにあるように ) name 指令を付けるか、DLL 内の関数が占めている順序を表すインデックス指令を付けていた。 ライブラリ内の順番が変わると、当然動作が変わった。 Win32 では、DLL の関数にアクセスするのに、順番を使うこともできるが、Microsoft は、将来もこの機能をサポートする予定は無いことを、表明している。 16 ビット Delphi の WinProcs と WinTypes ユニットは、Windows ユニットでカバーしていることに注意。
 
A Windows Callback Function
 
Windows コールバック関数
 
We've seen in Chapter 6 that Objet Pascal supports procedural types. A common use of procedural types is to provide callback functions to a Windows API function.
 
この第6章で、Object Pascal が手続き型をサポートすることを話した。 手続き型の一番の用途は、Windows API 関数へのコールバック関数だ。
 
First of all, what is a callback function? The idea is that some API function performs a given action over a number of internal elements of the system, such as all of the windows of a certain kind. Such a function, also called an enumerated function, requires as a parameter the action to be performed on each of the elements, which is passed as a function or procedure compatible with a given procedural type. Windows uses callback functions in other circumstances, but we'll limit our study to this simple case.
 
その前に、コールバック関数って、何? これは、API 関数が、システム内部のいくつかの要素、特定のウィンドウすべて、に働きかける、ということから来ている。 そのような関数は、列挙型関数と呼ばれるが、各要素に対して働きかけるアクションをパラメータとして要求し、このパラメータは、該当する列挙型と互換性のある関数や手続きに渡される。 Windows は、コールバック関数を、この例以外の環境でも使うが、これについてはここでは取り扱わない。
 
Now consider the EnumWindows API function, which has the following prototype (copied from the Win32 Help file):
 
さて、こういうプロトタイプ ( これは、Win32 Help ファイルからコピーした ) を持つ、EnumWindows API 関数を例に取ろう。
 
BOOL EnumWindows(
 WNDENUMPROC lpEnumFunc, // address of callback function コールバック関数のアドレス
 LPARAM lParam // application-defined value アプリケーションが定義する値
 );
 
Of course, this is the C language definition. We can look inside the Windows unit to retrieve the corresponding Pascal language definition:
 
もちろん、これは C 言語の定義だ。 Windows ユニットを見れば、これに対応する Pascal 言語での定義が分かる。
 
function EnumWindows (
 lpEnumFunc: TFNWndEnumProc;
 lParam: LPARAM): BOOL; stdcall;
 
Consulting the help file, we find that the function passed as a parameter should be of the following type (again in C):
 
ヘルプファイルによれば、パラメータとして渡される関数は、次のようでなければならない ( これも C だ )。
 
BOOL CALLBACK EnumWindowsProc (
 HWND hwnd, // handle of parent window 親ウィンドウのハンドル
 LPARAM lParam // application-defined value アプリケーションが定義する値
 );
 
This corresponds to the following Delphi procedural type definition:
 
Delphi 手続き型の定義では、こうだ。
 
type
 EnumWindowsProc = function (Hwnd: THandle;
  Param: Pointer): Boolean; stdcall;
 
The first parameter is the handle of each main window in turn, while the second is the value we've passed when calling the EnumWindows function. Actually in Pascal the TFNWndEnumProc type is not properly defined; it is simply a pointer. This means we need to provide a function with the proper parameters and then use it as a pointer, taking the address of the function instead of calling it. Unfortunately, this also means that the compiler will provide no help in case of an error in the type of one of the parameters.
 
この最初のパラメータは、それぞれメインになっていくウィンドウのハンドルで、二番目のものは、EnumWindws 関数を呼ぶときに渡す値だ。 実のところ、Pascal では、TFNWndEnumProc 型は、正しく定義されていない。 これは、そのままポインタなのだ。 ということは、正しいパラメータを装備した関数を作って、それを呼び出す代わりに、関数のアドレスを取得し、それをポインタとして使う、ということだ。 不幸なことに、このことは、パラメータのどれかの型にエラーがあっても、コンパイラは知らせてくれない、ということでもある。
 
Windows requires programmers to follow the stdcall calling convention every time we call a Windows API function or pass a callback function to the system. Delphi, by default, uses a different and more efficient calling convention, indicated by the register keyword.
 
Windows は、プログラマに Windows API 関数を呼び出したり、システムにコールバック関数を渡したりする時には、stdcall 呼び出し規約に従うよう、求めている。 Delphi では、デフォルトとして、register キーワードで示される、別種の、より有効な呼び出し規約を用意している。
 
Here is the definition of a proper compatible function, which reads the title of the window into a string, then adds it to a ListBox of a given form:
 
互換性が確かな、関数を提供しよう。 これは Window のタイトルを読み取り、string に納める。 その後、指定のフォームの ListBox に追加してくれる。
 
function GetTitle (Hwnd: THandle; Param: Pointer): Boolean; stdcall;
var
 Text: string;
begin
 SetLength (Text, 100);
 GetWindowText (Hwnd, PChar (Text), 100);
 FormCallBack.ListBox1.Items.Add (
  IntToStr (Hwnd) + ': ' + Text);
 Result := True;
end;                 
 
The form has a ListBox covering almost its whole area, along with a small panel on the top hosting a button. When the button is pressed, the EnumWindows API function is called, and the GetTitle function is passed as its parameter:
 
このフォームでは、ListBox が面積の殆どを占めていて、上の部分にボタンを乗せたパネルがあるだけだ。 ボタンをクリックすると、EnumWindowsAPI 関数を呼び出し、GetTitle 関数が、パラメータとして渡される。
 
procedure TFormCallback.BtnTitlesClick(Sender: TObject);
var
 EWProc: EnumWindowsProc;
begin
 ListBox1.Items.Clear;
 EWProc := GetTitle;
 EnumWindows (@EWProc, 0);
end;
 
I could have called the function without storing the value in a temporary procedural type variable first, but I wanted to make clear what is going on in this example. The effect of this program is actually quite interesting, as you can see in Figure 9.2. The Callback example shows a list of all the existing main windows running in the system. Most of them are hidden windows you usually never see (and many actually have no caption).
 
最初に、ここで扱われる型の変数に値を納めるのではなく、そのまま関数を呼び出すこともできるが、このサンプルでは、何が行われているか、はっきり知って貰いたい、と思って作った。 このプログラムの示すものは、図 9.2. で分かるように、非常に興味深いものだ。 Callback サンプルでは、システムで動いている、すべてのメインウィンドウのリストを提供する。 ウィンドウの多くは、滅多に見ることの無い(多くは、caption も無い)、隠れたウィンドウになっている。
 
Figure 9.2: The output of the Callback example, listing the current main windows (visible and hidden).
 
図 9.2. : Callback サンプルの実行。 現在のメインウィンドウ(見えるもの、隠れている もの)のリスト。
 
A Minimal Windows Program
 
最小の Windows プログラム
 
To complete the coverage of Windows programming and the Pascal language, I want to show you a very simple but complete application built without using the VCL. The program simply takes the command-line parameter (stored by the system in the cmdLine global variable) and then extracts information from it with the ParamCount and ParamStr Pascal functions. The first of these functions returns the number of parameters; the second returns the parameter in a given position.
 
Windows プログラミングと Pascal との関連を理解してもらうため、VCL を使わない、非常にシンプルな、しかし完全なアプリケーションを提供しよう。 このプログラムは、単純にコマンドライン・パラメータを取り( cmdLine グローバル変数でシステムに取り込まれる)、ParamCount と ParamStr という Pascal 関数で、情報を取り出す。 ParamCount はパラメータの数を返し、ParamStr は与えられた位置のパラメータを返す。
 
Although users seldom specify command-line parameters in a graphical user interface environment, the Windows command-line parameters are important to the system. For example, once you have defined an association between a file extension and an application, you can simply run a program by selecting an associated file. In practice, when you double-click on a file, Windows starts the associated program and passes the selected file as a command-line parameter.
 
グラフィカルなユーザーインターフェイス環境では、コマンドライン・パラメータを使う頻度は多くないだろうが、Windows コマンドライン・パラメータは、システムにとっては重要だ。 たとえば、ファイルの拡張子とアプリケーションを結びつけたら、そのファイルを選択するだけで、プログラムを動かすことができる。 実際には、ファイルをダブルクリックしたら、Windows は、関連づけられたプログラムを開始し、選択されたファイルをコマンドライン・パラメータとして渡す。
 
Here is the complete source code of the project (a DPR file, not a PAS file):
 
プロジェクトの完全なソース( PAS ではなく、DPR ファイルになっている)は、
 
program Strparam;
 
uses
 Windows;
 
begin
 // show the full string 文字列全部を表示
 MessageBox (0, cmdLine,
  'StrParam Command Line', MB_OK);
 
 // show the first parameter 最初のパラメータを表示
 if ParamCount > 0 then
  MessageBox (0, PChar (ParamStr (1)),
   '1st StrParam Parameter', MB_OK)
 else
  MessageBox (0, PChar ('No parameters'),
   '1st StrParam Parameter', MB_OK);
end.
 
The output code uses the MessageBox API function, simply to avoid getting the entire VCL into the project. A pure Windows program as the one above, in fact, has the advantage of a very small memory footprint: The executable file of the program is about 16 Kbytes.
 
VCL を使わないで済むよう、MessageBox API 関数を使って、表示させている。 このような、純粋な Windows プログラムの利点は、使用メモリが実に小さくできることだ。 この実行ファイルは、僅か 16 KB しかない。
 
To provide a command-line parameter to this program, you can use Delphi's Run > Parameters menu command. Another technique is to open the Windows Explorer, locate the directory that contains the executable file of the program, and drag the file you want to run onto the executable file. The Windows Explorer will start the program using the name of the dropped file as a command-line parameter. Figure 9.3 shows both the Explorer and the corresponding output.
 
コマンドライン・パラメータをこのプログラムに提供するには、Delphi の 実行 > パラメータメニューコマンド、を使えばよい。 Windows Explorer を開き、実行可能ファイルが納められているディレクトリに移動し、実行可能ファイルに、希望のファイルをドラッグしても良い。 Windows Explorer は、ドロップされたファイル名を、コマンドライン・パラメータとして使い、プログラムをスタートさせる。 図 9.3. で、Explorer とその結果とを示す。
 
Figure 9.3: You can provide a command-line parameter to the StrParam example by dropping a file over the executable file in the Windows Explorer.
 
図 9.3 : Windows Explorer で、ファイルを実行可能ファイルにドロップし、StrParam にコマンドライン・パラメータを渡すことができる。
 
Conclusion
 
結論
 
In this chapter we've seen a low-level introduction to Windows programming, discussing handles and a very simple Windows program. For normal Windows programming tasks, you'll generally use the visual development support provided by Delphi and based on the VCL. But this is beyond the scope of this book, which is the Pascal language.
 
この章では、低レベルの Windows プログラミングについて、基本的なことを取り扱い、ハンドルと、非常にシンプルな Windows プログラムを検討した。 一般的な Windows プログラミング・タスクでは、Delphi が提供する、VCL をベースにしたビジュアル開発環境を使うだろう。 しかし、これは Pascal 言語を扱っている、この文書の範囲を超えてしまう。
 
Next chapter covers variants, a very strange addition to Pascal type system, introduced to provide full OLE support.
 
次章では、OLE を完璧にサポートするため、Pascal 型システムに加えられた、非常に奇妙な要素、バリアントを扱う。
 
Next Chapter: Variants
 
次章 : バリアント
 
c Copyright Marco Cantu, Wintech Italia Srl 1995-2000
 
 
戻る