Delphi Tips 
-----------------------------

キーワード:すべて

>> Index

01/12 ファイルを作らずメモリ上で動作する TTable コンポーネント
10/02 DataSet を指定していないときに QuickReport の進捗状況を表示する
01/22 短いファイル名を長いファイル名に変換したい(COM版)。
12/31 リンクファイルから参照先のファイル名を得る
12/08 SubDetailが印刷できない
10/15 EXE ファイルのスリム化
07/05 デバッグ中にコード特定部分で発生する例外を無視する
02/08 リソースにあるバージョン情報を取得したい。
06/20 システムメニューに項目を追加/削除したい
03/04 自作アプリにスペルチェックの機能をつけたい
03/04 マウスがコントロールから出たことを検知する
03/04 正規表現の使える検索・置換えライブラリ
03/04 ブレークポイントで停止したときに IDE がアクティブにならない
03/04 エディットコントロールで右寄せ表示
03/04 フォームの最小化時のアニメーション効果を出す(BCB)
03/04 コンパイラを識別するための定義済みシンボル
03/04 春分、秋分、夏至、冬至の求め方
11/21 子プロセス(DOS)の標準出力をパイプする
10/02 二重起動防止措置で既存プロセスを最前面に送る
09/24 Delphi7 のコンボボックスの空文字列でエラー
08/22 非ビジュアルコンポーネントの Left, Top 座標を取得
08/22 プロパティ値を文字列に変換/逆変換
07/24 集合型変数の内部構造が知りたい/数値として処理したい。
07/18 スクリーンセーバーの作り方
07/10 浮動小数点数を整数に丸めるときの注意
06/27 Delphi によるレジストリの操作方法
06/27 ファイルの更新日時を得る
06/27 システムアイコンをリフレッシュする
06/27 コントロールパネルを作る
06/27 全てのウィンドウを最小化する
06/27 コンボボックスにブラウザのURL入力のような自動補完機能を付けたい
06/27 TMemoで、先頭行/最終行/指定行へ移動する。
06/25 「アドレス????????でエラーが発生」からエラー位置を知る
06/25 Delphi の格言
06/25 OnDblClick発生時にOnMouseDownはいらない!
06/25 ComboBoxのDropDownListの幅を変更する
06/25 自己実行形式の動画
06/25 フォルダもファイルも選べるダイアログ
06/25 Ini ファイルに published プロパティを保存する方法
06/25 ボタン間を矢印キーで移動させるロジック
06/25 RichEdit を印刷したい
06/25 Install Shield Express でアンインストール時にレジストリを削除できない
06/25 ActiveX でショートカットキーが使えない
06/25 DLL にブレークポイントが設定できない
06/25 FindFirst でアイコンを変更したディレクトリを検索できない
06/25 FindFirst による4文字以上の拡張子の判別
05/17 Photoshop のようなツールウィンドウを実現したい
05/17 HTMLタグ表記の大文字・小文字変換を行う
05/17 文字列から括弧の中のみを削除する
05/17 列挙型(Enum)の値と文字列との変換
05/17 TIdentToInt型とTIntToIdent型
05/17 2つの TMemo のスクロールを同期させる
05/17 2つの TRichEdit のスクロールを同期させる
05/17 文字列や画像データをリソースに埋め込むためのコンポーネント
05/17 ActiveX 内部から自身の親ウィンドウのハンドルを得る
05/17 OnShow イベント中で SetFocus すると不具合
05/17 異なるバージョンのDelphiを1つのPCに共存させる
05/17 TreeView で D&D 中の描画処理
04/04 国際化アプリケーションの作り方
02/09 TListView の ... 表示をなくす
12/27 VBのMIDステートメント
06/11 ListView をスクロールする
06/06 <Delphi Install Dir>\BINディレクトリの中のファイル
06/02 フォームの新規作成のデフォルトを変更したい
06/02 トークンの切り出し
05/14 ディレクトリのファイルを列挙する
04/05 Oracle の Number 型で入力値が化ける
04/05 メモリマネージャのマルチスレッド対応 -- IsMultiThread
04/05 スレッドローカル変数 -- threadvar の使い方
09/08 整数値が奇数かどうかの判定
08/25 ComCtl32.DLL を配布するには
08/12 Dual CPU 機でフォームのフォントに不具合
06/01 色表現について(RGB, HSV, YUV など)
05/26 DLLの初期化・終了処理
04/06 Currency型の小数演算結果が不正
03/28 C++Builder でwith文の代用
03/28 あるアドレスを基点とした、変位のアドレスの参照
01/02 TField.EditMask の y2k 回避
01/02 StringGrid の内容更新を高速に行う
12/28 Windows2000の新APIを使った半透明ウィンドウ
12/22 フォームを1つずつ表示する
12/21 ランダムなレコードの移動
11/30 スクリーンセーバーの名前を変更する。
11/16 INI ファイルを扱うもう1つのクラス
10/14 終了処理の中の例外を見逃すな !
10/12 Pascal 版 auto_ptr -- Free の必要の無い高機能ポインタ
10/07 System ユニットの _ で始まる特殊ルーチンの呼び方
10/07 文字列リソースの編集ツール - 文字列テーブルエディタ
10/07 OnExit ハンドラで次にフォーカスを受け取るコントロールを知る
10/07 大きなソースブロックのコメントアウト
09/30 アクティブデスクトップを使って壁紙を変更
09/27 短いファイル名を長いファイル名に変換したい。
09/27 デスクトップにあるアイコンの数と位置を知りたい。
09/27 アップリケーションにサウンドリソースを埋め込んで使いたい。
09/27 入力された漢字のひらがなを取り出す
09/27 エクスプローラからファイルをドラッグ&ドロップする
09/27 アプリケーションを常駐させてタスクトレイに登録したい
09/26 ファイルを削除してゴミ箱に移動させたい。
09/25 TSaveDialogでファイルタイプが変更されたらファイル拡張子を変更したい
09/24 Windows 特殊フォルダの Class ID List
09/24 TOpenDialog(TSaveDialog) の初期フォルダをシステムフォルダ(デスクトップなど)に設計する
09/24 TOpenDialogで、Executeメソッド実行時に表示位置を変えたい。
09/23 シェルのデスクトップやマイコンピュータをプログラムから開きたい。
09/23 TOpenDialogが表示された時のフォーカスを変えたい。
09/22 長いファイル名を短いファイル名に変換したい
09/21 Delphi4 で TBitmap を pf1bit で使うときの注意点(不具合回避)
09/21 TListを特定のクラスのListにする方法
09/20 エクスプローラのように、アプリケーションにブラウザページをつくりたい。
09/20 フォームのアイコンをアニメーションにしたい
09/20 MDI等で二重起動を防止して新しいファイルを開く
09/19 二重起動の判定
09/19 簡易アプリケーション間通信
09/19 インターネット エクスプローラを起動したい/その情報を取得したい
09/19 Sqr()の結果が負になる!?
09/17 起動中のブラウザからURLを取得する/ブラウザにURLをセットする方法
09/16 StringGrid でセル編集終了のイベントを得たい
09/16 TStringGrid の列の ReSize イベントの取得
09/16 Pascal で文字列を効率良く扱う(例:文字列を逆順にする)。
09/15 漢数字で位取り表示
09/15 Win98 でタイトルバーのグラデーション色を得る
09/15 子に override されたメソッドを孫クラスから呼び出す
09/15 TRichEdit.Add でリソース不足
09/15 TPageControl に OnDblClick を追加する
09/15 TTreeView で5つ以上のオーバレイ・イメージを使う
09/15 Install Shield でアンインストール時にレジストリが掃除されない
09/13 TFontDialog で標準以外のサイズを選択肢に表示したい
09/11 Editコントロールで入力を数値専用にする
09/11 TMemo のキャレットを非表示にする
09/11 エディットコントロールにポップアップウィンドウをつけたい
09/09 文字列を TDateTime に変換する
09/09 経過日数を取得する
09/09 1時間後を取得する
09/09 Metafile が Draw で1ピクセル小さく描画される
09/09 TWebBrowser を使って HTML の描画イメージを取得する
09/09 DLL 内で TDBCtrlGrid を使うときの注意事項
09/09 サブネットマスク値など TCP/IP 関連パラメータを取得する
09/09 UDP 通信で NoParam ???
09/09 デフォルトプリンタの設定
09/09 TPageControl でタブをドラッグして順序入れ替え
09/08 任意のドライブをセクタ単位で読み書きする
09/08 IME に未確定文字列を入力
09/08 フォルダのタイムスタンプを変更する
09/08 Delphi3 でコンポーネントパレットを複数行にする
09/08 ショートカットキーに'+'を使う。
09/07 右寄せ・数値入力可能なEditコンポーネントを作りたい。
09/06 メッセージボックスを独自にカスタマイズしたものを使いたい。
09/06 Delphi 2.0/3.0でCPUウィンドウを出す
09/06 メインフォーム以外のフォームをタスクバーに入れたい。
09/06 APPのフォームを最小化して起動したい
09/06 メッセージボックスのデフォルトボタンを変えたい
09/06 ButtonのCaptionで改行を使って文字を複数段で表示したい
09/06 キーボードでボタンを押したとき、ボタンをちゃんと沈ませたい
09/06 カーソルキーでボタン(TButton)のフォーカス移動をやめさせたい
09/06 エディットコントロールにコンボボックスのようなボタンをつけたい
09/05 数値の2進数への変換で効率的な方法
09/05 ドッカブルメニュー(ツールバー形式のメニュー)を実現したい。
09/02 Windowsの「ファイルの検索」ダイアログをプログラムから使いたい
09/01 フォームの最小化、最大化をアニメーションでやりたい。(DELPHI)
09/01 RichEditでHTMLタグを色・書式付き表示をする
08/31 LinesプロパティエディタでTabを入力する
08/31 全角文字が半角文字の2倍幅になるフォントの選び方
08/31 RichEdit の全パラグラフのタブ幅を設定する
08/31 TRichEdit.Paragraph.Tab[] の設定(Tab位置の設定)
08/30 メインフォーム以外のフォームを最小化した時もAPP全体を最小化したい
08/30 Pascal 版の yacc & lex
08/28 データコントロールのDataLinkオブジェクトを取得する方法(ReadOnlyプロパティのバグの解決法)
08/26 ダイヤラを呼び出す。(TAPI32.DLLの使用)
08/26 他のアプリの起動パスを取得する
08/26 セルのテキストをドラッグイメ−ジにしてグリッド(TStringGrid)でドラッグ&ドロップを行う
08/26 ツリービューのノードをドラッグ&ドロップで移動させる
08/26 書式付きメモ型項目へアクセスしたい
08/23 デスクトップのウィンドウのタイトルとハンドルを取得する
08/23 プロセスの実行ファイル名を列挙する
08/23 Win95/98で、ウィンドゥハンドルから、実行アプリ名を知る
08/23 WinNT でウィンドウハンドルから実行アプリ名を知る
08/21 クリップボードのフォーマットを知る
08/21 クリップボードが更新された時のイベントを取得する
08/19 インターネットエクスプローラのアドレス帳を呼び出す
08/17 PASCAL ソースの整形ツール
08/14 Delphi2/3.x における Cardinal 型の妙な定義
08/14 MS-Word 97 で作成した rtf ファイルがヘルプコンパイラでエラーを起こす
08/14 カスタムコントロールの子コントロールをオブジェクトインスペクタに表示させない
08/14 ショートカットキーのキー名を独自に設定する
08/14 Object Pascal のコーディングスタイル
08/13 TColor 値を文字列に変換する
07/28 HTML-Help を作りたい
07/14 基本的な階層プロパティ定義の例
07/09 @ 演算子の働き
07/07 CapsLock の状態を変更する
06/08 LhasaのようなUIを持つアプリケーションの作成方法
05/28 TFileListBox にファイル名が重複して表示されてしまう
05/19 コンボボックスのリスト部分の幅を指定する
05/19 独自メッセージとして自由に使える値の範囲
05/19 「送る」の 516 文字制限について
05/19 TRichEdit の内容を高速に変更する
05/14 文字数のカウント方法
05/14 システムカラーを得る、設定する
05/12 コードエディタで「キーボードマクロ」を使う
05/12 コードエディタで選択部分をまとめてインデントする
05/12 コードエディタで矩形領域を選択する
05/08 改行コードの違いについて
05/01 右の項目の幅が固定されるTStatusBar
04/29 TCoolBarを用いたツールバーの位置保存
03/21 アプリケーション間でデータの送受信(WM_COPYDATAを使う)
02/11 BCB で実行ファイルのサイズを小さくするには
02/11 IME 入力で読み仮名を取得する
02/11 デバッグ中に関数評価の戻り値をチェックしたい
02/11 フォームの破棄、生成を続けて行うときの注意事項
02/11 DBGrid のスクロールバーを非表示に
02/11 プログラムからプリンタのスプーラ表示を開く
02/11 カレントユーザのデスクトップディレクトリを得る
02/11 IniFile に書き込みを行った後にはバッファのクリアが必要
02/11 TFileStream で標準出力に表示
02/11 半角カナを確定無しで直接入力させる
02/11 CreateProcess を使うときは CloseHandle で後始末
02/11 ディスパッチインターフェイスとデュアルインターフェイスについて
02/11 デバッグ時にライブラリ内もステップ実行したい
02/11 マウスがクリックされた正確な時刻が知りたい
02/11 Delphi2 以上で Form の枠を黒線一本にするには
02/11 エクスプローラで使われるアイコンを取得・変更する
02/11 和暦を西暦に直したい
02/11 可変長レコードの扱い方
02/11 アプリケーションが最小化されているかどうかを判定する
02/11 クリップボードにコピーされたファイル・ディレクトリ
02/11 Form をスクロールして特定のコントロールを表示させる
02/11 プリンタのスプールファイルを TMetafile に読みこむ
02/11 長すぎる TreeView アイテムを補完するチップヘルプを出さなくする
02/11 リムーバブルドライブの種類を判別する
02/11 下の図柄がすける透明パネル
02/11 Bitmap のパレットに使いたい色を追加する
02/11 API を使って縦書きなどのフォントを指定する
02/11 表示中のポップアップメニューを消す
02/11 TSplitter をドラッグ中にヒント文字列が表示された時の不具合
02/08 リードオンリーファイルを Assign/Reset で読もうとするとエラーになる
02/08 Fortran のソースを C に変換するツール
02/08 TColor を RGB 値へ変換する
02/08 Delphi で DOS のアプリを書く方法
02/08 Delphi/CBuilder で作った DLL から VB に文字列を返す
02/08 コントロールパネルのスクリーンセーバの設定画面を表示させる
02/08 Windows95 のみを再起動する
02/08 ダイヤルアップネットワークで設定されている接続先を取得する
02/08 他プロセスの Window を GUI で選ばせたい
02/08 *.h ファイルから *.pas ファイルを作るコンバータ
02/08 任意の実行ファイルが DLL などからインポートしている関数の一覧を得る
02/08 実行終了後、自分自身(実行ファイル)を削除したい
02/08 メタファイルを wmf 形式でコピーするときの注意
02/08 超高速 ListView
02/08 ステータスバーにプログレスバーを置きたい
02/08 Glyphに張ったビットマップの背景がおかしくなる
02/08 中村さんありがとうシリーズ:ビットマップ・パレット編
02/08 デスクトップフォルダのパスを得る
02/08 Scaled/AutoScrollプロパティと実行時のフォームサイズ
02/08 起動時にフォームの表示・非表示を決める
02/08 TBitmap の Width/Height に 0 を代入すると例外が発生する
02/08 Bitmap から Icon を作る
02/08 CD-DA のデータを Wav ファイルに落としたい
02/08 複数プログラムから同一内容のメモリを参照/更新する
02/08 プログラムからWindowsのスタートメニューを表示する
02/08 SetWindowsExt/SetViewportExtを使うときの注意点
02/08 PopupMenu に MainMenu のサブ項目をそのまま表示する
02/08 親クラスのプライベートフィールドにアクセスする
02/08 OpenDialogでたくさんファイルを選択するとエラー
02/08 C++ の関数の親子関係をレポートするツール
02/08 スクリーンセーバーをプログラムから停止する
02/08 Delphi3のコード補完機能で選択肢をソートして表示させる
02/08 コードエディタで「しおり」を使う
02/08 Delphiアプリをマウスのホイールに対応させたい
02/08 ヘルプ作成用のホットスポットエディタ(SHED.EXE)の入手方法
02/08 「システムエラー 読み出せません ドライブ X:」ダイアログを回避する
02/08 StringGrid で マウスのある Cell 内容に応じた Hint を出したい
02/08 自作コントロールで IME 入力時の変換候補をキャレット位置に表示したい
02/08 TDDEClientConvで最初の行しか実行されない?
02/08 TUpDown の不具合
02/08 Delphi1/2で状況依存型のコンポーネントヘルプを作るときの注意
02/08 time_t を TDateTime に変換する
02/08 TPageControl を TabPosition=tpBottom にすると不具合
02/08 TBitmap をきれいに印刷する
02/08 アプリケーションアイコンの変更が反映されない
02/08 クイックレポート関連記事
02/08 BCB3 のバージョン情報でキー名が日本語だと不具合
02/08 起動したアプリケーションの終了待ち
02/08 BCB1 から BCB3 へ移動したプロジェクトでのプリコンパイルヘッダ利用
02/08 最新版クイックレポート(英語)の日本語化
02/08 親の published プロパティを子クラスで隠蔽する
02/08 NT のタスクマネージャにアプリケーションのアイコンが表示されない
02/08 QuickReport で Canvas プロパティを使う
02/08 DDeClientConv を使ってスタートメニューにアイコンを登録
02/08 DLL のロード・アンロードでメモリリーク?
02/08 サブフォームがアクティブな時はメインフォームのアクセラレータキー・ショートカットキーを無効にしたい
02/08 用紙の印刷可能範囲を求める
02/08 超高速タイマーコンポーネント(サブミリ秒)
02/08 スタートメニューを任意の位置にポップアップさせる
02/08 MS-Access97 に接続できない
02/08 Delphi1.0でHugeポインタを使う
02/08 IDEのコードエディタのデフォルトサイズを変更する
02/08 アイコン状態で起動するアプリ
02/08 Windowsの「ファイルの検索ダイアログ」を表示させる
02/08 StringGridで選択セルのハイライト表示を無くしたい
02/08 関数のパラメータを省略可能にしたい
02/08 TLabelのFontがイタリックだと、AutoSize=Trueで右端が切れる
02/08 Delphi1.0のDirectoryListBoxが全角英文字のディレクトリ名で動作不良
02/08 Delphi3 の TStringList.CommaText の不具合
02/08 TIniFileにクオートを含む文字列を与えるときの注意点
02/08 Internetコンポーネントが他のマシンで動かない
02/08 自作アプリで作ったオブジェクトを他のアプリに貼り付けたい
02/08 Visual C++ と Delphi で Exe/DLL のやり取り
02/08 フォームの印刷時にComboBoxの内容が印刷されない
02/08 Delphiのインラインアセンブラで MMX コードを使いたい
02/08 COMCTL32.DLLのバージョンについて
02/08 Delphi3.1でオブジェクトインスペクタの表示がおかしい
02/08 DelphiのバグをBorlandに報告する
02/08 TrueTypeフォントからベクタ情報を得る
02/08 oDelphi1.0とDelphi2.0/3.0でコンポーネントのソースを共有したい
02/08 TDriveComboBoxの内容の更新
02/08 TMemoで入力*行数*を制限したい
02/08 設計時にフォームがエラーで読み込めず変更もできない
02/08 TListViewで列を指定してソート
02/08 文字列の切り分け
02/08 TStringGridのソート
02/08 StringGrid/DBGrid でのセル編集の動作を細かく指定する
02/08 32bitアプリから16bit DLLを呼び出す
02/08 complib.dllが壊れた!また全部のコンポーネントをインストールするの?!
02/08 New/Dispose に Pointer 型のポインタを渡すと。。。
02/08 Delphi3.0でDLLにバージョン情報が入らない
02/08 Delphi 1.0 (16bit)で、物理メモリアドレスに直接アクセスする
02/08 NTで他のアプリが開いているファイルを知る

最終更新: 3546 日前

0129  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2007/01/12 RAN 編集
ファイルを作らずメモリ上で動作する TTable コンポーネント

>前どこかで TTable 互換でメモリ上で動作するコンポーネントを見かけたのです
>が、ご存知な方いらっしゃいませんか? (その時にダウンロードしておけばよかっ
>た...)

[1]

Delphi Super Pageに昔からあるコンポーネントです。
BDEのインメモリテーブルと一時テーブルの機能を使ったものです。

http://sunsite.icm.edu.pl/delphi/
(2007年現在はhttp://delphi.icm.edu.pl/authors/a0000561.htm に移動)
ファイル名:inmemory.zip および inmem32.zip
※サンプル付きです。

Delphi1.0用のほうを、Delphi3で使用するときの修正点は以下のとおりです。32ビット版が出ているのでもう必要無いのかな?
#Inmemユニット:
#  TypeMapで配列の最後に「, fldCURSOR」を追加。
#  SubTypeMapで配列の最後に「, 0」を追加。
#TempTblユニット:
#  TypeMapで配列の最後に「, fldCURSOR」を追加。
#  SubTypeMapで配列の最後に「, 0」を追加。
※Register手続きがありませんので、追加してください。

>これがあればテンポラリのテーブルをいちいちディスクに作成しなくても済んで
>しまうため(結果的に作られるとしても)、便利なのですが...

 そうなんですが、デバッグのとき、値を確認しにくいと思いますよ。

[2]

> ひょっとして http://delphideli.com/dlnbde.htm にある TMemTable のことでしょうか。

僕が前見たのは確かシェアウエアだったのですが、これはフリーでしかもソース付き。嬉しい限りです。

[3]

最近のDelphi では標準でMyBase が利用できます。
http://hp.vector.co.jp/authors/VA028375/delphi/db.html が分かりやすいです。
参照: [Delphi-ML:22981] [Delphi-ML:22983] <データベース> <DataAccess> <コンポーネント >

0150  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2006/10/02 223 編集
DataSet を指定していないときに QuickReport の進捗状況を表示する

> 今回作ったレポートだと TQuickRep.DataSet:=nil で、 OnNeedDataイベ
> ントですべてのデータを供給しているので、プログレスフォームに進捗
> を表示してくれません。
> 実行時には出力すべきレコード数と現在出力中のレコード番号は分かっ
> ています。こういうときに、うまくプログレスフォームで進捗を表示し
> てあげる方法は用意されていないのでしょうか?

QuickRep.QRPrinter.Progress プロパティに 0..100 の範囲の値を指定すると良さそうです。

procedure QuickRep1.DetailBand1AfterPrint(Sender: TQRCustomBand;
  BandPrinted: Boolean);
begin
  QrPrinter.Progress:=Trunc((100/MaxBandCount)*BandCount);
end;

MaxBandCount: 最大レコード数
BandCount: 現在のレコード
参照: [Delphi-ML:25304] <印刷>

0273  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/24 西坂良幸 rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2006/01/22 <> 編集
短いファイル名を長いファイル名に変換したい(COM版)。

エクスプローラは内部的には、短い名前を使っているようです。
ということは、シェルのCOMインターフェースのメソッドが使えるということです。
[Tips:233]のCOM版を考えてみましょう。

uses ShlObj,Comobj,ActiveX;

function ShortToLongFileName(const ShortName: string): string;
var
  Desktop: IShellFolder;
  pIDList: PITEMIDLIST;
  NameS: String;
  NameW: WideString;
  Len : integer;
  Buffer: array[0..MAX_PATH] of Char;
  // 以下は値は使わない
  pDummy: PCHAR;
  pchEaten, Attributes: ULONG;
begin
  pIDList := Nil;
  // フルパス化
  Len := GetFullPathName(PChar(ShortName), 0, PChar(result), pDummy);
  SetLength(NameS, Len);
  GetFullPathName(PChar(ShortName), Len, PChar(NameS), pDummy);
  // ワイド文字列に転換
  NameW := NameS;
  // IShellFolderを生成(解放は自動)
  OleCheck(SHGetDesktopFolder(Desktop));
  // IDリストをえる
  OleCheck(Desktop.ParseDisplayName(0, Nil, PWideChar(NameW), pchEaten, pIDList, Attributes));
  if not SHGetPathFromIDList(pIDList, Buffer) then
  raise EConvertError.Create('ファイルを変換できません。');
  Result := StrPas(Buffer);
end;


WideStringを使うことを覗けば、IShellFolderのParseDisplayNameメソッドとSHGetPathFromIDList
を使うだけです。[Tips:233]よりすっきりしましたか。

※ 使用できるOS、バァージョンに注意して下さい。
参照: [Delphi-ML:7322] <その他Windows関連> <Windows> <ファイル> <PASCAL>

0099  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2005/12/31 長山 編集
リンクファイルから参照先のファイル名を得る

IShellLinkを使用すれば出来ます。

    CoInitialize(NULL);

    HRESULT HR;
    IShellLink *psl;
    IPersistFile *ppf;
    WideChar wsz[MAX_PATH];
    char szGotPath[MAX_PATH];
    WIN32_FIND_DATA wfd;

    HR = CoCreateInstance(CLSID_ShellLink, NULL,
                CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
    if(SUCCEEDED(HR)){
        HR = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
        if(SUCCEEDED(HR)){
            MultiByteToWideChar(CP_ACP, 0, "ショートカット.lnk", -1,
                    wsz, MAX_PATH );
            HR = ppf->Load( wsz, STGM_READ );
                if(SUCCEEDED(HR)){
                    HR = psl->Resolve(Application->Handle, SLR_ANY_MATCH);
                    if(SUCCEEDED(HR)){
                        HR = psl->GetPath(szGotPath, MAX_PATH,
                                (WIN32_FIND_DATA *)&wfd, SLGP_SHORTPATH );
                        Edit2->Text = szGotPath;
                    }
                }
            }
            ppf->Release();
        }
        psl->Release();
    }
    CoUninitialize();



Delphi翻訳版 (関数です)

uses
  Windows, SysUtils, ShlObj, ActiveX, ComObj;
  
const IID_IPersistFile: TGUID= (D1:$0000010B;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46));

function ExtractStringFromLinkFile( Target:TFileName ): String;
var
    R   : HRESULT;
    SL  : IShellLink;
    PF  : IPersistFile;
    Wrk : array[0..MAX_PATH] of WideChar;
    Path: array[0..MAX_PATH] of Char;
    WFD : WIN32_FIND_DATA;
begin
    Result := '';
    CoInitialize( NIL );

    R := CoCreateInstance( CLSID_ShellLink, NIL, CLSCTX_INPROC_SERVER, IID_IShellLinkA, SL );
    if Succeeded( R ) then
    begin
        R := SL.QueryInterface( IID_IPersistFile, PF );
        if Succeeded( R ) then
        begin
            MultiByteToWideChar( CP_ACP, 0, PChar(Target), -1, Wrk, MAX_PATH );
            R := PF.Load( Wrk, STGM_READ );
            if Succeeded( R ) then
            begin
                R := SL.Resolve( 0{Application.Handle}, SLR_ANY_MATCH );
                if Succeeded( R ) then
                begin
                    SL.GetPath( Path, MAX_PATH, WFD, SLGP_SHORTPATH );
                    Result := Path;
                end;
            end;
        end;
    end;

    CoUninitialize;
end;
参照: [builder:5475] <ShellApi> <Windows> <ファイル>

0357  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2005/12/08 三輪一雄 rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2005/12/08 <> 編集
SubDetailが印刷できない

QRBandでBandTypeをrbSubDetailに設定しても、テーブルのフィールドが印刷されません。この方法で作成するとDataSetを指定するプロパティーがありません。
必ずQRSubDetailでバンドを作成します。
参照: <QReport> <コンポーネント > [d DelphiML]

0302  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2000/06/01 osamu rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2005/10/15 nameless <> 編集
EXE ファイルのスリム化

.exe ファイルを圧縮しておき、実行時に自動的に解凍することで、.exe ファイルを小型化することの出来るソフトがいくつか出回っています。フリーソフトでは ezip, upx、商用ソフトでは aspack というものが有名なようです。

ezip>
        http://web.archive.org/*/http://www.jonathanclark.com/ezip/ezip.exe

upx>
    http://upx.sourceforge.net/

aspack>
    http://www.entechtaiwan.com/aspack.htm

圧縮ではなく、W32 PE EXE ファイルのの 'reloc' セクションを削除してしまう方法もあります。reloc が無くても EXE はメモリー空間に Windows のローダがチャンと割り付けてくれます。(DLL は削除してはいけません)

StripReloc>
    http://www.jrsoftware.org/striprlc.htm
参照: <開発環境> <アプリケーション> <配布>

0333  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2005/07/05 <> 編集
デバッグ中にコード特定部分で発生する例外を無視する

例外をデバッガが受け取るようにした場合、try except でハンドルしている既知の例外で頻繁に実行が止まってしまい困る場合があります。

コードの特定部分で発生する例外をデバッガに無視させるには、その範囲の前後にブレークポイントを仕掛けて、右クリック-[ブレークポイントの設定]-[拡張]で[ブレーク]のチェックを外し、それぞれ[この後の例外を無視する][この後の例外を処理する]のチェックを入れると良いです。
参照: [Delphi-ML:73061] <開発環境> <デバッグ>

0226  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/29 西坂良幸 rev 1.5
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2005/02/08 <> 編集
リソースにあるバージョン情報を取得したい。

Delphiのメニュー[プロジェクト|オプション]のバージョン情報ページのデータはリソースとして製作したアプリケーションの EXE ファイルの中にあります。バージョン情報ダイアログのバージョン番号は、是非このリソースの内容を反映させたいですね。

この方法は、多くの書物に書かれているようですが、ML でも多い話題です。
自作のダイアログをつくり、リポジトリに登録しておきましょう。
コンポーネント化するのもひとつの方法です。
  
VerQueryValue 関数の第二パラメータに、 '\' をつかって バージョン番号を取得する方法は [Delphi-ML:31478] で紹介しています。
 
ここでは、すべてのバージョン情報を取得する関数を紹介します。

type
  TVerResourceKey = (
        vrComments,         // コメント
        vrCompanyName,      // 会社名
        vrFileDescription,  // 説明
        vrFileVersion,      // ファイルバージョン
        vrInternalName,     // 内部名
        vrLegalCopyright,   // 著作権
        vrLegalTrademarks,  // 商標
        vrOriginalFilename, // 正式ファイル名
        vrPrivateBuild,     // プライベートビルド情報
        vrProductName,      // 製品名
        vrProductVersion,   // 製品バージョン
        vrSpecialBuild);     // スペシャルビルド情報

const
  KeyWordStr: array [TVerResourceKey] of String = (
        'Comments',
        'CompanyName',
        'FileDescription',
        'FileVersion',
        'InternalName',
        'LegalCopyright',
        'LegalTrademarks',
        'OriginalFilename',
        'PrivateBuild',
        'ProductName',
        'ProductVersion',
        'SpecialBuild');

// バージョン情報を取得
function GetVersionInfo(KeyWord: TVerResourceKey): string;
const
  Translation = '\VarFileInfo\Translation';
  FileInfo = '\StringFileInfo\%0.4s%0.4s\';
var
  BufSize, HWnd: DWORD;
  VerInfoBuf: Pointer;
  VerData: Pointer;
  VerDataLen: Longword;
  PathLocale: String;
begin
  // 必要なバッファのサイズを取得
  BufSize := GetFileVersionInfoSize(PChar(Application.ExeName), HWnd);
  if BufSize <> 0 then
  begin
    // メモリを確保
    GetMem(VerInfoBuf, BufSize);
    try
      GetFileVersionInfo(PChar(Application.ExeName), 0, BufSize, VerInfoBuf);
      // 変数情報ブロック内の変換テーブルを指定
      VerQueryValue(VerInfoBuf, PChar(Translation), VerData, VerDataLen);
      if not (VerDataLen > 0) then
        raise Exception.Create('情報の取得に失敗しました');
      // 8桁の16進数に変換
      // →'\StringFileInfo\027382\FileDescription'
      PathLocale := Format(FileInfo + KeyWordStr[KeyWord],
        [IntToHex(Integer(VerData^) and $FFFF, 4),
         IntToHex((Integer(VerData^) shr 16) and $FFFF, 4)]);
      VerQueryValue(VerInfoBuf, PChar(PathLocale), VerData, VerDataLen);
      if VerDataLen > 0 then
      begin
        // VerDataはゼロで終わる文字列ではないことに注意
        result := '';
        SetLength(result, VerDataLen);
        StrLCopy(PChar(result), VerData, VerDataLen);
      end;
    finally
      // 解放
      FreeMem(VerInfoBuf);
    end;
  end;
end;

// テスト
procedure TForm1.Button1Click(Sender: TObject);
begin
  Label1.Caption := GetVersionInfo(vrFileVersion);
  Label2.Caption := GetVersionInfo(vrLegalCopyright);
end;


参照: [Delphi-ML:31478] [Delphi-ML:37794] <アプリケーション> <開発環境> <ダイアログ>

0065  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2004/06/20 kakken 編集
システムメニューに項目を追加/削除したい

海外製のコンポーネントですがこういうのがあるそうです(ソース付だそうだ)
http://www.torry.ru/vcl/menus/ksysmenu.zip

実際にやってみましょう。まず削除です。
デファウルトでシステムメニューはこのようになっています

+−−−−−−−−−+
|元のサイズに戻す  |
|移動              |
|サイズ変更        |
|最小化            |
|最大化            |
|−−−−−−−−−|
|終了              |
+−−−−−−−−−+

// 上の例から移動と、終了だけ残します。
procedure TForm1.Button1Click(Sender: TObject);
var
    hSysMenu:integer;
begin
    hSysMenu := GetSystemMenu(Handle,False);
    DeleteMenu(hSysMenu, 0, MF_BYPOSITION);
    DeleteMenu(hSysMenu, 1, MF_BYPOSITION);
    DeleteMenu(hSysMenu, 1, MF_BYPOSITION);
    DeleteMenu(hSysMenu, 1, MF_BYPOSITION);
end;

MF_BYPOSITION を指定した時は、第二パラメータで位置を0..で指定します。
削除ごとに位置が変わることに注意して下さい。
MF_BYCOMMAND を指定した時は  SC_SIZE、SC_MOVE、SC_MINIMIZE、SC_MAXIMIZE、SC_CLOSE などでメニューを特定します。

次に追加です。
const
    NewMenu1_Command = 10;  // この値は重複しないように任意
    NewMenu2_Command = 11;
procedure TForm2.Button1Click(Sender: TObject);
var
    hSysMenu:integer;
begin
    hSysMenu := GetSystemMenu(Handle,False);
    // 底に(最後に)追加する
    // セパレータを追加
    AppendMenu(hSysMenu, MF_SEPARATOR,0,nil);
    // 'NewMenu_1'を追加
    AppendMenu(hSysMenu, MF_STRING, NewMenu1_Command, 'NewMenu_1');
    // セパレータ(位置=1)の上の挿入
    InsertMenu(hSysMenu, 1, MF_BYPOSITION or MF_STRING, NewMenu2_Command, 'NewMenu_2');
end;


Const で定義した値が、TMenuItemで、Commandプロパティにあたるものです。
でも、これだけでは、表示されるだけです。追加した項目をクリックしたらイベントハンドラを呼び出さねばなりません。
(ここでは、イベントハンドラではなく、メッセージボックスで代用)それには、WM_COMMANDメッセージを捕まえます。
procedure WMCOMMAND(var msg: TWMSysCommand);message WM_COMMAND;
を、フォームのPrivateに定義して、

procedure TForm1.WMCOMMAND(var msg: TWMSysCommand);
begin
    case Msg.CmdType of
        NewMenu1_Command: ShowMessage('NewMenu_1が押されました');
        NewMenu2_Command: ShowMessage('NewMenu_2が押されました');
    end;
    inherited;
end;

ですね。

たくさん作るときは、TPopupMenuを貼り付け、TMenuItemを作成してこのCaption、Command、OnClickなどのプロパティを利用した方が簡単です。
参照: [Delphi-ML:19712] [Delphi-ML:42000] <メニュー>

0046  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2004/03/04 osamu 編集
自作アプリにスペルチェックの機能をつけたい

Spell Checker(辞書付き)というコンポーネントが、http://www.cs.monash.edu.au/~vtran/にあります。
Delphian World MLの過去ログにこれに関する話題があるそうです。
http://www.delphianworld.com/
参照: [Delphi-ML:19276] <文字列> <PASCAL>

0101  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2004/03/04 osamu 編集
マウスがコントロールから出たことを検知する

マウスカーソルがコントロールに入ったり、出たりする瞬間を捕らえる方法です。

CM_MOUSEENTER/CM_MOUSELEAVE メッセージを使う方法
    [Delphi-ML:9631]

マウスの出入りを検出できるコンポーネントを作ってしまう方法
    [Delphi-ML:9645]

アイドル処理で、検出する方法
    [Delphi-ML:9820]

等が有ります。
9631 はフォームに直接貼り付けられたコントロールにしか使えないので注意して下さい。

コントロールをサブクラス化するコンポーネントを使っても簡単にできるかもしれません。
    http://www.delphianworld.com/direct.html?id=SY0054
SubClassVCL というやつです。
参照: [Delphi-ML:14031] <コンポーネント > <その他コンポーネント関連>

0119  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2004/03/04 osamu 編集
正規表現の使える検索・置換えライブラリ

正規表現を使った文字列探索/操作 : Rexp016.lzh
Perl 互換正規表現ユニット : BRegExp.lzh

DLは Delphian World で、
http://www.delphianworld.com/direct.html?id=MI0036

それか、この手のDLLがいろいろありますからそれらを使うという手がラクだと思います。

VWXW.DLL(Wz Editorで使われている)
作者のM.Ishidaさんのページ
http://www2h.meshnet.or.jp/~ishida/

jre.dll(秀丸エディタで使われている)
http://www.yamada-labs.com/software/spec/jre/

basp21.dll
http://www.hi-ho.ne.jp/babaq/
参照: [Delphi-ML:22272] <文字列> <PASCAL>

0146  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2004/03/04 osamu 編集
ブレークポイントで停止したときに IDE がアクティブにならない

 Windows98 に移行してから、ブレークポイントで停止したときの挙動が変わりました。
フォーカスがDelphi IDE に移らず、デバッグ中のプログラムに残ったままなのです。
これを改善するためのエキスパート focusmgr.zip が、Delphian World
http://www.delphianworld.com/ で入手可能です。

(別件)
win.ini ファイルを編集することでも対応できます。
このファイルの[Compatibility95] セクションに(なければ追加し)、
  DELPHI32=0x00000002
と記述するだけです。
こちらについての詳細は、以下をご覧ください。
  Microsoft のサポート技術情報
   W98:メッセージボックスがデスクトップの背後に隠れる
   文書番号: J044951
参照: [Delphi-ML:24961] [Delphi-ML:25050] <開発環境> <バグ>

0204  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/16 osamu rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2004/03/04 osamu 編集
エディットコントロールで右寄せ表示

>TEditで表示したい内容が数字なため右寄せにしたいと
>思っています。しかし、調べた限りでは右に寄ってく
>れません。

Delphian World などで既存のコンポーネントを入手するのが一番楽チンですね。( http://www.delphianworld.com/ )

自分で作る場合:
Win98とそれ以前のWinとでは作り方が異なります。
これはWindows98が右寄せEditをサポートしたからです。
『Win98で右寄せ・数値入力可能なEditコンポーネントを作る』
というTipsを参照ください。
こちらでは簡単に完璧に右寄せEditが作れませす。

Win98以前のWinでは
Editの代わりにTMemoを使い、1LineのTMemoをEditに見せかけます。

TMemoを配置して
1、Alignment Property を taRightJustify にする。
2、WordWrap Property を False にする。

WantReturns Property を False にして改行を入力させないようにしても
Ctrl+JやCtrl+Returnを押すと改行コードが入力されてしまいます。
そこで改行された時に改行を解除する動作をコーディングします。
procedure TForm1.Memo1KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  SelStartBuf: Integer;
  S: string;
begin
  if Memo1.SelLength>0 then exit;

  SelStartBuf := Memo1.SelStart;
  S := Memo1.Text;

  if pos(#13,S)<>0 then//改行コードのCRを削除
  begin
      Delete(S,pos(#13,S),1);
      Dec( SelStartBuf );
  end;
  if pos(#10,S)<>0 then
  begin
      Delete(S,pos(#10,S),1);//改行コードLFを削除
      Dec( SelStartBuf );
  end;

  Memo1.Text := S;
  Memo1.SelStart :=  SelStartBuf;
(*
また、TMemoを右寄せにしているとWordWrap:=falseが効果ありません。
文字が増えるとどうしても改行されてしまいます。
それに対応して改行されたらその時の文字数を保持して左寄せに変えます。
LengthShowはFormのメンバーとして変数宣言してください。
*)
  if Memo1.Lines[1]<>'' then//改行されたなら
  begin
    SelStartBuf := Memo1.SelStart ;
    Memo1.Alignment := taLeftJustify;
    Memo1.SelStart := SelStartBuf;
    LengthShow := Length(Memo1.Lines[0]);//LengthShow変数に
  end;//表示可能文字数を保持
(*
文字数が減ったら元に戻さなければいけません。
*)
  if LengthShow<>0 then//LengthShowに保持数があるなら
    if Length(Memo1.Lines[0])<LengthShow then//文字が減ったら
    begin
      SelStartBuf := Memo1.SelStart;
      Memo1.Alignment := taRightJustify;
      Memo1.SelStart := SelStartBuf;
    end;
end;//KeyUpイベント終わり

単純に、改行された時の文字数=表示の限界、とみなして
その文字数以下になれば右寄せに変えるという動作ですので
プロポーショナルフォントの場合では文字幅が異なりますのでちょっと変な動作になりそう。
また、左寄せの状況で文字を削除していくと左寄せという事がばれる動作をします。
更に、キー入力以外でテキストを代入するような動作は考慮していません。

その辺は、自分で作ってね。出来たら、このTipsを更新してくだされ。
参照: [Delphi-ML:9195] [Delphi-ML:41622] <コンポーネント > <Standard>

0057  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2004/03/04 osamu 編集
フォームの最小化時のアニメーション効果を出す(BCB)

BCBで作成したアプリだけは、他のアプリと異なり、Win95で「アイコン化」したときなどのタイトルバーのアニメーション(タイトルバーがひゅるるっとタスクバーに吸い込まれるようなアレ)が出ないようなのですが、これはBCBの仕様なのでしょうか?あるいは出す方法があるとか??
  Delphiでもそうですよ!!

 これは、BCB が使用しているライブラリ VCL の仕様のようです。

 アニメーションを実現するには、プログラムを組む必要がありますが、(別項でDELPHIでのコード例を見て下さい)
既にこのようなコンポーネントが発表されています。

http://www.delphianworld.com/direct.html?id=SY0042

TAnimateWindowというのがそれのようです。
参照: [Delphi-ML:34432] [builder:4884] <Windows> <フォーム>

0086  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.7
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2004/03/04 osamu 編集
コンパイラを識別するための定義済みシンボル

Pascal コンパイラの バージョン識別子です。
  http://3932.rapidforum.com/topic=100288647371
  http://www.adug.org.au/Reference/VersionSymbols.htm
  http://www.blong.com/Tips/KylixTips.htm
及び[Delphi-ML:67458]より。

Compiler                  Symbol   System  Symbol   BCB?
Turbo Pascal 4            Ver40    DOS       -
Turbo Pascal 5.0          Ver50    DOS       -
Turbo Pascal 5.5          Ver55    DOS       -
Turbo Pascal 6.0          Ver60    DOS       -
Turbo Pascal for Win 1.0  Ver10    Win16    ???
Turbo Pascal for Win 1.5  Ver15    Win16    ???
Borland Pascal 7          Ver70    ???      ???
Delphi 1.0                Ver80    Win16   Windows
Delphi 2.0x               Ver90    Win32   Win32
C++ Builder 1             Ver93    Win32   Win32    BCB
Delphi 3                  Ver100   Win32   Win32
C++ Builder 3             Ver110   Win32   Win32    BCB
Delphi 4                  Ver120   Win32   Win32
C++ Builder 4             Ver125   Win32   Win32    BCB
Delphi 5                  Ver130   Win32   Win32
C++ Builder 5             Ver130   Win32   Win32    BCB
Kylix1                    Ver140   Linux   LINUX
Delphi 6                  Ver140   Win32   Win32
C++ Builder 6             Ver140   Win32   Win32    BCB
Kylix2                    Ver140   Linux   LINUX

その他、CPU386、LINUX32、POSIX(32)、PIC、ELF なども状況により利用可能です。


また、Kylix からは不等号を使った条件分岐ができます。
条件コンパイルするには、[Delphi-ML:67458], [Delphi-ML:67474], [Delphi-ML:67489] を参考にして、

{$IFDEF VER80}  {Delphi1}  {$ENDIF}
{$IFDEF VER90}  {Delphi2}  {$ENDIF}
{$IFDEF VER93}  {Builder1} {$ENDIF}
{$IFDEF VER100} {Delphi3}  {$ENDIF}  
{$IFDEF VER110} {Builder3} {$ENDIF}
{$IFDEF VER120} {Delphi4}  {$ENDIF}  
{$IFDEF VER125} {Builder4} {$ENDIF}
{$IFDEF VER130}
  {$IFDEF BCB}  {Builder5}
  {$ELSE}       {Delphi5}  {$ENDIF}
{$ENDIF}
{$IFDEF CONDITIONALEXPRESSIONS}
  // Kylix1 以上は RTLVersion を持っているので
  {$IF RTLVersion < 14.20 - 0.001}
      // こういう形で処理できる
      // "- 0.001" の部分は2進小数と10進小数との変換誤差を
      // 吸収するためのダミー定数 → [Delphi-ML:67489] を参照
  {$IFEND}
  {$IF Declared(CompilerVersion)}
      // Delphi6 以上では CompilerVersion も利用可能
      {$IF CompilerVersion < 14.10 - 0.001}
        // Kylix1 から Builder6 までに対する処理
      {$IFEND}
  {$IFEND}
{$ENDIF}  

などとします。
ちなみに、中村さんの [Delphi-ML:67486] によれば、

                          RTLVersion  CompilerVersion
Kylix1                    14.00       なし
Delphi6             14.10       14.01
Delphi6     Update Pack 1 14.11       14.01
Delphi6     Update Pack 2 14.20       14.01
C++Builder6               14.20       14.01
Kylix 2                   14.20    14.10

とのことですが、Nobuyuki Nakashima さんの [Delphi-ML:67489] によれば、2進小数と10進小数との変換誤差で、上記の値ぴったりにはなりません。コード例のように、誤差を考慮した対処が必要です。

http://www.delphianworld.com/direct.html?id=MI0062
のようなインクルードファイルを用意すると楽ができます。
参照: [builder:5430] [Delphi-ML:57660] [Delphi-ML:67458] [Delphi-ML:67474] [Delphi-ML:67486] [Delphi-ML:67489] <開発環境>

0221  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/26 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2004/03/04 osamu 編集
春分、秋分、夏至、冬至の求め方


水野さんが明快なアイデアをだしています。[Delphi-ML:38594]
  
春分、秋分、夏至、冬至の求め方は、単純に1997年の春分、夏至、秋分、冬至の日時に、地球が太陽の周りを回る周期(365.2422日)を足したり引いたりするだけのものです。
ただ、ここ20〜30年くらいの春分、秋分の日は、上の式で求めたものと同じだそうです。
実際は、計算して人間(政府)が決めるらしいですね。
カレンダーなどの作成に大変便利です。

下記のコードは、時刻部を省略し、日付のみに変えてあります。

type
  TSeason = (seVernalEquinox, seSummerSolstice, seAutummnalEquinox, seWinterSolstice);

function JapanHoliday4(myYear: Integer; mySeason: TSeason): TDateTime;
var
  myDate: TDateTime;
begin
  case Integer(mySeason) of
    0: myDate:= StrToDateTime('97/03/20 22:55') + 365.2422 * (myYear - 1997); //春分
    1: myDate:= StrToDateTime('97/06/22 03:55') + 365.2422 * (myYear - 1997); //夏至
    2: myDate:= StrToDateTime('97/09/23 08:56') + 365.2422 * (myYear - 1997); //秋分
    3: myDate:= StrToDateTime('97/12/21 18:49') + 365.2422 * (myYear - 1997); //冬至
  end;
  Result:= Int(myDate);
end;

またコンポーネントでは、
Delphian World < http://www.delphianworld.com/ >;
に「祝祭日カレンダー」というのがあります。
秋分・春分計算もしてくれる様です。
参照: [Delphi-ML:38539] [Delphi-ML:38594] <日時> <PASCAL>

0115  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/11/21 osamu 編集
子プロセス(DOS)の標準出力をパイプする

こんなんでどうでしょう?(↓)
    CreatChildProcess('cmd.exe /c dir');
とやると、Memo1に"dir"の結果が表示されます(NT4.0では動きました)。

ただし、標準出力をリダイレクトしてしまっているので、DOS窓(コンソール)には、なにも表示されません(この例では、コンソールを表示しないようにしていますが、表示しても空のコンソールが表示されるだけです)。
どうしてもコンソールにも表示したい場合は、AllocateConnsoleAPIで自前でコンソールを作成して、Memo1に書く内容を自前で書くのかなぁ?

あとエラー処理等まるっきり省いていますのでご注意を。

function TForm1.CreatChildProcess(exec_name: AnsiString): Integer;
var
  buf: array[0..4095] of Char;
  hRead, hWrite: THandle;
  SecAttrib: TSecurityAttributes;
  StartInfo: TStartupInfo;
  dwRead: DWORD;
begin
  //
  // 名前なしパイプの作成
  //
  FillChar(SecAttrib, SizeOf(SecAttrib), 0);
  SecAttrib.nLength := SizeOf(SecAttrib);
  SecAttrib.bInheritHandle := TRUE;
  CreatePipe(hRead, hWrite, @SecAttrib, 0);

  //
  // 子プロセスを作成
  //
  FillChar(StartInfo, SizeOf(StartInfo), 0);
  StartInfo.cb := SizeOf(StartInfo);
  StartInfo.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
  StartInfo.hStdOutput := hWrite;
  StartInfo.wShowWindow := SW_HIDE;
  if not CreateProcess(Pointer(0),
              PChar(exec_name),
              Pointer(0), Pointer(0),
              TRUE,
              0,
              Pointer(0), Pointer(0),
              StartInfo, ProcInfo) then
  begin
    Result := -1;
    Exit;
  end;
  WaitForInputIdle(GetCurrentProcess(), INFINITE);
  CloseHandle(hWrite);

//
//  Windows95ではこの部分で制御を返してくれなくなります。
// もうちょっとしたら対処法を書くつもり。
// いつになることやら。。。(--;
//
  While ReadFile(hRead, buf, SizeOf(buf) - 1, dwRead, Nil) do
  begin
    if dwRead = 0 then
      Break;
    buf[dwRead] := #00;
    Memo1.Lines.Add(buf);
    Application.HandleMessage;
  end;

  CloseHandle(hRead);
  Result := 0;
end;


[追記] Autch.net さんの tips にもソースが挙げられているとの情報を得ました。[Delphi-ML:79357]

Autch.net
http://hp.vector.co.jp/authors/VA026252/

GUI アプリからコンソールアプリを実行するには
http://hp.vector.co.jp/authors/VA026252/tips/delphi_anonymous_pipe.html
参照: [Delphi-ML:21973] [Delphi-ML:79357] <Windows>

0349  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/10/02 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/10/02 osamu 編集
二重起動防止措置で既存プロセスを最前面に送る

以下のコードでうまく動くそうです。
定数宣言部分を必要に応じて書き換えて使います。

program Project1;

uses
  Windows,
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}

const
  MutexName = 'TEST_MUTEX';
  ClassName = 'TForm1';
  WindowName = 'Form1';
var
  Mutex: THandle;
  Handle: THandle;
begin
  Mutex := OpenMutex(MUTEX_ALL_ACCESS, False, MutexName);
  if Mutex <> 0 then
  begin
    Handle := FindWindow(ClassName, WindowName);
    SetForegroundWindow(Handle);
    Exit;
  end;
  CreateMutex(nil, False, MutexName);
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
参照: [Tips:269] [Delphi-ML:78270] <アプリケーション>

0344  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/07/03 osamu rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/09/24 osamu 編集
Delphi7 のコンボボックスの空文字列でエラー

Delphi7 では、コンボボックスに空文字列を入れておくと、
  ComboBox1.Items.Add('');
この Item を Items[0] などとして参照した時にアクセスバイオレーションエラーが発生してしまいます。

これは、以前の Delphi が Item 保持領域として 4096 などの固定値を使っていたのに対して、Delphi7 からは CB_GETLBTEXTLEN を使ってバッファを動的に確保するようになったためで、それ自体は正しいことなのですが、Item の長さが 0 の時に正しくバッファが確保されないためにエラーが発生してしまいます。

エラーの詳しい内容は、[Delphi-ML:77352][Delphi-ML:77360][Delphi-ML:77366]を見てみてください。回避方法としては、Amaito さんの [Delphi-ML:77357] のように、

StdCtrls.pasをプロジェクトと同じフォルダにコピーして、2325行を

  //if Len <> CB_ERR then
  if Len > 0 then

とするのが良いようです。(CB_ERR は負の値なので、Len > 0 で Len=0 と Len=CB_ERR との両方の場合に対応しています)

[Delphi-ML:72969] でもすでに同じ問題が報告されていました。

## 実は編集後のコードにもちょっとした仕様バグが含まれています。
## TListBox.Items などと動作を合わせるのであれば、CB_ERR
## の場合には空文字列を返すのではなく例外を投げるべきだと
## 思います。
参照: [Delphi-ML:72969] [Delphi-ML:77352] [Delphi-ML:77357] [Delphi-ML:77360] [Delphi-ML:77366] <バグ> <Standard> <コンポーネント >

0342  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/27 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/08/22 osamu 編集
非ビジュアルコンポーネントの Left, Top 座標を取得

> 設計時にフォーム上に貼り付けた
> 非ビジュアルコンポーネント(TTable,TQuery)の
> フォーム上の位置を取得したいんですけれどもできるんでしょうか?

procedure TComponent.WriteLeft(Writer: TWriter);
procedure TComponent.WriteTop(Writer: TWriter);

の2つのメソッドを見てみると、DesignInfo プロパティの上半分、
下半分がそれぞれ Top, Left に対応するみたいですね。

TheLeft:= LongRec(ACompo.DesignInfo).Lo;
TheTop := LongRec(ACompo.DesignInfo).Hi;

で取り出せるようです。
参照: [Delphi-ML:77269] <その他コンポーネント関連> <コンポーネント >

0346  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/08/22 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/08/22 osamu 編集
プロパティ値を文字列に変換/逆変換

published なプロパティを Ini に書き込みたい・から読み出したいというような時、プロパティ値を文字列に変換する必要が生じます。

Font プロパティを Ini/Registry に保存したい という投稿はFAQに近いですが、この記事はそういった要望への回答となります。

Enum/Set だけではなく、TColor のように「Enum ではないけど文字で書きこまれることがあるプロパティ」にも対応しています。

uses Classes, TypInfo;

function PropertyToString(obj: TPersistent; PropName: string): string;
var IntToIdent: TIntToIdent;
    Ident: string;
begin
  Result:= GetPropValue(obj, PropName);
  if PropType(obj, PropName)=tkInteger then begin
    IntToIdent := FindIntToIdent(GetPropInfo(obj, PropName).PropType^);
    if Assigned(IntToIdent) then
      IntToIdent(GetPropValue(obj, PropName), Result);
  end;
end;

procedure StringToProperty(s: string; obj: TPersistent; PropName);
var IdentToInt: TIdentToInt;
    i: Integer;
begin
  if PropType(obj, PropName)==tkInteger then begin
    IdentToInt:= FindIdentToInt(GetPropInfo(obj, PropName).PropType^);
    if Assigned(IdentToInt) and IdentToInt(s, i) then begin
      SetPropValue(obj, PropName, i);
    end else begin
      SetPropValue(obj, PropName, s);
    end;
  end else begin
    SetPropValue(obj, PropName, s);
  end;
end;
参照: [Delphi-ML:75958] <文字列> <PASCAL>

0277  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/28 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/07/24 西坂良幸 編集
集合型変数の内部構造が知りたい/数値として処理したい。

集合型の変数は、フラッグの集まりです。
例えば、
type
  TDbit  = 0..25;
  TDbits = set of TDbit;

と定義し、
  Var D:TDbit;
  D := [1,3,4,6];  の場合

  内部的には,00000000 00000000 00000000 01011010B
  とビット表現されています               ~~~~~~~~~
  したがって、Integer(D)とキャスト可能で、この値は90です

集合で使うバイト数は次の式で計算します。
  
  ByteSize = (Max div 8) - (Min div 8) + 1
      ※ 最大255要素ですから、最大32バイト

Min と Max は集合の基本型の下限と上限です。
特定の要素 E が何バイト目かは次の式でわかります。

  ByteNumber = (E div 8) - (Min div 8)

そのバイト内で何ビット目かは次の式でわかります。

  BitNumber = E mod 8
     ※ E は要素の順序値を表します。

GetLogicalDrives関数は、 現在利用可能なディスクドライブを表すビットマスクを返しますので、これで、試してみましょう。返り値のビット位置0 (最下位ビット) はドライブAに対応します。

バイトサイズ → (25 div 8) - (0 div 8) + 1 = 4
で、4バイト、DWord型やLongint型が使えます。

TDBitsの最小値は → 0
   0 mod 8      → 0  ですから、そのまま対応できます

procedure TForm1.Button1Click(Sender: TObject);
var
  d: TDbit;
  drvs: TDbits;
  DName:string;
begin
  ListBox1.Items.Clear;
  // マシンのドライブをえる
  DWORD(drvs) := GetLogicalDrives;
  for d := Low(TDbit) to High(TDbit) do
  begin
    if d in drvs then
    begin
      DName := Chr(Integer('A') + d) + ':\';
      // ドライブタイプをえる
      case GetDriveType(PChar(Char(Ord('A')+d)+':\')) of
      DRIVE_REMOVABLE: DName := DName + 'リマーブルデスク';
      DRIVE_FIXED: DName := DName + 'ハードデスク';
      DRIVE_REMOTE: DName := DName + 'ネットワークデスク';
      DRIVE_CDROM: DName := DName + 'CDROMデスク';
      DRIVE_RAMDISK: DName := DName + 'ラムデスク';
      end;
      ListBox1.Items.Add(DName);
    end;
  end;
end;

次に、
Type
  TDrive  = 'A'..'Z';
  TDrives = Set of TDrive;
を使えばどうでしょうか。

TDrivesの最小値は → 'A'  順序値 65
   65 mod 8      → 1  ですから、
返り値の0ビットは、TDravesの1ビット目に対応します。

procedure TForm1.Button1Click(Sender: TObject);
var
  d: TDrive;
  drvs: TDrives;
  DName:string;
begin
  ListBox1.Items.Clear;
  // マシンのドライブをえる−−左に1ビットシフトする
  DWORD(drvs) := GetLogicalDrives shl 1;
  for d := Low(TDrive) to High(TDrive) do
  begin
    if d in drvs then
    begin
      DName := Char(d) + ':\';
      // ドライブタイプをえる
      case GetDriveType(PChar(d +':\')) of
      DRIVE_REMOVABLE: DName := DName + 'リマーブルデスク';
      DRIVE_FIXED: DName := DName + 'ハードデスク';
      DRIVE_REMOTE: DName := DName + 'ネットワークデスク';
      DRIVE_CDROM: DName := DName + 'CDROMデスク';
      DRIVE_RAMDISK: DName := DName + 'ラムデスク';
      end;
      ListBox1.Items.Add(DName);
    end;
  end;
end;

集合型を内部表現で使うのは、注意が必要です。
なるべく集合型として使いましょう。

なお、集合型の演算子として +,*,-,IN が定義されていますので、
not  は、 全定義 - 値
xor  は、 和集合 - 積集合で代用できます。

要素数は、4バイトまでの集合なら以下のようなぐあいですか?

function GetElements(Drvs: TDrives):DWORD;
var
  i:TDrive;
begin
  result := 0;
  for i := Low(TDrive) to High(TDrive) do
  begin
    inc(result,DWORD(Drvs) and 1);
    DWORD(Drvs) := DWORD(drvs) shr 1;
  end;
end;


*リマーブルデスクって・・・(ぷ
参照: [Delphi-ML:9105] [Delphi-ML:42690] <計算> <PASCAL>

0345  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/07/18 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/07/18 osamu 編集
スクリーンセーバーの作り方

Ryota Ando さんの、「Delphi で作るスクリーンセーバー制作講座」
http://www02.so-net.ne.jp/~rando/delphi/how2ss/index-f.html
に詳しいです。

参考として、以下の URL も紹介されています。

HowToScr - technical documentation
http://www.wischik.com/scr/resources.html
  How to write a 32bit screen saver
  http://www.wischik.com/scr/howtoscr.html

screensavergallery.com: Developers Corner
http://www.screensavergallery.com/Developers_Corner/

Borland Technical Information
http://www.borland.com/devsupport/delphi/ti_list/TI4534D.html

Microsoft Visual J++ 6.0 Developer's Workshop
http://mspress.microsoft.com/vstudio/books/sampchap/2275.htm#94
参照: [Delphi-ML:31792] <その他Windows関連> <Windows>

0073  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/07/10 yamamoto 編集
浮動小数点数を整数に丸めるときの注意

Delphiには四捨五入用の関数として Round() がありますが、この関数は「Banker's Rounding」(銀行家の丸め)をするため、普通の四捨五入とは結果が異なることがあるため注意が必要です。
具体的には、引数がちょうど ???.5 となるとき、通常の四捨五入では答は 1 繰り上げた数になりますが、Round() では結果の一の位が偶数になるように切り上げ/切り捨てが行われます。(例: 0.5 は 0,1.5 は 2 になる)[Delphi-ML:4727][Delphi-ML:12693]から始まるスレッドも参考になります。

これに対して Trunc() はいつも小数部分を切り捨てて返しますので、普通の四捨五入をするには、

function Roundoff(X: Extended): Longint;
begin
    if x >= 0 then Result := Trunc(x + 0.5)
              else Result := Trunc(x - 0.5);
end;

のような関数を作って使用します。

Professional Edition 以上では、Math ライブラリに Floor()/Ceil() の関数もあります。
Int() 関数は Trunc() と同じ答を Extended 型で返します。
参照: [Delphi-ML:4727] [Delphi-ML:12693] [Delphi-ML:20194] [Delphi-ML:20205] <計算> <PASCAL>

0170  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/03/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/27 osamu 編集
Delphi によるレジストリの操作方法

ひきさんのページで詳しい解説をしてくださっているので、参考にすると良いでしょう。

[Delphi 壁の穴]-[その三:レジストリを覗く]
http://hp.vector.co.jp/authors/VA009712/take/delphi/kabereg.htm

以下は内容:

レジストリ操作の基本を知る
レジストリにアプリケーションの設定を保存する
レジストリにファイルの関連づけを設定する
レジストリにDWORD値を記録させる
レジストリにバイナリ値を記録させる
各種のシェルフォルダを得る(レジストリ版)
REGファイルを作る
TRegistryでDeleteKeyできない
TRegIniFileでキーを丸ごと削除したい
キーの指定で「\」付きとなしではどう違うのか
参照: <その他Windows関連> <Windows>

0173  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/03/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/27 osamu 編集
ファイルの更新日時を得る

Windows 的な方法としては、FindFirst/FindClose を使って、得られた TSerchRec を読みます。

別解として、PASCAL の FileAge 関数を使った方法を、ひきさんが以下のホームページで解説してくださっています。

[Delphi壁の穴]-[その二:システムを覗く]
http://hp.vector.co.jp/authors/VA009712/take/delphi/kabesys.htm#datetimefile1
http://hp.vector.co.jp/authors/VA009712/take/delphi/kabesys.htm#datetimefile2
参照: <日時> <ファイル> <PASCAL>

0175  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/03/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/27 osamu 編集
システムアイコンをリフレッシュする

フォルダのアイコンなど、システムで使われるアイコンを変更した後は、ちょっとしたトリックを使わないと画面に反映されません。
具体的には、一旦アイコンの大きさを変更してまた元に戻すのだそうです。ひきさんのページでサンプルコードを見ることができます。

[Delphi壁の穴]-[その二:システムを覗く]
http://hp.vector.co.jp/authors/VA009712/take/delphi/kabesys.htm#refreshsysicon
参照: <Windows> <バグ> <アイコン>

0176  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/03/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/27 osamu 編集
コントロールパネルを作る

コントロールパネル(*.CPL)を作るなんてさぞかし難しいように思われるかも知れませんが、案外簡単に作れてしまいます。とのことです。
ひきさんのページへGo!

[Delphi壁の穴]-[その二:システムを覗く]
http://hp.vector.co.jp/authors/VA009712/take/delphi/kabesys.htm#controlpanel
参照: <その他Windows関連> <Windows>

0174  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/03/08 osamu rev 1.6
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/27 osamu 編集
全てのウィンドウを最小化する

Keybd_event を使って、[WindowsKey(ミ田)]+[M] を押してやると言う手法が、ひきさんの日本Delphi振興会のページで紹介されています。

[Delphi壁の穴]-[その2:システムを覗く]
http://hp.vector.co.jp/authors/VA009712/take/delphi/kabesys.htm#allminimize

Windows+Mを押すと全起動APPが最小化するいうこと知っていましたか?
知らなかったらこのコードは書けませんね。
procedure TForm1.Button1Click(Sender: TObject);
begin
  Keybd_event(VK_LWIN,   0, 0, 0);  //Windowsキーを押す
  Keybd_event(Byte('M'), 0, 0, 0);  //Mキーを押す
  Keybd_event(Byte('M'), 0, KEYEVENTF_KEYUP, 0); //Mキーを離す{この行:必要ないかも知れない}
  Keybd_event(VK_LWIN,   0, KEYEVENTF_KEYUP, 0);  //Windowsキーを離す
end;

Byte('M')の代わりにOrd('M')を用いてもよいでしょう。

そして、この操作で最小化したAPPを元に戻すには、
Windows+Shift+Mキーを押します。
Keybd_eventの書き方は分りますね。Shiftキーの仮想キーコードはVK_SHIFTです。

また、Win98やIE4以降インストールでデスクトップ統合を行った
Windowsでは
Windows+Dキーで
『全ウィンドウの最小化』←→『元に戻す-すべて最小化』
を切りかえられます。
参照: <Windows>

0171  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/03/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/27 osamu 編集
コンボボックスにブラウザのURL入力のような自動補完機能を付けたい

ひきさんのページにサンプルコードを見つけることができます。ひきさんに感謝しつつ、ご利用下さい。

[Delphi壁の穴]-[その一:Delphiを覗く]
http://hp.vector.co.jp/authors/VA009712/take/delphi/kabedel.htm#autocomplete
参照: <Standard> <コンポーネント >

0172  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/03/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/27 osamu 編集
TMemoで、先頭行/最終行/指定行へ移動する。

ひきさんのページにサンプルソースを見つけることができます。ひきさんに感謝しつつ活用しましょう。

[Delphi壁の穴]-[その1:Delphiを覗く]
http://hp.vector.co.jp/authors/VA009712/take/delphi/kabedel.htm#memomove
参照: <Standard> <コンポーネント >

0184  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/11 花井@自宅 rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
「アドレス????????でエラーが発生」からエラー位置を知る

「EAccessViolationがモジュールHOGEHOGE.EXEの0005E1D9で発生しました。モジュール'HOGEHOGE.EXE'のアドレス0045E1D9でアドレスFFFFFFFFに対する読み込み違反がおきました。」
などというメッセージから、エラー発生のソース中での位置を調べることができます。

(IDE 上から)
 Delphi の統合環境上のメニュー [検索][エラーの検索] でアドレスを指定します。エラーの起きた場所が見つけられると、その位置にカーソルが移動します。

(コマンドラインから)
コマンドラインコンパイラ(dcc32.exe)が使えます。

(delphi 3の場所)\bin\dcc32 -f5E1D9 hogehoge.dpr

とかすると

Delphi for Win32  Version 10.0  Copyright (c) 1983,97 Borland International
hogehoge.dpr(20)
UNIT1.PAS(775) Target address found.
    strcopy(p, title);
    ^

のように表示されます。ソースのない部分とかWindowsの中で起きている場合は 'target address not found' になります。
ただし、これを使うには、ライブラリパスを指定しておく必要があります。
コマンドラインコンパイラの場合、ライブラリパスは -u オプションで指定します。引数なしで dcc32 を起動すると、オプションの種類が分かります。
常時指定するオプションは dcc32.exe と同じディレクトリにある dcc32.cfg に書き込んでしまっても OK です。こんな感じです。

----------^ dcc32.cfg
-aWinTypes=Windows;WinProcs=Windows;DbiProcs=BDE;DbiTypes=BDE;DbiErrs=BDE
-uE:\DELPHI3\Lib\User;E:\DELPHI3\Lib;E:\DELPHI3\Lib\Delphi2
----------$


追記:コンパイル時に map ファイルを作成しておけば IDE が無くても対応行が分かるそうです。
[Delphi-ML:68565][Delphi-ML:68566][Delphi-ML:68574][Delphi-ML:68592]
参照: [Delphi-ML:19322] [Delphi-ML:4975] [Delphi-ML:68565] [Delphi-ML:68566] [Delphi-ML:68574] [Delphi-ML:68592] <開発環境>

0341  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
Delphi の格言

[Delphi-ML:68385] から始まったツリーなんですが、まとめるに当たって編集者の個人的な好みが反映されています。ご容赦。

1) リソースの取得と開放は try〜finally〜end を使うべし。[Delphi-ML:68385]
2) Assert を使いまくれ。[Delphi-ML:68385]
3) メソッドを override するとき、override キーワードが抜けていないか常にチェックせよ。[Delphi-ML:68385]
4) Except で例外を処理するとき、raise で例外を再生成する必要がないか常にチェックせよ。[Delphi-ML:68385]
5) with文を使用するのは控えること[Delphi-ML:68385][Delphi-ML:68402]
6) フォームは自動生成ではなく自分で明示的に生成しよう![Delphi-ML:68386][Delphi-ML:68402]
7) AnsiString, WideString, Interface, Variant, 動的配列を含むレコードを動的に確保するときは New, Dispose を使うか、動的配列でメモリを確保せよ[Delphi-ML:68387][Delphi-ML:68423]
8) Application.ProcessMessages はその危険性を充分認識して使え。[Delphi-ML:68387]
9) VCL のソースをよく読もう。[Delphi-ML:68387]
10) RECORD に AnsiString/WideString/DynArray を不用意に使うな。[Delphi-ML:68391]
11) RECORD や ARRAY は PACKED が必要か考えろ。[Delphi-ML:68391]
12) 1行処理でも begin 〜 end は必ず付けよう。[Delphi-ML:68401]
13) 「名は体を表す」 変数名やクラス名、コンポーネント名は意味のわかる単語で。[Delphi-ML:68401]
14) バリアント変数の型変換はなるべく関数経由で。[Delphi-ML:68402]
15) try 〜 exceptはエラー情報の損失を最小に。[Delphi-ML:68402]
16) プロパティと同一名をメソッドの仮引数名に使わない。[Delphi-ML:68402]
17) イベントハンドラ内に細かい処理を書かない。[Delphi-ML:68402]
18) 他のフォーム内のコンポーネントは直接触らず、メソッドかプロパティ経由で。[Delphi-ML:68402]
13) 状態変化を伴うメソッド(C++での non-const method)は、なるべく関数でなく手続きに[Delphi-ML:68402]
14) プロジェクトで開発するときは基底モジュールを用意してフォームの継承を活用する[Delphi-ML:68408]
15) TThreadからVCL(TFormとか)を参照するときは必ずSynchonize! [Delphi-ML:68411]
16) public で 非virtual なメソッドは極力再定義するな。[Delphi-ML:68420]
17) オブジェクトが上位から継承する仮想メソッドを呼び出すときは inherited をつけて呼び出すか、そうしないかをよく考えよ。[Delphi-ML:68420]
18) デストラクタは、必ず destroy という名にして、必ず仮想メソッドにする。[Delphi-ML:68420]
19) コンストラクタは protected にしてはいけない[Delphi-ML:68420]
20) New で確保したメモリを破棄するときは、New に渡したポインタと同じ型のポインタを Dispose に渡せ[Delphi-ML:68423]
21) コメントは必要最小限にして、極力コードの可読性を高めよ[Delphi-ML:68429]
22) デフォルト引数は使わず、オーバーロードを使え。[Delphi-ML:68433]
23) {ObjExportsAll On} を忘れずに。[Delphi-ML:68433]
24) 名前だけが異なる複数のコンストラクタは作らない。[Delphi-ML:68433]


IDEの格言
1) アプリケーションをリリースするときは、map ファイルを作るのを忘れずに。[Delphi-ML:68385]
1b) 外に出したようなリリース版は、*.dcu をすべて保存しておいて Delphi を起動して「エラーの検索」を活用する[Delphi-ML:68572]

2) たくさんウィンドウを開いているときは ALT+0 を活用せよ。[Delphi-ML:68385]
3) コンパイルオプションは Ctrl+O+O でソースに埋め込むとIDE のコンパイルオプションの設定に左右されないソースが作れる。[Delphi-ML:68385]
4) デフォルトのコンパイルオプションの変更はトラブルの元。[Delphi-ML:68385]
5) Delphi をインストールしたら「環境オプション]→[設定]→[自動保存の設定]→[エディタファイル]をチェックしよう。[Delphi-ML:68420]


コンポーネントの格言
1) OnExit イベントでダイアログボックスを表示するな。[Delphi-ML:68385]
2) コンポーネントの Loaded メソッドが呼ばれることを仮定したコンポーネントを作ってはいけない。[Delphi-ML:68385]
3)自動生成されるコンポーネント名をそのままでほったらかすな。意味のわかりやすいコンポーネント名に変えろ。[Delphi-ML:68398][Delphi-ML:68402]

番外編
1) 『プログラミング作法』を読もう。[Delphi-ML:68404]
  http://www.ascii.co.jp/books/detail/4-7561/4-7561-3649-4.html

人間関係の格言???[Delphi-ML:68543]
1.感情的に物事を判断しない。
2.例え正しい事でも、言い方や伝え方には気を使う。
3.コーディングスタイルには、ある種の宗教的要素が存在する事を認めて無駄な議論にならないように。
 (みんな、自分のスタイルが正しいと信じている。)
4.ユーザーがどのように使い運用するのかを常に考える。
 (ユーザーとのコミュニケーション無しに役立つソフトはできない。)
5.最初から完全なソフトウェアを目指そうとしてはいけない。
 (実際に運用してみないと分からないもんです。
 役立つソフトであれば仕様変更は必ずあります。必要最低限の機能を早くリリースするように心がけましょう。)
参照: [Delphi-ML:68385] <開発環境> <PASCAL>

0019  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
OnDblClick発生時にOnMouseDownはいらない!

ダブルクリック発生をOnDblClickで捕まえたいのに、1度目のクリックでOnMouseDownが発生してしまう。
ダブルクリックとシングルクリックの両方を捕まえるにはどうするか?

procedure TForm1.FormMouseDown(Sender: TObject;
    Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var t:LongInt;
begin
    //
    // シングル/ダブルクリックの判定
    //
    if ssDouble in Shift then begin
        DoubleClickOccurred[Button]:=True;
    end else begin
        DoubleClickOccurred[Button]:=False;
        t:=GetTickCount+GetDoubleClickTime;
        while GetTickCount<t do begin
            Application.ProcessMessages;
            if DoubleClickOccurred[Button] then
                Exit;
        end;
    end;

    if ssDouble in Shift then begin
      case Button of
      mbLeft:   ;
      mbMiddle: ;
      mbRight:  ;
      end;
    end else begin
      case Button of
      mbLeft:   ;
      mbMiddle: ;
      mbRight:  ;
      end;
    end;
end;

ここで、
    DoubleClickOccurred:array [TMouseButton] of Boolean;
は、TForm1のメンバ変数です。
シングルクリックの際の動作でチョット遅れた感じがするのはしかたないですね。
参照: [Delphi-ML:7386] [Delphi-ML:7392] [Delphi-ML:7457] <コンポーネント > <その他コンポーネント関連>

0043  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
ComboBoxのDropDownListの幅を変更する

エディット部分はそのままで、ドロップダウンする部分の幅だけを変更したければ、

    ComboBox1.Perform(CB_SETDROPPEDWIDTH, 幅, 0);

とします。
「幅」はピクセル単位となります。
参照: [Delphi-ML:19165] <Standard> <コンポーネント >

0340  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
自己実行形式の動画

Exe 内部に動画データをバイナリデータのリソースにしてコンパイルします。D5でのリソースファイルの作り方について:

http://halbow.cool.ne.jp/Notes/N008.html

例えば、'clock.avi' をリソースにする場合、リソーススクリプトファイル(MyRes.rc) は以下のようになります。

MyAVI AVI "c:\WINNT\clock.avi"

このリソースを使って以下のようにして、うまくいきました。

procedure TForm1.Button1Click(Sender: TObject);
var
  RS:TResourceStream;
begin
  RS := TResourceStream.Create(hInstance,'MyAVI','AVI');
  try
    RS.SaveToFile(ExtractFilePath(ParamStr(0))+'MyAVI.avi');
  finally
    RS.Free;
  end;
  if FileExists(ExtractFilePath(ParamStr(0))+'MyAVI.avi') then
    with MediaPlayer1 do begin
      Filename := ExtractFilePath(ParamStr(0))+'MyAVI.avi';
      DeviceType := dtAVIVideo;
      Notify := false;
      Open;
      Notify := true;
      Play;
    end;
end;

procedure TForm1.MediaPlayer1Notify(Sender: TObject);
begin
  MediaPlayer1.Close;
  if FileExists(ExtractFilePath(ParamStr(0))+'MyAVI.avi') then
  begin
    DeleteFile(ExtractFilePath(ParamStr(0))+'MyAVI.avi');
    ShowMessage('AviFile has Deleted!');
  end;
end;
参照: [Delphi-ML:76119] <その他Windows関連> <System> <Windows> <コンポーネント >

0339  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
フォルダもファイルも選べるダイアログ

Q.デスクトップ 〜 右クリック 〜 新規作成 〜 ショートカットの時に「参照」ボタンを押しますと、Caption は「フォルダの参照」とかになっていながらフォルダもファイルも選べるダイアログが出てきます。こいつを使用したいのです。

A.ShBrowseForFolder で BIF_BROWSEINCLUDEFILES を指定すると良いようです。

  with BrowseInfo do begin
    hwndOwner := FhParent;
    pidlRoot := nil;
    pszDisplayName := BDisplayName;
    lpszTitle := 'フォルダを選択してください';
    ulFlags := BIF_STATUSTEXT or BIF_RETURNONLYFSDIRS or
                           BIF_BROWSEINCLUDEFILES; // ここを追加
    lpfn := @BrowseFolderProc;
    lParam := integer(@BFFR);
  end;
参照: [Delphi-ML:76043] <Dialogs> <コンポーネント >

0338  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
Ini ファイルに published プロパティを保存する方法

published プロパティを Ini ファイルなどに保存するためにテキストに/テキストから変換する方法を [Delphi-ML:75958] に載せました。

例えば、Font.Style プロパティを [fsBold] などとして保存することができます。
参照: [Delphi-ML:75958] <アプリケーション> <PASCAL>

0337  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
ボタン間を矢印キーで移動させるロジック

Q.フォーム上にボタンがたくさんあり、上下左右の矢印キーによって、実際のボタンの配置から期待される順序でフォーカスを動かしたいのですが。

A.設計時の手間はかかるのですが、各ボタンを個別にパネルの上に乗せてしまえば、矢印キーによる通常のフォーカス移動を無効にできるので、ボタンの OnKeyUp イベント内で移動先を設定できると思うのですがいかがでしょうか。
参照: [Delphi-ML:75689] <コンポーネント > <Standard>

0336  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
RichEdit を印刷したい

Delphi の Demo にサンプルコードが含まれています。Delphi5 であれば、

Program Files\Borland\Delphi5\Demos\Richedit\richedit.dpr

に RichEdit の印刷ルーチンがあります。
参照: [Delphi-ML:54315] <印刷> <Win95> <コンポーネント >

0335  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
Install Shield Express でアンインストール時にレジストリを削除できない

>  Delphi3.1に付属の InstallShield Express にてインストール時
> に設定したキーをアンインストール時に掃除させようとしているの
> ですがうまくいきません。(キーが全く削除されない)

私もキーが削除できなくて困った経験があり、何かのショー(忘れました)で、インストールシールドをデモしているブースがあったので、聞いてみたところ、Delphi付属のInstallShieldでは「出来ません」という簡単な回答でした。
では、どうすればよいかと尋ねたところ、Professional版(有料)を購入し、自分でプログラミングしてください、ということでした。(ほかにもいろいろな機能を持っているそうです)
参照: [Delphi-ML:32275] <開発環境> <配布>

0334  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
ActiveX でショートカットキーが使えない

ActiveXをd3・d4で取り込むと ActiveX に組み込まれているショートカットキーが使えないものがあります。

どうも、TOLEControlの親であるTWinControlでショートカットのメッセージが止まっていて、activeXに渡されてないようなのです。

ちょっとうまい対処の方法が思いつかないのですが、とりあえずApplication.OnMessage をつかってOleInPlaceActiveObject.TranslateAccelerator(Msg); で、activeXに直接伝えれば、症状を回避できるようです。

由木尾@蛸薬師倶楽部さんが具体的なコードを [Delphi-ML:32242] に示してくださっています。
参照: [Delphi-ML:32242] <その他Windows関連> <Windows> <バグ>

0332  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
DLL にブレークポイントが設定できない

今までWin2000 + Del5Entの環境で開発していました。OSをWinXPに変えたところ、DLLのデバッグができなくて困っています。

D5 + WinXP では DLL のデバッグができないようです。
D7 では正常に動作するとの報告があります。
参照: [Delphi-ML:72312] [Delphi-ML:73399] <開発環境> <バグ> <デバッグ> <DLL>

0331  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
FindFirst でアイコンを変更したディレクトリを検索できない

Delphi7, WinXPです。XPにはフォルダのアイコンイメージを変更することができるのですが、これを適用したフォルダをFindFirstは認識しません。

この投稿に簡単な解決法は投稿されませんでした。FindFirstFileEx API や Shell 関連の API を使うことで回避できるかもしれないとの意見がありました。
参照: [Delphi-ML:73372] <Windows> <ファイル>

0330  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
FindFirst による4文字以上の拡張子の判別

Q.FindFirst,FindNextを使用してファイル名を取得しているのですが、PATH定数を "C:\TEST\*.jpg" と指定した場合、拡張子が「.jpg」のファイルだけでなく退避用にリネームした”XXXX.Jpg_”といったファイルまでヒットしてしまいます。

A.WinXPには4文字以上の拡張子を正しく認識させるためのレジストリが用意されています。以下の方法を試してみてはいかがでしょうか。Win2000でも同じことができるかどうかはわかりません。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem の Win95TruncatedExtensions を 0 にして再起動。
参照: [Delphi-ML:73374] <Windows> <ファイル>

0327  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
Photoshop のようなツールウィンドウを実現したい

1.細いタイトルバーでクローズボタンのみが付いている
2.アプリケーションがアクティブであればツールウィンドウのタイトルバーもアクティブ色
3.常にアプリケーションのフォームよりも手前にある

というようなツールウィンドウを実現しようと思うと、フォーカス関連のイベントが貧弱な Delphi ではなかなか難しいようです。

[Delphi-ML:66799][Delphi-ML:66801] で書かれているように、アプリケーションに飛んでくるすべてのメッセージの中からフォーカスの移動に関係するものをチェックしてやることで実現が可能です。実際のツールウィンドウはコード中の TToolWindow を継承して作成することになります。
参照: [Delphi-ML:66799] <アプリケーション> <フォーム>

0326  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
HTMLタグ表記の大文字・小文字変換を行う

コードはSJISを仮定します。

HTMLのコメント部分、""などで囲まれたパラメータ部分などは変換しません。

速度を気にするのであれば IsDBCSLeadByte は避けるべきです。自分で文字テーブルを作れば速くなります。ByteType の方は最適化されていたと思います。通常の用途では速度が気になることは無いかもしれませんね。

function ChangeHTMLTagCase(s:string; Lower:Boolean):string;
const
    sNormal   = 0;
    sInComment= 1;
    sInBracket= 2;
    sInQuote  = 3;
    sInDQuote = 4;
    sAfterEq  = 5;
var
  p: PChar;
  state: Integer;
begin
  state:= 0;
  Result:= s;
  UniqueString(Result);
  p:= PChar(Result);
  while p^<>#0 do begin
    if IsDBCSLeadByte(Ord(p^)) and ((p+1)^<>#0) then begin
      Inc(p, 2);
    end else begin
      case state of
      sNormal:
        if p^='<' then
          if StrLComp(p, '<!--', 4)=0
            then state:= sInComment
            else state:= sInBracket;
      sInComment:
        if p^='-' then
          if StrLComp(p, '-->', 3)=0 then
            state:= sNormal;
      sInBracket:
        case p^ of
        '''': state:= sInQuote;
        '"':  state:= sInDQuote;
        '=':  state:= sAfterEq;
        '>':  state:= sNormal;
        'A'..'Z': if Lower     then p^:= Chr(Ord(p^)+32);
        'a'..'z': if not Lower then p^:= Chr(Ord(p^)-32);
        end;
      sInQuote:
        case p^ of
        '''': state:= sInBracket;
        end;
      sInDQuote:
        case p^ of
        '"':  state:= sInBracket;
        end;
      sAfterEq:
        case p^ of
        '''': state:= sInQuote;
        '"':  state:= sInDQuote;
        ' ':  state:= sInBracket;
        '>':  state:= sNormal;
        end;
      end;
      Inc(p);
    end;
  end;
end;
参照: [Delphi-ML:66840] <WWW> <文字列> <通信> <PASCAL>

0325  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
文字列から括弧の中のみを削除する

特に、全角の括弧と半角の括弧に対応した方法を紹介します。一旦WideStringに直しているところが味噌で、こうすることによってコードの見通しが非常に良くなります。

function DeleteInBracket(s:string):string;
const
  ZenAki = $FF08;
  ZenToji= $FF09;
  HanAki = $0028;
  HanToji= $0029;
var
  PrevPos,Len,BTimes,i:integer;
  ss:WideString;
begin
  ss := s;
  i := 1; PrevPos := 1;Len := Length(ss);BTimes := 0;
  result := '';
  while i < Len+1 do begin
    case Ord(ss[i]) of
      ZenAki,HanAki:begin
        Inc(BTimes);
        if BTimes = 1 then result := result+Copy(ss,PrevPos,i-PrevPos);
      end;
      ZenToji,HanToji:begin
        Dec(BTimes);
        if BTimes = 0 then PrevPos := i+1;
      end;
    end;
    inc(i);
    If BTimes < 0 then Break;
  end;
  if BTimes = 0 then
    result := result+Copy(ss,PrevPos,i-PrevPos)
  else if BTimes < 0 then begin
    ShowMessage('カッコが閉じていません-- ( が足りません' );
    result := result+Copy(ss,PrevPos,i-PrevPos);
  end else begin
    ShowMessage('カッコが閉じていません--  ) が足りません' );
  end;
end;

また、こういった文字列処理には正規表現を使うとかなり楽ができます。たとえば、
http://www2.big.or.jp/~osamu/Delphi/MyLibrary.htm
の BRegExp ユニットを使えば、

uses BRegExp;

function RemoveParentheses(text: string): string;
begin
  Result:= text;
  while brx.Subst('s/(\(|()[^()()]{3,1024}(\)|))//gk', Result) do;
end;

とするだけでできてしまいます。
s/// の k というオプションは、BREGEXP.DLL に固有のもので、正規表現中の SJIS を SJIS として認識してくれるので、2バイト文字にも特殊な処理はいらないです。
参照: [Delphi-ML:66865] <文字列> <PASCAL>

0324  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
列挙型(Enum)の値と文字列との変換

TBrushStyle や TPenStyle などの値を文字列として取り出したい、またはそのような文字列からもとの値に戻したい場合、TypInfoユニットにあるGetEnumNameやGetEnumValueを使用します。

uses TypInfo;

function AlignmentToString(Value: TAlignment): String;
begin
  Result := GetEnumName(TypeInfo(TAlignment),Ord(Value));
end;

こんな感じですね。
参照: [Delphi-ML:66981] <文字列> <PASCAL>

0323  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
TIdentToInt型とTIntToIdent型

IdentToColor は TIdentToInt 型の変換関数で、TIntToIdent型 とともに、整数型のプロパティを見やすくするために登録される関数です。

TColorのような特定の整数型に対し、TIdentToInt 型の関数とTIntToIdent型の関数を RegisterIntegerConsts で登録しておくとコンポーネントの整数型プロパティの特定の値を見やすい文字表現でオブジェクトインスペクタに表示することができます。
また、dfm ファイルも読みやすくなります。

また、実行時に任意の整数型に対して

function FindIntToIdent(AIntegerType: Pointer): TIntToIdent;
function FindIdentToInt(AIntegerType: Pointer): TIdentToInt;

で変換関数が存在するか調べることもでき、整数を見やすい文字表現に変換したり、その逆も可能です。
参照: [Delphi-ML:66991] <コンポーネント開発>

0321  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
2つの TMemo のスクロールを同期させる

Q:
memo1 のスクロールバーを動かすと、memo2 も同じようにスクロールさせたいです。

A:[Delphi-ML:67004] Halbow さん
垂直スクロールバーについてだけ、回答します。Memo1 と Memo2 は Width や Height 、Font.Size など同一のプロパティーであると仮定しています。

TRichEdit で同様のことをする方法が[Tips:322]にあります。

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Memo2: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    Memo1Proc:TWndMethod;
    MKEY:WORD;
    procedure Memo1SuclassProc(var Msg:TMessage);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1Proc := Memo1.WindowProc;
  Memo1.WindowProc := Memo1SuclassProc;
end;

procedure TForm1.Memo1SuclassProc(var Msg: TMessage);
begin
  Memo1Proc(Msg);
  case Msg.Msg of
    WM_VSCROLL:Memo2.Dispatch(Msg);
    CN_COMMAND:
      if (Msg.WParamHi = EN_VSCROLL) then begin
        case MKEY of
          VK_DOWN:Memo2.Perform(EM_LINESCROLL,0,1);
          VK_UP  :Memo2.Perform(EM_LINESCROLL,0,-1);
          VK_HOME:if (GetAsyncKeyState(VK_CONTROL) and $8000) <> 0 then begin
            Memo2.SelStart := 0;
            Memo2.Perform(EM_SCROLLCARET,0,0);
          end;
          VK_END:if (GetAsyncKeyState(VK_CONTROL) and $8000) <> 0 then begin
            Memo2.SelStart := Length(Memo2.Text);
            Memo2.Perform(EM_SCROLLCARET,0,0);
          end;
        end;
        MKEY := 0;
      end;
    CN_KEYDOWN:MKEY := Msg.WParam;
  end;
end;
参照: [Delphi-ML:67004] <Standard> <コンポーネント > [Tips:322]

0322  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
2つの TRichEdit のスクロールを同期させる

2つのTMemo のスクロールを同期させるやり方が[Tips:321]にありますが、実は TRichEdit だと同じようにしてもうまく行きません。

解決方法は、やはり Halbow さんの[Delphi-ML:67313]にあります。

うまく行かないのは、TRichEdit では CN_COMMAND を通じたスクロール通知メッセージ EN_VSCROLL が発行されないためです。EM_SETEVENTMASK というメッセージを送って、LParam に ENM_SCROLL を設定すると、親に EN_VSCROLL を通知するようになります。

親にイベントを通知するかどうかをプログラムで設定するためのこのようなマスクについて、[Delphi-ML:67328]にさらに詳しい説明があります。

  public
    RichEdit1Proc:TWndMethod;
    MKEY:WORD;
    procedure RichEdit1SuclassProc(var Msg:TMessage);
    procedure SyncVScroll;
    procedure PageDown;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses
  richedit;

procedure TForm1.FormCreate(Sender: TObject);
begin
  RichEdit1Proc := RichEdit1.WindowProc;
  RichEdit1.WindowProc := RichEdit1SuclassProc;
end;

procedure TForm1.FormShow(Sender: TObject);
var
  MASK:LPARAM;
begin
  MASK := RichEdit1.Perform(EM_GETEVENTMASK,0,0);
  RichEdit1.Perform(EM_SETEVENTMASK,0,MASK or ENM_SCROLL);
end;

procedure TForm1.RichEdit1SuclassProc(var Msg: TMessage);
begin
  RichEdit1Proc(Msg);
  case Msg.Msg of
    WM_VSCROLL:RichEdit2.Dispatch(Msg);
    CN_COMMAND:begin
      if (Msg.WParamHi = EN_VSCROLL) then
        case MKEY of
          VK_DOWN,VK_UP,VK_PRIOR:SyncVScroll;
          VK_NEXT:PageDown;
          VK_HOME,VK_END:
            if (GetAsyncKeyState(VK_CONTROL) and $8000) <> 0 then
              SyncVScroll;
        end;
    end;
    CN_KEYDOWN:MKEY := Msg.WParam;
  end;
end;

procedure TForm1.SyncVScroll;
var
  Msg:TWMScroll;
begin
  Msg.Msg := WM_VSCROLL;
  Msg.Pos := GetScrollPos(RichEdit1.Handle,SB_VERT);
  Msg.ScrollBar := 0;
  Msg.ScrollCode := SB_THUMBTRACK;
  RichEdit2.Dispatch(Msg);
  Msg.ScrollCode := SB_THUMBPOSITION;
  RichEdit2.Dispatch(Msg);
  Msg.ScrollCode := SB_ENDSCROLL;
  RichEdit2.Dispatch(Msg);
end;

procedure TForm1.PageDown;
var
  Msg:TWMScroll;
begin
  Msg.Msg := WM_VSCROLL;
  Msg.Pos := 0;
  Msg.ScrollBar := 0;
  Msg.ScrollCode := SB_PAGEDOWN;
  RichEdit2.Dispatch(Msg);
end;
参照: [Delphi-ML:67313] [Delphi-ML:67328] <Win95> <Standard> <コンポーネント > [Tips:321]

0320  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
文字列や画像データをリソースに埋め込むためのコンポーネント

プログラム内部で使いたい文字列や画像のデータを、フォーム上に置いた非ビジュアルコンポーネントに保存しておくと、アプリケーションと別にファイルを配布する必要が無くなり、便利な場合があります。

そういった用途に使えるコードが[Delphi-ML:67285]のスレッドに紹介されています。ただし、画像データなどは文字列にエンコードされますので、そのままファイルを持つ場合に比べ、ファイルサイズは大きくなってしまいます。

[Delphi-ML:50664]で中村さんが紹介されたコンポーネントは任意のバイナリデータを内部に持てるようです。
参照: [Delphi-ML:67285] <画像> <文字列> <PASCAL>

0319  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
ActiveX 内部から自身の親ウィンドウのハンドルを得る

Q:
ActiveXコントロールに関する事です。親ウインドウをサブクラス化しようとする時に必要なウインドウハンドルをparent等で、取得することができませんでした。(nilが返される)

A:
IE4 以降の ActiveX コントロールでは、ウィンドウハンドルを持たないことが多い ( ウィンドウレスコントロール ) ので、親ウィンドウのウィンドウハンドルは自分自身のウィンドウハンドルであることが多いです。

Internet Explorer のようなアプリケーションを見て貰えるとわかるかもしれませんが、Windows でいう「ウィンドウ」は一番親にあたるコンテナ1つ以外には一切作成されなかったりします。

それで、ActiveX コントロールが乗っかっているコンテナのウィンドウハンドルはは、InPlaceSite プロパティの GetWindow メソッドを利用すれば得られます。
参照: [Delphi-ML:67312] <その他Windows関連> <Windows>

0318  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
OnShow イベント中で SetFocus すると不具合

フォームにMemoを貼り付けて実験してみたのですが

procedure TForm1.FormShow(Sender: TObject);
begin
  Memo1.SetFocus;
end;

とすると「ソフトを起動したとき、それがアクティブウィンドウになるにもかかわらず、そのソフトを示すタスクバーのボタンが押されない状態で表示される」という症状が出るようです。

Memo1 の TabOrder をゼロにするなど、別の方法でフォーカスをコントロールする必要があるようです。
参照: [Delphi-ML:67321] <アプリケーション> <フォーム>

0317  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
異なるバージョンのDelphiを1つのPCに共存させる

基本的に問題は起こりません。ただし、古いものから順に入れていったほうが良いと思われます。気をつけるべき点としては、

  最終的に *.dpr などのファイルがどのバージョンのDelphiに関連付けられるか。

  BDE のバージョンに依存するコードが無いか。

  delphimm.dll など、同じ名前でバージョンの異なるDLLで問題が起こらないか。

といったところでしょうか。


*.dpr などのファイルを複数のバージョンから簡単に開けるようにするには、レジストリの HKEY_CLASSES_ROOT\DelphiProject\Shell 以下に

  [HKEY_CLASSES_ROOT\DelphiProject\Shell\Open3]
  @="Delphi&3で開く"

  [HKEY_CLASSES_ROOT\DelphiProject\Shell\Open3\command]
  @="\"D:\\Programs\\Borland\\Delphi 3\\BIN\\Delphi32.exe\" \"%1\""

みたいなそれぞれに対応するキーを作っておくと、Explorer から右クリックで任意のバージョンの Delphi でそれを開くことができます。
参照: [Delphi-ML:67330] [Delphi-ML:67329] <開発環境>

0316  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
TreeView で D&D 中の描画処理

TreeView のアイテムをドラッグ・ドロップする際に、挿入位置をグラフィカルに表示するためのサンプルコードです。[Delphi-ML:67348] Halbow さん作。


procedure TForm1.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
var
  AnItem: TTreeNode;
  r:TRect;
begin
  AnItem := TreeView1.GetNodeAt(X, Y);
  if not Assigned(AnItem) then exit;
  r := AnItem.DisplayRect(true);
  with TreeView1.Canvas do begin
    Brush.Color := TreeView1.Color;
    Pen.Color := clRed;
    Font := TreeView1.Font;
    TextRect(r,r.Left+2,r.Top+1,AnItem.Text);
    if (GetAsyncKeyState(VK_CONTROL) and $8000) = 0 then begin
      Brush.Style := bsClear;
      Rectangle(r.Left,r.Top,r.Right,r.Bottom)
    end else begin
      MoveTo(r.Left+1,r.Bottom-1);
      LineTo(r.Right-1,r.Bottom-1);
    end;
  end;
end;
参照: [Delphi-ML:67348] <Win95> <コンポーネント >

0315  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/04/01 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/04/04 osamu 編集
国際化アプリケーションの作り方

日本語フォントを使わない、など基本的なこと以外にも、ダイアログ関連を修正する必要があります。

詳細は過去ログにいくつか存在します。

[Delphi-ML:44083], [Delphi-ML:53963]

「英語版」「国際化」などで検索すると、他にも見つかるかも知れません。

また、Microsoft のサイトに国際化対応ソフトウェア開発のためのページがあります。そこの情報も一読されることをお薦めします。

Top ページ
http://www.microsoft.com/globaldev/

Guidelines
http://www.microsoft.com/globaldev/guides/guides.asp


その他の注意点としては、
・小数点は "." 、リストの区切りは ","、日付は"年月日の順"など
  とは仮定してはいけない。
・そのため 数値←→数値文字列、日付←→日付文字列の変換はロケー
 ルを適切に使用する Delphi の関数/手続きを使用する。
・でも HTML や XML などの属性値における小数点は必ず "."。
あたりは常に意識しておいたほうが良いでしょう。


ちょっと古い本ですが国際化対応のアプリケーションを作ろうとする場合とても参考になる本として、

Developing International Software For Windows 95 and Windows NT
Microsoft Press 発行 Nadine Kano 著
http://www.microsoft.com/globaldev/dis_v1/disv1.asp

があります。オンラインで内容すべてを閲覧できます。
参照: [Delphi-ML:44083] [Delphi-ML:53963] [Delphi-ML:66183] <アプリケーション>

0314  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/02/09 鈴木充 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/02/09 鈴木充 編集
TListView の ... 表示をなくす

>  自作ソフトにTListViewを使っているのですが、ViewStyleをvsListにした場
> 合、実行時にListItemのCaptionを編集して元のCaptionより長くなった場合、
> 入りきらない部分が"..."表示になるのですが、これをすべて表示するように
> するにはどうすればよいのでしょうか?

ListView1.Perform(CM_RECREATEWND, 0, 0);

で表示されるはずですが、選択状態・スクロール状態等は解除されるので必要に
応じて状態を復元する処理を行ってください。
参照: [Delphi-ML:64465] <Win95> <コンポーネント >

0313  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2001/12/05 濱野 rev 1.5
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2001/12/27 濱野 編集
VBのMIDステートメント

Delphi6でVB互換の関数などが追加されました。
Mid関数もそのひとつですが、部分文字列の挿入
であるMidステートメントはありません。

S = "1234567890"
Mid(S, 3, 5) = "ABC"

そこで逆Mid関数ともいうべきMidステートメントを
シミュレートする手続きを作ってみました。

procedure MidInsert(var S1: String; P, N: Integer; S2: String);
var
  L: Integer;
begin
  L := Length(S1);
  if N > (L - P + 1) then
    N := (L - P + 1);
  if N > Length(S2) then
    N := Length(S2);
  Delete(S1, P, N);
  Insert(Copy(S2, 1, N), S1, P);
end;

{ テスト例: }
procedure TForm1.Button1Click(Sender: TObject);
var
  S: String;
begin
  S := '1234567890';
  MidInsert(S, 5, 3, 'ABC');
  ShowMessage(S);
end;

Delphiの文字列型は配列と同様の扱いも出来るのでDelete, Insert, Copyを
使わない別の方法もあります。一時オブジェクトが作成されない分、
こちらの方が高速に動作するかもしれません。

procedure MidInsert(var S1: String; P, N: Integer; S2: String);
var
  L, I: Integer;
begin
  L := Length(S1);
  if N > (L - P + 1) then
    N := (L - P + 1);
  if N > Length(S2) then
    N := Length(S2);
  StrMove(Pchar(@S1[P]), PChar(S2), N);
end;
参照: <文字列> <PASCAL>

0312  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2001/06/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2001/06/11 osamu 編集
ListView をスクロールする

> データセット後に任意の行を表示させたいのですが、
> TopItem プロパティだと read のみで変更できません。
> TStringGrid では TopRow プロパティにて行う事ができますが、
> TListView では何か良い方法はあるのでしょうか?

ListView1->Selected->MakeVisible(false or true);

でスクロールすることができます。
参照: [builder:31260] <Win95> <コンポーネント >

0311  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2001/06/05 濱野 rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2001/06/06 濱野 編集
<Delphi Install Dir>\BINディレクトリの中のファイル

DelphiのインストールされているBINディレクトリには
アプリケーション以外にも様々なファイルが存在します。

その中でIDE(Delphi32.EXE)と同名のファイルがいくつか
存在し、これらはレジストリ以外のIDEの設定を保存する
のに使用されているようです。


[Delphi 3/4]
.dci : コードテンプレート(テキスト)
.dct : コンポーネントテンプレート(バイナリ)
.din : メニューのキャプションで和名を使ったときの
       オブジェクト命名表(テキスト)
.dmt : メニューテンプレート(バイナリ)
.dro : オブジェクトリポジトリのプロパティ(テキスト)
.dsk : IDEの表示状態(テキスト)


Delphi32.dciやDelphi32.dinはテキストエディタで編集
出来ますがその他は不整合が出る恐れがあるためIDE以外
では弄らないほうが無難です。
参照: <開発環境>

0310  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2001/06/02 濱野 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2001/06/02 濱野 編集
フォームの新規作成のデフォルトを変更したい

例えばはじめからScaled=Falseにしたい、
文字は固定ピッチで大きめのフォントにしたい、
フォームの位置、大きさ、表示状態を最大化で標準化したい、etc....

こういう時、元になるフォームを[プロジェクト]-[リポジトリに追加]
でリポジトリに登録しておき、[ツール]-[リポジトリ]で登録した
フォームを選択して、[フォームの新規作成時に使用]にチェックを入れて
おけばスピードバーや[ファイル]-[フォームの新規作成]を選んだときに
リポジトリに登録したものと同じ内容でフォームを作成することが出来ます。

ただしあくまでもコピーが作成されるだけなので元のフォームを変更しても
その変更は反映されません。そのような変更が予想される場合は[ファイル]
-[新規作成]で[継承]を選んで使用すると後々便利です。

コントロールのデフォルト変更には[コンポーネント]-
[コンポーネントテンプレートの作成]を使用するといいでしょう。
Delphi 5からはさらにフレーム機能という便利な機能もあります。
参照: <開発環境> <フォーム>

0309  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2001/05/25 濱野 rev 1.6
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2001/06/02 K.Takaoka 編集
トークンの切り出し

Delphiのライブラリにはstrtokのようなトークンの切り出し
を行なう関数や手続きが無い為、自作することになります。

以下のコードはCopyとIsDelimiter関数を使ったトークンの
切り出し例です。


{$APPTYPE CONSOLE}
program Typing;
uses
    SysUtils;
  
procedure TypingToken(S, Delims: String);
  var
      TokenIn : Boolean; // 進行中であるかのフラグ
      TokenS, TokenLen, // トークンの開始位置と長さ
      I: Integer;
  begin
      TokenIn := False;
      TokenS := 0;
      TokenLen := 0;
      for I := 1 to Length(S) do
      begin
          if not IsDelimiter(Delims, S, I) then begin
              if TokenIn then
                  Inc(TokenLen)
              else begin
                  TokenS := I;
                  TokenLen := 1;
                  TokenIn := True
              end
          end else begin
              if TokenIn then begin
                  Writeln(Copy(S, TokenS, TokenLen));
                  TokenIn := False;
                  TokenLen := 0;
              end
          end
      end;
      if Tokenlen > 0 then
          Writeln(Copy(S, TokenS, TokenLen));
  end; { TypingToken }
const
  Delims = #9#10#13'[](){};, ';
var
  Buf: String;
begin
  while not EOF(Input) do begin
      Readln(Buf);
      TypingToken(Buf, Delims)
  end
end.


※リダイレクトしない場合、最後に[Ctrl]+[Z]を入力
して下さい。
参照: <文字列> <PASCAL>

0274  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/24 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2001/05/14 jkaneko@fujita.co.jp 編集
ディレクトリのファイルを列挙する

以下のようにするのが定石です。
ポイントは,
  2バイト文字の2バイト目に '\' が来る可能性を考慮する
    -> IsPathDelimiter 関数
  FindFirst が成功したときのみ FindClose を呼ぶ。
    -> [Delphi-ML:17508]
  repeat until を使うとループがスマートに書ける
  '.' や '..' といった特殊ディレクトリも列挙される
といったところです。

SearchRec.FindData には見つかったファイルに関するさらに多くの情報が詰まっています。ヘルプを参照しましょう。

procedure Form1.EnumFiles(DirectoryName: string);
var
  SearchRec: TSearchRec;
begin
  // 一番後ろに '\' がついていなければ付ける
    DirectoryName:= IncludeTrailingBackslash(DirectoryName);

  // FindFirst が成功した場合のみ FindClose を呼ぶ必要がある
  if 0=FindFirst(DirectoryName+'*.*', faAnyFile, SearchRec) then try
    repeat
      if SearchRec.Attr and faDirectory <> 0 then begin
        // カレントディレクトリや親ディレクトリをスキップ
        if (SearchRec.Name='.') and (SearchRec.Name='..') then
          Continue;
        // ディレクトリに対する処理
        // SearchRec.Name にディレクトリ名が入っている
        // たとえば、Memo1.Lines.Add('Dir :'+DirectoryName+SearchRec.Name);
      end else begin
        // ファイルに対する処理
        // SearchRec.Name にファイル名が入っている
        // たとえば、Memo1.Lines.Add('File:'+DirectoryName+SearchRec.Name);
      end;
    until 0<>FindNext(SearchRec);
  finally
    FindClose(SearchRec);
  end;
end;
参照: <ファイル>

0202  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/13 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2001/04/05 濱野 編集
Oracle の Number 型で入力値が化ける

BDE の 5.01 よりも前のバージョンで、Oracle 8.0.4 のテーブルのNUMBER型で桁数が7,2の項目に 99.999 と入力すると 10.00 になってしまいます。これは、BDE のバグです。
http://www.borland.co.jp/download/other.html
で BDE を 5.01 以上にバージョンアップすることで回避されます。詳しくは [Delphi-ML:41554] から始まるスレッドを参照してください。
参照: [Delphi-ML:41554] <データベース> <バグ>

0284  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/10/12 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2001/04/05 濱野 編集
メモリマネージャのマルチスレッド対応 -- IsMultiThread

以下,
http://www.borland.co.jp/interbase/tech/ib_udf/delphi_udf_2.html
からの抜粋です。Delphi のメモリマネージャをマルチスレッドで利用する際に IsMultiThread グローバル変数を使わなければならないことを解説しています。

>>>>>>>>>>>>>>>> ここから
スレッドセーフティの問題を解決するために、Inpriseはメモリ管理ルーチンをクリティカル・セクションにラップすることによってメモリ・マネージャをスレッドセーフにしました。クリティカル・セクションについて説明することは本稿の範囲を外れているので詳しくは述べませんが、共用リソースへ秩序正しくアクセスできるようにするものであるとだけ考えておいてください。
Inpriseはその際に、クリティカル・セクションはあまりよく知られていない変数IsMultiThreadがTrueに設定されている場合しか使用されないという規則を設定しました。(IsMultiThreadは、すべてのDelphiユニットによって暗黙的に使用されるユニット 'System.pas' で定義されます。)
つまりこういうことなのです。Delphiは確かにスレッドセーフですが、それは開発者がそのように指示した場合だけです。アプリケーションやライブラリで複数のスレッドを扱う可能性がある場合は、必ずIsMultiThreadをTrueに設定しなければなりません。そうでないと、そのアプリケーションやライブラリはスレッドセーフになりません。(重要:IsMultiThreadはTThreadオブジェクトを使用した場合は暗黙的に設定されます。)
マルチスレッド環境でIsMultiThreadをTrueに設定することの必要性は、いくら強調してもしすぎることはありません。
参照: [Delphi-ML:43304] <PASCAL>

0285  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/10/12 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2001/04/05 濱野 編集
スレッドローカル変数 -- threadvar の使い方

http://www.borland.co.jp/interbase/tech/ib_udf/delphi_udf_3.html
に解説が載っています。
参照: <PASCAL>

0306  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2000/08/25 ITO, Sakuya rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2000/09/08 ITO, Sakuya 編集
整数値が奇数かどうかの判定

Delphiで整数値が奇数かどうかの判定をするには Pascal の標準関数 Odd を使用して次のようにします。


    if Odd( int ) then
      奇数のときの処理
    else
      偶数のときの処理
参照: <PASCAL>

0158  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2000/08/25 ITO, Sakuya 編集
ComCtl32.DLL を配布するには

Delphi4 で作成した ComCtrl32.DLL のバージョンに依存するプログラムに ComCtl32.DLL を添付して配付すると MS の EUL に違反します。CDに入ってる 40comupd.exe を添付すれば問題はないです。

インストーラを利用する場合は /q をオプションにつけて呼び出すとMicrosoft の承諾文章が出ませんがその場合の注意点なんてのもあるので詳しくは Microsoft のサイトの EUL を読んでください。

# まあ、Win95/Win98, WinNT で ComCtl32.DLL に互換性ないし
# ComCtl32.DLL を含めて配付できたとしても面倒ですね。

//2000.08.25 by Sakuya ITO 
その時点で最新のComCtl32.DLLの配布用インストーラ ??comupd.exe は、Microsoftの次のURLからダウンロードできます。これ1本で日本語を含む各国言語に対応しています。
http://www.microsoft.com/msdownload/ieplatform/ie/comctrlx86.asp
参照: [Delphi-ML:30766] <Windows> <配布>

0300  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2000/04/06 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2000/08/12 ITO, Sakuya 編集
Dual CPU 機でフォームのフォントに不具合

開発環境がNT4 + Dual CPUだと、IDEで Code Explorer を表示させていると、 Object Inspector や作ったフォームなどのフォントが勝手に変わるというおぞましい現象がでます。Delphi 4で経験し、Delphi 5でも解消していませんでした。ちょっと使用に耐えなかったので、泣く泣く1個 CPU を外しました。

Delphi 5 Update Pack #1 では治っているそうです。

//追記 2000-08-12
日本語版 Delphi 5 は  Update Pack #1 で修正されますが、US版では UP1 をあてても解消されません。
参照: [Delphi-ML:47436] <バグ>

0303  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2000/06/01 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2000/06/01 osamu 編集
色表現について(RGB, HSV, YUV など)

色を数値で表現する有名な方法として、RGB, HSV, YUV などがありますが、このような色表現同士の相互変換およびこれらを用いた画像処理に関してよくまとめてあるページを紹介します。

カラーのお話 -詳細- :
http://robotics.me.es.osaka-u.ac.jp/~koji/html/color_detail.html
参照: <画像>

0301  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2000/05/26 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2000/05/26 osamu 編集
DLLの初期化・終了処理

D3 のヘルプでは DLL の終了処理に ExitProc を使うように書かれていますが、ExitProc のヘルプには ExitProc が下位互換性のためだけに残してあるものである旨の記述があります。実際(?)、ExitProc はパッケージの使用時に正常に動作しないようです。
このような問題を回避するためには、System ユニットにある DLLProc という変数を使います。

library MyLibrary;

uses Windows, SysUtils;

...

procedure DLLEntry(ul_reason_for_call: DWORD);
begin
  case ul_reason_for_call of
    // これらの値の意味については、Win32SDK の
    // DLLEntryPoint の HELP を参照してください。
    DLL_PROCESS_ATTACH:
        ;
    DLL_PROCESS_DETACH:
        ;
    DLL_THREAD_ATTACH:
        ;
    DLL_THREAD_DETACH:
        ;
  end;
end;

begin
  DllProc := @DLLEntry;
  DLLEntry(DLL_PROCESS_ATTACH);
end.


なお、初期化部分でエラーを発生させて DLL のロードを失敗させたい場合には、

(1) 初期化コードで System.ExitCode を 0以外に設定する。
(2) 初期化コード内で例外を起こす。

のいずれかを行います。
参照: [Delphi-ML:39301] [Delphi-ML:39147] <バグ> <DLL> <PASCAL>

0299  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2000/04/06 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2000/04/06 osamu 編集
Currency型の小数演算結果が不正

Currency型で小数点以下の計算をすると、環境によっては結果が期待した値にならない場合があるそうです。

[例]

procedure TForm1.Button1Click(Sender: TObject);
var
  num1, num2: Currency;
  ret: string;
begin
  num1 := StrToCurr('888888888888888.8888');
  num2 := StrToCurr('0.8888');
  ret := FormatCurr('#,##0.0000', num1 - num2);
  ShowMessage(ret);
end;


この結果が『888888888888888.0128』になります。

この問題を解決するには、Currency や Extended 型の演算を行う前に、Set8087CW(Default8087CW); なるおまじないを入れておけばよいらしい。プロジェクトソースの一行目にでも書いておきましょう。

未確認ながら Delphi4 では治っていると言う報告があります。

[例]

begin
  Set8087CW(Default8087CW);
  num1 := StrToCurr('888888888888888.8888');
参照: [Delphi-ML:47431] <バグ> <PASCAL>

0297  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2000/03/24 濱野 rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2000/03/28 濱野 編集
C++Builder でwith文の代用

BCBには(というかC++には)Pascalのwith文に相当するものが
無い為、クラスのメンバの階層が深いとコード1行あたりの文字数
が無茶苦茶長くなってしまいます。

こんな時はポインタか参照変数を使えば、コード量を減らす事が
出来ます。

void __fastcall TForm1::StringGrid1DrawCell(TObject *Sender, long Col, long Row,
    TRect &Rect, TGridDrawState State)
{   char *s;
    TCanvas &cv = *StringGrid1->Canvas;

    s = StringGrid1->Cells[Col][Row].c_str();
    if (strchr(s, '?') != NULL)
        cv.Font->Color = clRed;
    else
        cv.Font->Color = clBlack;
    cv.TextOut(Rect.Left + 2, Rect.Top + 2,
            StringGrid1->Cells[Col][Row]);

}
参照: <C++>

0298  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2000/03/25 濱野 rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2000/03/28 濱野 編集
あるアドレスを基点とした、変位のアドレスの参照

バイト列を処理する場合、あるアドレスを基点に
そこから+nバイト目を数バイトずつ処理したい場合があります。
特に文字処理や画像処理ではこの様なことは頻繁に行われます。

Cであれば(p+1)* = '\0'; といったアドレッシングを行えますが、
Pascalでは強引な型キャストでも行わない限りこのような書き方は
行えません。

Pchar(Integer(p) + n)^ := #0;

のようになってしまいます。Integerとポインタのサイズが同じ
であるので、このような書き方でも通ります。
しかし、WORD,DWORDなどもっと大きな型の場合SizeOfなどを使っ
て型のサイズを意識した書き方を行わなければなりません。

PWORD(Integer(pw) + Sizeof(WORD) * n)^ := 0;

このような場合、必要なサイズ分の配列のポインタ型を定義して
やり、その変数に代入することでかなり近い事が行える様になり
ます。

例では、'Delphi 'という文字を、10回繰り返し配列
にセットしています。


type
  CharArray = array[0..6] of char;
  PCharArray = ^CharArray;
var
  p: array[0..100] of Char;
  C: PCharArray;
  I : Integer;
begin
  C := @p;
  for I := 0 to 9 do
  begin
     C^[0] := 'D';
     C^[1] := 'e';
     C^[2] := 'l';
     C^[3] := 'p';
     C^[4] := 'h';
     C^[5] := 'i';
     C^[6] := ' ';
     Inc(C);
  end;
  C^[0] := #0;
  Edit1.Text := StrPas(p);
参照: <PASCAL>

0296  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2000/01/02 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2000/01/02 osamu 編集
TField.EditMask の y2k 回避

> DBEditで日付入力させるのですが、関連付けているTTable側の
> 日付フィールドのTFieldのEditMaskプロパティで

>  !99/99/00;1;_

>  ・・とマスクをかけています。
>  すると、西暦を下2桁で打つマスクが有効になるのですが
> 2000/05/05 の意で 00/05/05 とか打つと、期待した
> 2000/05/05にならずに、1900/05/05と表示されてしまいます。

OnCreate イベントハンドラ内で

    TwoDigitYearCenturyWindow := 50;
    ShortDateFormat := 'yyyy/mm/dd';

の設定を行うと,現在の年が1999年のとき,1999年の前後50年である
1949/1/1 から 2048/12/31 の100年を変換の対象として扱います.
ただし D4 からの機能のようです。

詳しくはヘルプか以下のサイトをご覧になられるとよいと思います.

    http://www.inprise.com/devsupport/y2000/

【追記】
Delphi 5 になってから TwoDigitYearCenturyWindow グローバル変数の初期値が「0」から「50」に変更されました。UI 簡略化等で西暦2桁年を使っているような場合、TwoDigitYearCenturyWindow 変数を設定しないまま日付型に変換しているような処理では、処理結果がD4以前と変わる場合があります。

ヘルプの記述(初期値は0)は誤っていますので、ご注意ください。
参照: [Delphi-ML:37908] [Delphi-ML:43093] <データベース> <コンポーネント > <DataControls>

0190  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/19 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2000/01/02 osamu 編集
StringGrid の内容更新を高速に行う

| 少々データ量が大きいので時間を稼ぐため、画面表示の Update を
| 停止したいのですが TStringGrid に BeginUpdate/EndUpdate は
| 無いようです。

【解法1】

描画更新の一次停止
  SendMessage(StringGrid1.Handle, WM_SETREDRAW, 0, 0);

描画更新の再開
  SendMessage(StringGrid1.Handle, WM_SETREDRAW, 1, 0);
  StringGrid1.Refresh;

この方法は、すべての TWinControl に対して有効です。

【解法2】

描画更新の一次停止
  StringGrid1.Rows[0].BeginUpdate;

描画更新の再開
  StringGrid1.Rows[0].EndUpdate;

Rows[0] は Rows[1] でも何でも構いませんが、停止と開始で同じ添字を使わなければなりません。Cols[x] も使えます。一つの Rows[x] または Cols[x] に対して BeginUpdate すると StringGrid のすべての表示更新が停止になります。

BeginUpdate は TStrings の仮想メンバ関数なので、TMemo.Lines とか TListBox.Items などで BeginUpdate を使って TMemo/TListBox などの変更を高速に行うこともできます。

【メモ】

描画更新の再開を必ず行うために、BeginUpdate/EndUpdate は try/finally で保護した方が良いです。

StringGrid1.Rows[0].BeginUpdate;
try
  // 更新処理
finally
  StringGrid1.Rows[0].EndUpdate;
end;

また、BeginUpdate を繰り返し呼んだ場合には EndUpdate を同じ回数呼ばなければ描画は再開されません。さらに、BeginUpdate よりも多く EndUpdate を呼んでしまうとおかしなことになってしまうので注意が必要です。
参照: [Delphi-ML:38146] [builder:19539] <Additional> <コンポーネント >

0289  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/12/19 Atsushi Shinoda rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/12/28 osamu 編集
Windows2000の新APIを使った半透明ウィンドウ

最近、雑誌の付録についていたWin2kRC2をインストールして「半透明ウィンドウを作ってみよう」と思い立ち、TClock(KAZUBON氏作のフリーソフト)のソースファイルを参考に作ってみたので紹介します。
ウィンドウの拡張スタイルにWS_EX_LAYEREDを指定して、SetLayeredWindowAttributesというAPIを使います。このAPIの詳細は http://msdn.microsoft.com/library/psdk/winui/windows_1p6b.htm を参照してください。(英語)
Win2kを使っている方は、ちょっとした遊びのつもりで試してみてください。(^^;;;

FormにScrollBarを1つ置いて、FormCreate, FormDestroy, ScrollBar1Changeのイベントを使っています。ScrollBarを動かすと、Formの透明度が変化します。


{API宣言}
type
  TSetLayeredWindowAttributes
    = function(wnd: HWND; crKey: DWORD;
        bAlpha: BYTE; dwFlag: DWORD): Boolean; stdcall;

const
  WS_EX_LAYERED = $80000;
  LWA_ALPHA = 2;

var
  hLibUser32: THandle;
  MySetLayeredWindowAttributes: TSetLayeredWindowAttributes;


implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var
  p: Pointer;
begin
  hLibUser32 := LoadLibraryA('user32.dll');
  MySetLayeredWindowAttributes := nil;
  if hLibUser32 <> 0 then begin
    p := GetProcAddress(hLibUser32, 'SetLayeredWindowAttributes');
    if p = nil then begin
      FreeLibrary(hLibUser32);
      hLibUser32 := 0;
    end else begin
      MySetLayeredWindowAttributes := TSetLayeredWindowAttributes(p);
    end;
  end;
  if hLibUser32 <> 0 then begin
    SetWindowLong(Handle, GWL_EXSTYLE,
      GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
    ScrollBar1.Position := ScrollBar1.Max;
    ScrollBar1Change(Self);
  end else begin
    ShowMessage('OSが半透明ウィンドウに対応していません!');
    Application.Terminate;
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if hLibUser32 <> 0 then begin
     FreeLibrary(hLibUser32);
     hLibUser32 := 0;
  end;
end;

procedure TForm1.ScrollBar1Change(Sender: TObject);
var
  alpha: Integer;
begin
  if hLibUser32 <> 0 then begin
    alpha := ScrollBar1.Position;
    alpha := alpha * 255 div (ScrollBar1.Max - ScrollBar1.Min);
    if alpha < 8 then alpha := 8;
    if alpha > 255 then alpha := 255;
    MySetLayeredWindowAttributes(Handle, 0, Byte(alpha), LWA_ALPHA);
  end;
end;

参照: [Delphi-ML:44902] <その他Windows関連> <Windows>

0295  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/12/22 濱野 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/12/22 濱野 編集
フォームを1つずつ表示する

TFormの配列をスタック風に管理し、呼び出し元は
呼び出されたフォームを表示後、非表示にします。
これでフォームが1つずつ表示されるようになります。
前のフォームへの復帰も再表示するだけなので速いです。

この手続きにちょっと手を加える事で位置やサイズを
揃える事も出来ます。


unit FmDsp;

interface
uses
  Windows, Messages, SysUtils, Classes, Forms;

  procedure SetMainForm(MainForm: TForm);
  procedure ShowNextForm(FormClass: TFormClass; Form: TForm);
  procedure ShowPrevForm;

implementation

type
  TShowType = (stWithCreate, stShowOnly);
  TFormRec = record
    Form: TForm;
    ShowType: TShowType;
  end;

var
  FormAry: array[0..100] of TFormRec;
  FormTop: Integer = 0;

{ 最上階のフォームの登録、プログラムのスタートアップ時
  に一回だけ呼び出す。 }
procedure SetMainForm(MainForm: TForm);
begin
  FormAry[0].Form := MainForm;
  FormAry[0].ShowType := stShowOnly;
  FormTop := 0;
end;

{ 次のフォームの表示
  FormClass: フォームのクラス名
  Form: フォーム変数名、フォームが自動作成でない場合 nilを指定 }
procedure ShowNextForm(FormClass: TFormClass; Form: TForm);
begin
  Inc(FormTop);
  if Form = nil then
  begin
    FormAry[FormTop].Form := FormClass.Create(Application);
    FormAry[FormTop].ShowType := stWithCreate;
  end else
  begin
    FormAry[FormTop].Form := Form;
    FormAry[FormTop].ShowType := stShowOnly;
  end;

  FormAry[FormTop].Form.Show;
  FormAry[FormTop - 1].Form.Hide;
end;

{ 前のフォームの表示、呼び出された側のフォームのCloseイベントで呼び出し }
procedure ShowPrevForm();
begin
  FormAry[FormTop - 1].Form.Show;
  if FormAry[FormTop].ShowType = stWithCreate then
    FormAry[FormTop].Form.Release
  else
    FormAry[FormTop].Form.Hide;
  Dec(FormTop);
end;

end. { unit FmDsp }
参照: <フォーム>

0294  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/12/21 濱野 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/12/21 濱野 編集
ランダムなレコードの移動

Random関数とMoveByメソッドを使います。
MaxRecordはあらかじめRecordCountプロパティやSELECT * FROM文などで
求めておきます。
利用目的としてテストデータの作成や練習問題の出題などに活用
出来ると思います。


procedure RandomMove(Dataset: TDataSet; MaxRecord: Integer);
var
  X : Integer;
begin
  X := Random(MaxRecord);
  DataSet.First;
  DataSet.MoveBy(X);
end;
参照: <データベース>

0252  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 濱野 rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/11/30 K.Takaoka 編集
スクリーンセーバーの名前を変更する。

スクリーンセーバーに名前を付ける場合、{$D }コンパイラ指令でリソース文字列を埋め込んでもコントロールパネルの画面の設定には反映されません。これはWin95/WinNT4.0からの新GUIに移行した際に、コントロールパネルで表示されるスクリーンセーバーの名前はファイル名そのものに変更されたためです。

しかし、 Delphi のプロジェクト名には日本語を使う事は出来ないので、日本語名を付けたい場合はバッチなどで変更するようにします。

COPY C:\MyProj\MySaver.exe "C:\Windows\まい せーばー.scr"

ただし、ファイル名が 8 バイトまでの場合に、先頭が SS で始まっていると、SS は削除されます。
例) sstest.scr → test

Microsoft の技術文章によると Win16/Win32 ともに、スクリーンセーバーの説明は {$D } にて 25 文字までで指定しておくことになっています。

この値を有効にするためには、ファイル名を 8 文字までにし、すべてを大文字にする必要があります。

ex) SSTEST.SCR

このようにすることで {$D} にて設定した 25 文字までの内容をコントロールパネルのスクリーンセーバーの選択肢として表示できるようになります。
参照: <その他Windows関連> <Windows>

0287  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/11/16 K.Takaoka rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/11/16 K.Takaoka 編集
INI ファイルを扱うもう1つのクラス

みなさん TIniFile を利用して Windows の .ini というファイルを扱われていると思いますが、Inifiles Unit には TMemIniFile というクラスがあります。

TIniFile は Windows API をカプセル化しているので以下のような制限・仕様があります。

・ファイルサイズは 64k bytes までしか認識しない
・1つのセクションの大きさは 32k bytes までしか扱えない
・コメントの概念が存在しない(無意味なキーを使って実現)
・クオーテーションを自動除去する
・Win95/98 では TAB 文字が扱えない
・WInNT では読み書きキャッシングが行われない

最初の2つは容量の制限。
最後の2つは重要で、Win95/98 では TAB 文字を扱えないために

[Section]
Key=Value    タブで区切って Key の意味を説明書き

なんて記述ができてしまい、WinNT でヒドイ目を見ますし、 WinNT では INI ファイルへの読み書きをレジストリに読み書きするためのマッピング処理のため、キャッシュが効かずに低速です。
また、キャッシングの有無に違いがあるため、キャッシュの操作を忘れると INI ファイルを頻繁に読み書きする際に挙動不審になるという弊害もあります。

TMemIniFile は上のような点をすべて解決します。

・ファイルサイズの制限はシステムによってのみ制限される。

・セクションの大きさはファイルサイズによってのみ制限される。

・行頭が ; で開始する行をコメントとして扱う
( ';hoge' のようなキー名は扱えないということです )

・クオーテーションの自動削除は行わない

・OS に関係なく行末までを読み出すことができる

・すべての変更は常にメモリ上にキャッシュされる
( UpdateFile を呼ばずに Free すると変更は無効になります )

と、なります。
TMemIniFile の保存処理で String 型の変数を介すため、2G Bytes までということになりますが、すべての Win32 環境で利用可能な最大メモリ量が 1.995G Bytes ですので、この制限は問題にならないでしょう。
参照: <Windows>

0286  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/10/14 K.Takaoka rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/10/14 K.Takaoka 編集
終了処理の中の例外を見逃すな !


Object Pascal の構造化例外処理の 1 つである try 〜 finally には思わぬメモリリークの可能性があります。

ObjectPascal言語ガイドには次のように記述されています。

-begin-
生成された例外が finally で処理されない場合,その例外は try...finally 文を越えて伝わり,try 節で既に生成されている例外は失われます。したがって,ほかの例外の伝播の妨げにならないよう,ローカルに生成された例外はすべて finally 節で処理するようにしてください。
-end-

つまり、


try
  保護ブロック
finally
  終了ブロック
end;


という記述の中で、保護ブロックの中で例外が発生した場合に、さらに終了ブロックで補足されない例外が発生してはいけないことになります。


A = TA.Create;
try
  A.Start;
  A.MethodCall; // ここで例外が起こる可能性がある !
finally
  A.Stop; // ここでも例外が起こる可能性がある !
  A.Free;  
end;


ではなく


A = TA.Create;
try
  A.Start;
  A.MethodCall; // ここで例外が起こる可能性がある !
finally
  try
    A.Stop; // ここでも例外が起こる可能背がある !
  except
    // A.Stop が失敗したときに必要な処理があればココへ
  end;

  A.Free;  
end;


などと、finally 節内での例外を補足し処理しなければなりません。
# 補足し処理するので try 〜 except 構文を用います。
参照: [Delphi-ML:41492] [Delphi-ML:41495] <PASCAL> []

0283  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/10/12 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/10/12 osamu 編集
Pascal 版 auto_ptr -- Free の必要の無い高機能ポインタ

[Delphi-ML:41732] で、C++ での auto_ptr にあたる高機能ポインタを Delphi 上で実現する方法を中村@NECさんが紹介してくださっています。使用後に Free することに煩わされること無く、TObject/record/MemoryBlock/string/自動配列 を動的に確保して利用することができます。

これを使うと、さまざまなリソースを変数と同じ寿命にしたり、レコードやオブジェクトが破棄されるときに、レコードやオブジェクトからポイントされているさまざまな資源を自動破棄できたりします。
finally より強力です。

技術的には、Interface の参照カウントと、System._Dispose を有効活用しています。_Dispose に付いては [Tips:282] も参照。

例:使用した レコードを自動破棄する

uses AutoPointer;

type
  TXXRecord = record
    str: string;
    :
    :
  end;

procedure TForm1.Timer1Timer(Sender: TObject);
var pRecord: ^TXXRecord;
    AutoPtr: IAutoPtr;
begin
  New(pRecord);
  AutoPtr := TAutoPtr.Create(pRecord, TypeInfo(TXXRecord));
    :
    :
end; // ここで レコードが自動破棄される
参照: [Delphi-ML:41732] [Tips:282] <PASCAL>

0282  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/10/07 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/10/07 osamu 編集
System ユニットの _ で始まる特殊ルーチンの呼び方

_Dispose など、System ユニットには _ で始まる特殊なルーチンがいくつかある。これを無理やり自分で呼び出したいときには,

procedure __Dispose(p: Pointer; typeInfo: Pointer);
asm
  call System.@Dispose
end;

のようにする。
そんなん何につかうん?
と言う人は [Tips:283] を見てみよう。
参照: [Delphi-ML:41727] <PASCAL>

0281  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/10/07 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/10/07 osamu 編集
文字列リソースの編集ツール - 文字列テーブルエディタ

> .RCファイルは手でも書けるということですが、ツールがあれば使
> いたいと思いましたのでヘルプを探してみました。
> すると、Delphi4のヘルプに、「文字列テーブルエディタ」という
> ものがあったのですが使い方が分かりません。

これの表示の仕方ですが、

1.適当なプロジェクトを開く

     もちろん、いじりたいリソースが resourcestring で定義されている
     プロジェクトです。エラーメッセージだけ編集するなら resourcestring
     がなくても OKAY(エラーメッセージもこれでいぢれるんですね!)

2.新規作成 → リソースDLL

     対象になる dfm を追加し、リソースDLLのプロジェクトを作成して
     ください。

3.表示 → プロジェクトグループ

     プロジェクトグループの一覧が出ます。(すでに出てないなら)
     ここから、2 で作成した言語のプロジェクトを開いてください。

4.言語.rc をダブルクリック

     これでOK!
参照: [Delphi-ML:34134] <開発環境> <その他Windows関連> <Windows>

0280  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/10/07 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/10/07 osamu 編集
OnExit ハンドラで次にフォーカスを受け取るコントロールを知る

> OnExit 内で、この後フォーカスが移動するコンポーネントを
> 知ることは出来るのでしょうか?

私はこうやってます。

procedure XXXXXExit(Sender:TObject);
begin
           :
   If ActiveControl = 該当のコンポーネント then
           :
end
参照: [Delphi-ML:34067] <コンポーネント > <その他コンポーネント関連>

0279  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/10/07 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/10/07 osamu 編集
大きなソースブロックのコメントアウト

コーディング中に数十行にわたるコードを一気にコメントアウトしたくなること、ありません?そんな時、どうしましょ?

コード中で {} を使っていなければ、{} でくくればおしまいですが,{} が入っていると、コメントがそこで途切れてしまいます。

以下のような方法を紹介します。

1) {$IFDEF} を使う

{$IFDEF DUMM_DUMMY_DUMMY}
ちょっとコメントアウト

{ コメントアウトしたいコード }

..

{$ENDIF}


2) (* *) を使う

(* や *) は、{ や } と同等に使えますが,コンパイラはこれらを区別するため,コード中に { } を使ってあっても、 (* や *) を使っていなければ,これが便利です。

(* ちょっとコメントアウト

{ コメントアウトしたいコード }

...

*)
参照: [Delphi-ML:34048] <PASCAL>

0278  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/30 篠田 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/30 篠田 編集
アクティブデスクトップを使って壁紙を変更

アクティブデスクトップを使うには、IActiveDesktop を使います。
Microsoftが提供しているリファレンスはhttp://msdn.microsoft.com/library/sdkdoc/shellcc/Shell/IFaces/IActiveDesktop/IActiveDesktop.htmにあります。


uses ShlObj, ComObj;

// IActiveDesktop を使って壁紙を変更する
procedure TForm1.Button1Click(Sender: TObject);
var
  hObj : IUnknown;
  ADesktop : IActiveDesktop;
  str : String;
  wstr : PWideChar;
begin
  hObj := CreateComObject(StringToGUID('{75048700-EF1F-11D0-9888-006097DEACF9}'));
  ADesktop := hObj as IActiveDesktop;
  if OpenDialog1.Execute then begin
    wstr := AllocMem(MAX_PATH);
    StringToWideChar(OpenDialog1.FileName, wstr, MAX_PATH);
    ADesktop.SetWallpaper(wstr, 0);
    ADesktop.ApplyChanges(AD_APPLY_ALL);
    FreeMem(wstr);
  end;
end;

ここでActiveDesktopのクラスIDとして {75048700-EF1F-11D0-9888-006097DEACF9} というマジックナンバーが使われていますが、もしかしたら将来Windowsのバージョンが変わるとこの値も変わる可能性があります。
しかし[Delphi-ML:42104]に書かれているように、アクティブデスクトップはWindowsの準(?)標準コンポーネントですので、恐らく問題ないと思います。
一応、\\HKEY_CLASSES_ROOT\CLSID\{75048700-EF1F-11D0-9888-006097DEACF9}\(標準) に "ActiveDesktop" という文字列が登録されているのを見つけることができます。
参照: [Delphi-ML:42096] <Windows> <デスクトップ>

0233  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/03 西坂良幸 rev 1.6
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/27 西坂良幸 編集
短いファイル名を長いファイル名に変換したい。

長いファイル名を短いファイル名にするのは、APIにGetShortPathNameという関数があるで簡単ですが([Tips:68])、逆の長いファイル名にするのはちょっと工夫が必要です。

APIのFindFirstFile関数を使うとパラメータのWIN32_FIND_DATA構造体のcAlternateFileNameに短いファイル名あり、長いファイル名はcFileNameにあります。
したがって、長い→短い、短い→長いの変換は基本的には、ファイル名を使ってもう一度FindFirstしてやればいいわけです。

効率を無視すれば次のようものでしょうか。
この関数ではドライブレターの大文字小文字は変換されませんので、必要であれば後から大文字に変換してください。

function ShortToLongFileName(ShortName: String):String;
var
  SearchRec: TSearchRec;
begin
  result:= '';
  // フルパス化
  ShortName:= ExpandFileName(ShortName);
  // 長い名前に変換(ディレクトリも)
  while LastDelimiter('\', ShortName) >= 3 do begin
    if FindFirst(ShortName, faAnyFile, SearchRec) = 0 then
      try
        result := '\' + SearchRec.Name + result;
      finally
        // 見つかったときだけ Close -> [Delphi-ML:17508] を参照
        FindClose(SearchRec);
      end
    else
      // ファイルが見つからなければそのまま
      result := '\' + ExtractFileName(ShortName) + result;
    ShortName := ExtractFilePath(ShortName);
    SetLength(ShortName, Length(ShortName)-1); // 最後の '\' を削除
  end;
  result := ShortName + result;
end;

[Tips:273]に同様の結果を得るCOM版があります。
参照: [Delphi-ML:3333] [Delphi-ML:7320] [Delphi-ML:7322] [Delphi-ML:17508] [Tips:68] [Tips:273] <ファイル>

0108  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/27 西坂良幸 編集
デスクトップにあるアイコンの数と位置を知りたい。

通常デスクトップには色々なアイコンがありますが、それらの数とそれらが置かれている位置(X,Y座標)をアプリケーション中で把握したいのです。

デスクトップを覆っているリストビューコントロールに対して、メッセージを投げるなりAPIを発行するなりしてください。
Commctrl.pas の ListView_XXXXXX関数は、結構豊富です。テストすることをお勧めします。

以下サンプルプログラムです。

uses Commctrl;

// デスクトップリストビューのハンドル所得
function GetDesktopListView: HWnd;
var
  Hdl:HWnd;
begin
   Hdl := FindWindow('Progman', 'Program Manager');
   if not (Hdl = 0) then
   begin
     Hdl := FindWindowEx(Hdl, 0, 'SHELLDLL_DefView', '');
     if not (Hdl = 0) then
     begin
       result := FindWindowEx(Hdl, 0, 'SysListView32', '');
       exit;
     end;
   end;
   result := 0;
end;

// アイコンの表示数をえる
procedure TForm1.Button1Click(Sender: TObject);
var
  hLView:Hwnd;
begin
  hLView := GetDesktopListView;
  if not (hLView = 0) then
    Label1.Caption := AnsiString('Count: ')
       + IntToStr(ListView_GetItemCount(hLView))
  else
    Label1.Caption := 'ハンドルの取得に失敗しました';
end;


詳細は、Win32 SDK Referenceを調べてください。
また、IE4&Active Desktopをインストールしている環境では動かないかもしれません。
参照: [builder:5968] <Windows> <アイコン>

0276  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/27 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/27 西坂良幸 編集
アップリケーションにサウンドリソースを埋め込んで使いたい。

リソースファイルには、*.WAVファイルを埋め込むことが出来ます。しかし、これは手作業で行わなければなりません。

たとえば、TEST.WAV というファイルがあるとします。
・このファイルをproject1.dprと同じディレクトリに起きます。
・メニューから[ファイル|新規作成−テキスト]を選びます。
・このテキストに、

   MYSOUND WAVE TEST.WAV

と1行を書き込み、PROJTEST.rc(適当でよい)という*.rcファイルとしてセーブします。
  ※ TEST.WAVが同じディレクトリでないときはフルパスで指定
  ※ リソースは、原則、大文字です。
・binディレクトリにあるbrcc32.exeで、*.resファイルを作成します。

   brcc32.exe PROJTEST.rc

  ※ コマンドラインEXE であることに注意
・project1.dprを開き作成したリソースファイルを書き込みます

・・省略・・・
{$R *.RES}               // デフォルトである
{$R projtest.res}        // ←ここを書き加える

begin
  Application.Initialize;
・・省略・・・


以上で、プロジェクトの再構築を行えば、EXEの中にTEST.WAVのデータが埋め込まれます。
Demosディレクトリの中にあるリソースエクスプローラの見本をコンパイルして、このプロジェクトのEXEファイルを読み込むと、WAVEリソースが出来ていることがわかります。

以下は、簡単な使用方法です。

// 音を鳴らす
procedure TForm1.Button1Click(Sender: TObject);
begin
  PlaySound('MYSOUND',HInstance, SND_RESOURCE or SND_ASYNC);
end;

// 停止させる
procedure TForm1.Button2Click(Sender: TObject);
begin
  PlaySound(nil, 0, SND_RESOURCE);
end;


上記の場合、SND_RESOURCE は必ず必要です。
また、SND_ASYNCをSND_SYNCにすると終わるまで制御が戻りません。
参照: [Delphi-ML:8787] [Delphi-ML:12338] <アプリケーション> <その他Windows関連> <開発環境> <Windows>

0201  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/13 西坂良幸 rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/27 K.Takaoka 編集
入力された漢字のひらがなを取り出す

WM_IME_COMPOSITIONメッセージをとらえて、ImmGetCompositionString関数を処理するのですが、受け取るのはコントロールの場合が多いので、少し工夫が必要です。

この例は、フォームに2つのTEditがあり、
TEdit1で漢字入力すると、TEdit2で入力に利用した平仮名がとれます。
ふりがなを取得するには別の方法を利用します.
// interface
type
  TForm1 = class(TForm)
    Edit1: TEdit;        // 漢字変換を行う
    Edit2: TEdit;        // フリガナを受け取る
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    FDefEditProc: TWndMethod;
    procedure EditWndProc(var Message: TMessage);
  public
  end;

// implementation
uses imm;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // 本来のWndProcを待避する
  FDefEditProc := Edit1.WindowProc;
  // 新しいWndProcを設定
  Edit1.WindowProc := EditWndProc;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  // 恐いので元に戻す
  Edit1.WindowProc := FDefEditProc;
end;

// 新しいEdit1のWndProc--ここでメッセーージを捕らえる
procedure TForm1.EditWndProc(var Message: TMessage);
var
  IMC: HIMC;
  Len: integer;
  Str: string;
begin
  with Message do
  begin
    if (Msg = WM_IME_COMPOSITION)
      and ((LParam and GCS_RESULTREADSTR) <> 0) then
    begin
      IMC := ImmGetContext(Edit1.Handle);
      Len := ImmGetCompositionString(IMC, GCS_RESULTREADSTR, nil, 0);
      SetLength(Str, Len + 1);
      ImmGetCompositionString(IMC, GCS_RESULTREADSTR, PChar(Str), Len + 1);
      ImmReleaseContext(Edit1.Handle, IMC);
      SetLength(Str, Len);
      Edit2.Text := Str;
      // Edit2.Text := Edit2.Text + Str; // でもよい
      // イベントを作成してもよい
    end;
    FDefEditProc(Message);
  end;
end;


実際は、メッセージを捕まえるコンポーネントのイベントなどで、必要なコントロールに渡すのがいいでしょうか。

参照: [Delphi-ML:41353] [Delphi-ML:41355] <System> <その他コンポーネント関連> <コンポーネント >

0218  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/26 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/27 西坂良幸 編集
エクスプローラからファイルをドラッグ&ドロップする

一度はやってみたいんですよね。MLでも多いスレッドです。
「Delphi2.0Q&A120選」(大野元久著)にもあります。

WM_DropFilesメッセージを捕まえて、DragQueryFile関数で処理するわけですが、受け取る側のスタイルを準備しなければなりません。
これは、一般的なフォームのOnCreateイベントで
DragAcceptFiles(Handle,True);
を使うよりも、CreateParamsをオーバーライドするのがベターだそうです。

// 定義部
 type
  TForm1 = class(TForm)
  ・・省略・・
  private
    procedure CreateParams(var Params: TCreateParams);override;
    procedure WMDropFiles(Var Msg: TWMDropFiles); Message WM_DropFiles;
  public
  end;

// 実装部
procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  // 受け取れる準備をする
  Params.ExStyle := Params.EXStyle or WS_EX_ACCEPTFILES;
end;

// ファイル1個の場合−−メモに読み込ませる。
procedure TForm1.WMDropFiles(Var Msg: TWMDropFiles);
Var
  FileName: Array[0..MAX_PATH] of Char;
Begin
  Count := DragQueryFile(Msg.Drop, 0, FileName, SizeOf(FileName));
  Memo1.Lines.LoadFromFile(String(FileName));
  DragFinish(Msg.Drop);
End;

//今度は複数の場合−−リストボックスにファイル名
procedure TForm1.WMDropFiles(Var Msg: TWMDropFiles);
Var
  FileName: Array[0..MAX_PATH] of Char;
  i, Count: integer;
Begin
  ListBox1.Items.clear;
  // 第二パラメータを-1にするとドロップ数が取得できる
  Count := DragQueryFile(Msg.Drop, DWord(-1), FileName, SizeOf(FileName));
  for i := 0 to count - 1 do
  begin
    DragQueryFile(Msg.Drop, i, FileName, SizeOf(FileName));
    ListBox1.items.add(String(FileName));
  end;
  DragFinish(Msg.Drop);
End;

最後のDragFinishを忘れないように。
参照: [Delphi-ML:3137] [Delphi-ML:8536] [Delphi-ML:31274] <ShellApi> <Windows> <ファイル>

0207  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/19 西坂良幸 rev 1.10
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/27 西坂良幸 編集
アプリケーションを常駐させてタスクトレイに登録したい

コンポーネントをつかう人が多いんでしょうね。MLでは少ない話題です。このようなAPLを何十本も作るんでなければ、直接コーディングしてみませんか。
要領は、APIのShell_NotifyIcon関数を使うことです。TaskTrayへの登録と削除は簡単にできます。
頭を悩ますのは、どんなアイコンを使うのかと、TaskTrayに送られてくるメッセージを自分で決めなければならないことです。

const
  WM_MY_TRAYICON = WM_APP + $300; // 適当です

// ProcessMesageに配慮−−無くても良い
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  // WM_QUIT メッセージを受け取る時
  if Application.Terminated then
  begin
    ShowWindow(Application.Handle, SW_HIDE);
    Visible := False;
    Action := caNone;
  end;
end;

// アイコンをトレイに登録−−ここではメインアイコンを使用
procedure TForm1.CreateTaskBarIcon;
var
  NotifyData: TNotifyIconData;
begin
  with NotifyData do
  begin
    cbSize := SizeOf(TNotifyIconData);
    Wnd    := hWndTrayIcon;
    uID    := 0;
    uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
    szTip  := 'Traybar Tip';
    hIcon  := Application.Icon.Handle;
    uCallbackMessage := WM_MY_TRAYICON;// 独自に定義
  end;
  Shell_NotifyIcon( NIM_ADD, @NotifyData );
end;

// アイコンを削除
procedure TForm1.DeleteTaskBarIcon;
var
  NotifyData: TNotifyIconData;
begin
  with NotifyData do
  begin
    cbSize := SizeOf(TNotifyIconData);
    Wnd    := hWndTrayIcon;
    uID    := 0;
  end;
  Shell_NotifyIcon( NIM_DELETE, @NotifyData );
end;

// 起動直後はトレイにアイコン表示のみ
procedure TForm1.FormCreate(Sender: TObject);
begin
  // uTaskBarRecrate は TForm1 の private に UINT 型で宣言
  // 新しい UtilWindow を作成し、ブロードキャストメッセージのみを受け取らせる
  uTaskBarRecreate := RegisterWindowMessage('TaskbarCreated');
  // hWndTrayIcon は TForm1 の private に HWND 型で宣言
  // メッセージ送信先を指定
  hWndTrayIcon := AllocateHWnd(TaskTrayWndProc);

  CreateTaskBarIcon;
  ShowWindow(Application.Handle,SW_HIDE);
  Application.ShowMainForm := False;
end;

// 終了した時にトレイのアイコンを削除
procedure TForm1.FormDestroy(Sender: TObject);
begin
  DeleteTaskBarIcon;
  DeallocateHWnd(hWndTrayIcon);
end;

// タスクトレイに来るWM_MY_TRAYICONメッセージを受信
procedure TForm1.TaskTrayWndProc(var Msg: TMessage);
var
  ps: TPoint;
begin
  Case Msg.LParam of
    WM_LBUTTONDBLCLK:
      begin
        Visible := true;
        ShowWindow(Application.Handle,SW_SHOW);
        //ShowWindow(Application.Handle,SW_RESTORE);
      end;
    WM_RBUTTONUP:
      begin
        GetCursorPos(ps);
        SetForegroundWindow(Handle);
        // フォームにポップアップメニューがあるとする
        PopupMenu1.Popup(ps.x,ps.y);
        PostMessage(Handle, WM_NULL, 0,0);
      end;
    else
      // タスクバーが移動・再構築された場合に消えたアイコンを再生成
      if (Msg.LParam = LongInt(uTaskBarRecreate)) then
        CreateTaskBarIcon;
  end;
end;

AllocateHWnd 関数の戻り値のウィンドウハンドルを利用すれば他のメッセージ受信先/送信先として利用できるので、TrayIcon のメッセージ送信先に利用しました。
参照: [Delphi-ML:2536] [Delphi-ML:11821] [Delphi-ML:35250] <System> <Windows> <フォーム> <コンポーネント >

0275  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/26 西坂良幸 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/26 西坂良幸 編集
ファイルを削除してゴミ箱に移動させたい。

SHFileOperation関数を使えば、ファイル単位でもフォルダーごとでもゴミ箱に移動させることができます。
注意事項としては、必ずフルパスでなければならないということです。

ちょっと変な関数名ですが・・・

Uses Shellapi;

procedure SendToRecycleBin(FileList: TStrings; Dlg: boolean);
var
  LpFileOp:TSHFILEOPSTRUCT;
  FileNames: string;
  i: integer;
begin
  if FileList.Count = 0 then exit;
  // #0をデリミタとした文字列を作る
  for i := 0 to FileList.Count - 1 do
    FileNames := FileNames + FileList[i] + #0;
  // ターミネイタにもう一度#0をつける
  FileNames := FileNames + #0;
  with LpFileOp do
  begin
    Wnd := Application.Handle;
    wFunc := FO_DELETE;
    pFrom := PChar(FileNames);
    pTo:= nil;
    fFlags := FOF_ALLOWUNDO;
    if not Dlg then fFlags := fFlags or FOF_SILENT;
    hNameMappings := nil;
    lpszProgressTitle := nil;
  end;
  SHFileOperation(LpFileOp);
end;

// テスト
procedure TForm1.Button1Click(Sender: TObject);
var
  Flist :TStrings;
begin
  Flist := TStringlist.Create;
  try
    Flist.Add('C:\Program Files\Borland\Delphi 4\Projects\*.~df');
    Flist.Add('C:\Program Files\Borland\Delphi 4\Projects\*.~pa');
    SendToRecycleBin(FList, true);
  finally
    Flist.free;
  end;
end;
参照: [Delphi-ML:3443] [Delphi-ML:5005] <ShellApi> <Windows> <ファイル>

0122  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/25 西坂良幸 編集
TSaveDialogでファイルタイプが変更されたらファイル拡張子を変更したい

Excelなどの「名前を付けて保存」でしているように 選択されたファイルタイプに応じて拡張子の部分を変更したいのですが。

TSaveDialogをはりつけて、Filterプロパティを以下のようにしたとします.
Filter  -> 'テキストファイル(*.txt)|*.txt|アイコンファイル(*.ico)|*.ico|カンマテキスト(*.csv)|*.csv|'

uses  Dlgs,Commdlg;

procedure TForm1.SaveDialog1TypeChange(Sender: TObject);
var
  DlgParent: HWND;
  StrFileName, StrExt: string;
begin
  DlgParent := GetParent(TSaveDialog(Sender).Handle);
  Case SaveDialog1.FilterIndex of
    2: StrExt := '*.ico';
    3: StrExt := '*.csv';
    else StrExt := '*.txt';
  end;

  StrFileName := ChangeFileExt(TSaveDialog(Sender).FileName, StrExt);
  SendMessage(DlgParent, CDM_SETCONTROLTEXT, Edt1, Longint(PChar(StrFileName)));
end;

// テスト
procedure TForm1.Button1Click(Sender: TObject);
begin
  SaveDialog1.Execute;
  Label1.Caption := SaveDialog1.FileName;
end;


Filterを切り分けて、Filterindexに拡張子をセットする処理ルーチンは省略していますが、やり方はわかると思います。
参照: [Delphi-ML:38586] [builder:7802] <ダイアログ>

0196  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/07/07 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/24 K.Takaoka 編集
Windows 特殊フォルダの Class ID List


SHGetFolderPath, SHGetFolderLocation, SHGetSpecialFolderPath, SHGetSpecialFolderPath といった API で Windows が特別に扱うフォルダのパスを得ることができます.
これらのフォルダはユーザ環境によって異なるため, 常に API を利用して取得するようにすると問題のないアプリケーションが開発できます.

フォルダ名:CSIDL名(プログラムで利用できる定数名)
{CLSIDL}
ディレクトリ名

マイコンピュータ: CSIDL_DRIVES
{20D04FE0-3AEA-1069-A2D8-08002B30309D}
マイコンピュータはディレクトリにリンクしていません

ネットワークコンピュータ: CLSIDL_NETWORK, CSIDL_NETHOOD
{208D2C60-3AEA-1069-A2D7-08002B30309D}
ネットワークコンピュータはディレクトリにリンクしていません

マイドキュメント: CSIDL_PERSONAL
{450D8FBA-AD25-11D0-98A8-0800361B1103}
C:\My Document
C:\WinNT\Users\UserName\Personal

ごみ箱: CSIDL_BITBUCKET
{645FF040-5081-101B-9F08-00AA002F954E}
C:\Recycled.Bin

コントロールパネル: CSIDL_CONTROLS
{21EC2020-3AEA-1069-A2DD-08002B30309D}
コントロールパネルはディレクトリにリンクしていません

プリンタ: CSIDL_PRINTERS, CSIDL_PRINTHOOD
{2227A280-3AEA-1069-A2DE-08002B30309D}
プリンタフォルダはディレクトリにリンクしていません


他にも

CSIDL_COOKIES, CSIDL_DESKTOP, CSIDL_DESKTOPDIRECTORY, CSIDL_FAVORITES, CSIDL_FONTS, CSIDL_HISTORY, CSIDL_INTERNET, CSIDL_INTERNET_CACHE, CSIDL_PROGRAMS, CSIDL_RECENT, CSIDL_SENDTO, CSIDL_STARTMENU, CSIDL_STARTUP, CSIDL_TEMPLATES

などといったものが Win95/98/NT4/2K で共通に利用できます.

WinNT/2K においては CSIDL_COMMON_*** という形式で全ユーザ共通のフォルダを指定できるものが多くあり, Win2K にはさらに多くの定数が新設されています.

基本的には MSDN などの Microsoft の公式な文書を読むことになりますが, HKEY_CLASSES_ROOT\CLSID\ 以下を探すことで, アプリケーション固有のものを発見することができます.

たとえば、
「受信トレイ」
{00020D75-0000-0000-C000-000000000046}


といったものです.

これらを利用して 'プリンタ.{2227A280-3AEA-1069-A2DE-08002B30309D}' という名前のフォルダを作ることで、任意の場所にプリンタフォルダを追加できます。

参考: http://msdn.microsoft.com/library/sdkdoc/Shell/Functions/CSIDL.htm
参照: [Delphi-ML:10601] <Windows> <ファイル>

0271  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/23 西坂良幸 rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/24 K.Takaoka 編集
TOpenDialog(TSaveDialog) の初期フォルダをシステムフォルダ(デスクトップなど)に設計する

TOpenDialog はデフォルトで Windows95 であればカレントディレクトリ, WindowsNT であればホームディレクトリ, Windows98 であればパーソナルディレクトリを表示します.

InitialDir プロパティにディレクトリ名を設定すれば変更できますが, システムフォルダの場所は一定ではないので実行時に指定する必要が出てしまいます.
# システムフォルダの位置を知るには API と CLSID 定数を利用します.
# その方法については [Tips:196] を参照してください.

これらのフォルダを設計時に設定することができます.
CLSID の値に :: をつけたもの, たとえば

::{20D04FE0-3AEA-1069-A2D8-08002B30309D}

などを InitialDir プロパティに設定します.
この値の一覧は Delphi の ShellAPI Unit や [Tips:196] にあります.
参照: [Delphi-ML:9689] [Delphi-ML:39628] [Tips:196] <ダイアログ>

0141  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/24 西坂良幸 編集
TOpenDialogで、Executeメソッド実行時に表示位置を変えたい。

TOpenDialogは、OnShowイベントの段階では、位置がすでに決まっているようです。調べてみると、何回かWM_NOTIFYが送られますが、NMHDR構造体のCodeメンバーがCDN_INITDONEになるダイアログの初期化時を捕まえるとうまくいくようです。(ただし、これでも最初のExecute時しか効果ありません。D4のみ?)
以下のような拡張ダイアログコンポが紹介されています。

// 定義部
type
  TQueryDlgPosEvent = procedure(Sender: TObject; var pt: TPoint) of object;
  ThtOpenDialogEx = class(TOpenDialog)
  private
    FQueryDlgPos: TQueryDlgPosEvent;
  protected
    procedure DefaultHandler(var Message); override;
    procedure DoQueryDlgPos; virtual;
  published
    property OnQueryDlgPos: TQueryDlgPosEvent read FQueryDlgPos write FQueryDlgPos;
  end;

// 実装部n

procedure ThtOpenDialogEx.DefaultHandler(var Message);
begin
  inherited;
  with TWMNotify(Message) do
    if (Msg = WM_NOTIFY) then
      if (NMHdr^.Code = CDN_INITDONE) then
        DoQueryDlgPos;
end;

procedure ThtOpenDialogEx.DoQueryDlgPos;
var
  DlgHandle: THandle;
  Rect: TRect;
  pt: TPoint;
begin
  if Assigned(FQueryDlgPos) then
  begin
    DlgHandle := GetParent(Handle);
    GetWindowRect(DlgHandle, Rect);
    pt.x := (GetSystemMetrics(SM_CXSCREEN) - Rect.Right + Rect.Left) div 2;
    pt.y := (GetSystemMetrics(SM_CYSCREEN) - Rect.Bottom + Rect.Top) div 3;
    FQueryDlgPos(Self, pt);
    SetWindowPos(DlgHandle, HWND_TOP, pt.X, pt.Y, 0, 0,
        SWP_NOSIZE or SWP_NOZORDER);
  end;
end;

// テスト
procedure TForm1.Button1Click(Sender: TObject);
var
  OpenDialogEx:ThtOpenDialogEx;
begin
  OpenDialogEx:=ThtOpenDialogEx.Create(self);
  try
    with OpenDialogEx do
    begin
      OnQueryDlgPos := QueryDlgPos;
      Execute;
    end;
  finally
    OpenDialogEx.Free;
  end;
end;

procedure TForm1.QueryDlgPos(Sender: TObject; var pt: TPoint);
begin
  Pt.x := 800;
  pt.y := 600;
end;


追記:
DefaultHandlerメソッドのかわりに、WndProcメソッドをオーバーライドしてもほぼ同じ結果が得られます。
以下は、イベントの代わりに、InitialLeft, InitialTop、というプロパティを設定しています。
procedure ThtOpenDialogEx.WndProc(var Message: TMessage);
var
  DlgHandle: THandle;
begin
  inherited WndProc(Message);
  if (Message.Msg = WM_NOTIFY) then
    if (TWMNOTIFY(Message).NMHdr^.Code = CDN_INITDONE)
      and not ((FInitialLeft < 0) or (FInitialTop < 0)) then
    begin    // 負数のときは処理しない
      DlgHandle := GetParent(Handle);
      SetWindowPos(DlgHandle, 0, FInitialLeft, FInitialTop, 0, 0, SWP_NOSIZE or SWP_NOZORDER);
    end;
end;

参照: [Delphi-ML:12600] [Delphi-ML:24640] <ダイアログ> <Dialogs> <コンポーネント >

0272  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/23 西坂良幸 rev 1.1.1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/23 西坂良幸 編集
シェルのデスクトップやマイコンピュータをプログラムから開きたい。

デスクトップは、
HKEY_CURRENT_USER\SoftwareMicrosoft\Windows\CurrentVersion\
Explorer\Shell Folders の Desktopを参照すればOKです。
たいていの場合 'C:\Windows\デスクトップ'(実際は半角です)

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShellExecute(Handle, 'Open', 'EXPLORER.EXE', 'C:\Windows\デスクトップ', '', SW_SHOW);
  // 'デスクトップ'は半角です。
end;


また、主要なシステムフォルダーは
HKEY_CURRENT_USER\SoftWare\Classes\CLSIDの値を使えばOKです
たとえば、マイコンピュータは。
procedure TForm1.Button4Click(Sender: TObject);
begin
  ShellExecute(Handle,'Open','EXPLORER.EXE','::{20D04FE0-3AEA-1069-A2D8-08002B30309D}','',SW_SHOW);
end;

という具合です。CLSIDについては、詳しくはCOMの知識が必要になります。
・ネットワークコンピュータ
・マイドキュメント
・ゴミ箱
などのCLSIDの値は、[Tips:196]にあります。

コントロールパネルは。アプリケーションですので。
procedure TForm1.Button2Click(Sender: TObject);
begin
  ShellExecute(Handle,'Open','Control.exe','','',SW_SHOW);
end;


// たとえばコントロールパネルの中の'アプリケーションの追加と削除'なら
procedure TForm1.Button3Click(Sender: TObject);
begin
  ShellExecute(Handle,'Open','Control.exe','Appwiz.cpl','',SW_SHOW);
end;
参照: [Delphi-ML:9689] [Delphi-ML:16991] [Delphi-ML:37909] [Delphi-ML:39661] <Windows>

0016  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/23 西坂良幸 編集
TOpenDialogが表示された時のフォーカスを変えたい。


TOpenDialogは、ダイアログを開いたとき最初のフォーカスは、ファイル名になっています。
TabOrderは、ファイル名(Edit)->ファイルの種類(ComboBox)->
>それを、上下キーで指定のフォルダから選択できるように、開く(Button)->キャンセル(Button)->ファイル場所(ComboBox)->選択リスト(ListView)の順です。

たとえば、選択リスト(ListView)にフォーカスをおく場合は、
OpenDialogのOnShowイベントで以下のようにすればどうでしょう。

procedure TForm1.OpenDialog1Show(Sender: TObject);
begin
  // ひとつ前のコントロールにフォーカスを戻す
  PostMessage(OpenDialog1.Handle, WM_NEXTDLGCTL, -1, 0);
  // リバースしないので、何かキーを押してリバースさせる
  keybd_event(VK_SPACE, 0, 0, 0);
  keybd_event(VK_SPACE, 0, KEYEVENTF_KEYUP, 0);
end;
参照: [Delphi-ML:33851] <ダイアログ>

0068  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/22 osamu 編集
長いファイル名を短いファイル名に変換したい

GetShortPathName APIを使いましょう。

function LongToShortFileName(Const LongName: String):String;
var
  Len: integer;
begin
  Len := GetShortPathName(PChar(LongName), PChar(result), 0);
  SetLength(result, len);
  if GetShortPathName(PChar(LongName), PChar(result), Len) = 0 then
    Raise EConvertError.Create('ファイルが見つかりません。');
end;

ファイルが実在しないと例外が発生します。

逆に、短いファイル名を長いファイル名にするには [Tips:233] を見てください。
参照: [builder:5092] [Tips:233] <Windows> <ファイル>

0270  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/21 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/21 osamu 編集
Delphi4 で TBitmap を pf1bit で使うときの注意点(不具合回避)

TBitmap は pf1bit で Width/Height が共に 0 以上になると 1bpp DIB を作成しますが、2色のカラーテーブルを初期化していません。

さらに、Width/Height が 0 以上の TBitmap を PixelFormat で pf1bit へ形式変換する場合
    DDB -> 1bpp DIB 変換なら 黒白2色のカラーテーブルが作られます。 -> OK
    DIB -> 1bpp DIB 変換なら 古いカラーテーブルが引き継がれます。   -> バグ
となります。

結局、PixelFormat := pf1bit; がまともに動くのは、古い PixelFormat の値が pfDevice で Width > 0, Height > 0 の場合だけです。たとえば,以下のようなコードで問題が発生します。

  Bitmap1 := TBitmap.Create;        // スクリーン互換 DDB を作成
  Bitmap1.PixelFormat := pf1bit;    // Size がゼロのまま 1bit DIB に変換
  Bitmap1.Width := 1000;
  Bitmap1.Height := 1000;

これを、

  Bitmap1 := TBitmap.Create;        // スクリーン互換 DDB を作成
  Bitmap1.Width := 1000;
  Bitmap1.Height := 1000;
  Bitmap1.PixelFormat := pf1bit;    // Size を設定してから 1bit DIB に変換

とすれば、正常に動きます。ただし、一旦ばかでかい DDB ができてしまうので,リソースの消費が問題になります。この場合には、以下のようにするのがベストでしょう。

  Bitmap1 := TBitmap.Create;        // スクリーン互換 DDB を作成
  Bitmap1.Width := 1;
  Bitmap1.Height := 1;
  Bitmap1.PixelFormat := pf1bit;    // 小さな Size を設定してから 1bit DIB に変換
  Bitmap1.Width := 1000;
  Bitmap1.Height := 1000;           // 大きくする

基礎知識:
    TBitmap.Monochrome=True;    は 1bit DDB
    TBitmap.PixelFormat:=pf1bit; は 1bit DIB
を作成します。

この辺は、Delphi Magazine 3/4/5号で中村@NECさんが詳しく説明して下さっています。
参照: [Delphi-ML:42732] <画像> <バグ>

0254  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/15 おばQ rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/21 おばQ 編集
TListを特定のクラスのListにする方法

みなさん、TListって使ってます?
TListはItemsプロパティで、いろんなオブジェクトにアクセスできる
とても便利なコレクションクラス(リスト)です。
これを利用すればコンポーネント配列なんて特に必要なくなりますし、
自分で作ったクラスが保持できます。

しかし、こういうコーディングしていませんか?

TMyClass( TList.Items[i] ).MyClassProperty

実際には特定のクラスのみItemsに保持したい場合が多いのに
TListはPointerを保持する汎用的なListなので
キャストしないとプロパティやメソッドが使えません。
TListのItemにアクセスするたびに
毎回キャストしなくてはいけないのであれば、大変めんどうですし
コーディング量も増えて綺麗ではありません。

そういう場合はTListを継承してしまいましょう。
とてもあっさりと可能です。

type節に追加します
  TMyClassList = class(TList)
  private
    function Get(Index: Integer): TMyClass;
    procedure Put(Index: Integer; const Value: TMyClass);
  public
    property Items[Index: Integer]: TMyClass read Get write Put; default;
  end;

実装部には
{ TMyClassList }
function TMyClassList.Get(Index: Integer): TMyClass;
begin
  Result :=  TMyClass( inherited Get(Index) );
end;

procedure TMyClassList.Put(Index: Integer; const Value: TMyClass);
begin
  inherited Put( Index, Value );
end;

TMyClassは適当に変えてください。
これだけで、TListを使うのとほとんど同様に
TMyClassList.Items[i].MyClassProperty
という風にスッキリと使えます。

また、TListを継承する時ついでに
  TMyClassList = class(TList)
  public
    destructor Destroy; override;

destructor TMyClassList.Destroy;
var
  i: Integer;
begin
  for i := 0 to Self.Count - 1 do
    Self.Items[i].Free;
  inherited Destroy;
end;

と実装しておくとListが破棄される時に
所有するItemも一緒に破棄されるので
結構便利に使えるでしょう。
参照: <PASCAL>

0266  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/19 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/20 西坂良幸 編集
エクスプローラのように、アプリケーションにブラウザページをつくりたい。

本来なら、DelphiにあるHRMLコンポーネント等を使うんでしょうが、これも、D4まででは、結局AktiveXなので、オフィス97をお持ちの方は、Webブラウザコントロール(WebBrowser)を使うととても簡単です。

これは、オフィス97のCD-ROM
 \VALUPACK\ACCESS\WEBHELP\Webrowse.hlpに
Web ブラウザ コントロールとして、詳しい解説があります。
この実体は、Shdocvw.dll というDLLファイルです。

メニューで[コンポーネント|ActiveXコントロールの取り込み]を開いて下さい。
ダイアログのリストに、Microsoft Internet Contorols(version 1.??) というのがあります。
無かったら、Windows\Systemディレクトリの、Shdocvw.dllを探して追加して下さい。
クラス名の欄に、TWebBrowser_V1、TWebBrowser と表示されたら、インストール実行で、パレットのActiveXページにコンポーネントがインストールされます。

ページ切り替えは省略しますが、
フォームにこのコンポーネントを貼り付け、Alignを決めます。

procedure TForm1.FormShow(Sender: TObject);
begin
  WebBrowser1.GoHome;
end;

とすれば、Web表示が出来上がりです。

URLを指定するときは、Navigate、やNavigate2 メソッドを使います

たとえば、URLがファイル(*.htm)なら、

procedure TForm1.Button1Click(Sender: TObject);
var
 url: WideString;
 flg,Tmp: OleVariant;
begin
  if OpenDialog1.Execute then
  begin
    url := OpenDialog1.FileName;
    flg := 0;
    WebBrowser1.Navigate(url, flg, Tmp, Tmp, Tmp);
  end;
end;


メソッドや、プロパティの詳細は、上記のヘルプファイルを見て下さい。
264番のインターネットエクスプローラオブジェクトと似通っているようです。
参照: [Delphi-ML:25232] [Delphi-ML:37104] <その他Windows関連> <WWW> <ShellApi> <Windows> <通信>

0265  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/19 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/20 西坂良幸 編集
フォームのアイコンをアニメーションにしたい

タイマーイベントを使って、AppliCationのアイコンをきりかえてやればアニメーションGIFのような効果ができます。

プロジェクトの*.resファイルに、アイコン'ICON1'-'ICON5'をアニメ風に作成して下さい。

フォームにStartBtn、StopBtn の2個のボタンとTTimer(Intervalプロパティを100程度)を貼り付けます。
  private 部に
    IconStat: integer;
    ICon1,ICon2,ICon3,ICon4,ICon5: TIcon;
と書き加えます。

// あらかじめリソースを参照するアイコンを作成
procedure TForm1.FormCreate(Sender: TObject);
begin
  ICon1 := TIcon.create;
  ICon1.Handle := LoadIcon(HInstance,'ICON1');
  ICon2 := TIcon.create;
  ICon2.Handle := LoadIcon(HInstance,'ICON2');
  ICon3 := TIcon.create;
  ICon3.Handle := LoadIcon(HInstance,'ICON3');
  ICon4 := TIcon.create;
  ICon4.Handle := LoadIcon(HInstance,'ICON4');
  ICon5 := TIcon.create;
  ICon5.Handle := LoadIcon(HInstance,'ICON5');
  Application.Icon.Handle := ICon1.Handle;
  IconStat := 1;
end;

// 破棄
procedure TForm1.FormDestroy(Sender: TObject);
begin
  ICon1.Free;
  ICon2.Free;
  ICon3.Free;
  ICon4.Free;
  ICon5.Free;
end;

// スタート
procedure TForm1.StartBtnClick(Sender: TObject);
begin
  Timer1.Enabled := true;
end;

// ストップ
procedure TForm1.StopBtnClick(Sender: TObject);
begin
 Timer1.Enabled := false;
 IconStat := 1;
 Application.Icon.Handle := ICon1.Handle;
end;

// タイマーイベントでアイコンの切り替え
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  If IconStat = 5 then IconStat :=1
  else IconStat := IconStat + 1;
  Case IconStat of
  1: Application.Icon.Handle := ICon1.Handle;
  2: Application.Icon.Handle := ICon2.Handle;
  3: Application.Icon.Handle := ICon3.Handle;
  4: Application.Icon.Handle := ICon4.Handle;
  else Application.Icon.Handle := ICon5.Handle;
  end;
end;


4−5個アイコンを作るとスムースです。
注意事項として。resファイルを書き直した時は、[プロジェクトの再構築]を行ってから実行して下さい。resの変更が反映されません。また、アイコンの名称はイメージエディタでは、デフォルトでIcon?となりますので、オリジナルな名称に変えて下さい。

また、イメージリストを使えば、以下のようにすれば、ほぼ同じ結果が得られます。

var
  IconCount : integer;
procedure TForm1.Button1Click(Sender: TObject);  // start
begin
    Timer1.Interval := 100;
    Timer1.Enabled := True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
    if IconCount >=ImageList1.Count then IconCount := 0;
    ImageList1.GetIcon(IconCount, Application.Icon);
    inc(IconCount);
end;

この場合は、使用するアイコンイメージは、リソースに入りませんので、プログラムアイコンとして使用出来ません。必要ならば、リソースからイメージリストへロードする処理を加えて下さい。
参照: [Delphi-ML:42725] [Delphi-ML:42748] <アイコン> <フォーム>

0267  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/19 おばQ rev 1.1.1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/20 K.Takaoka 編集
MDI等で二重起動を防止して新しいファイルを開く


なんか変なタイトルですいません。
Exe本体やExeのショートカットにファイルをドラッグ&ドロップ(以下D&D)した時にアプリケーションが起動してファイルが開く処理を実現したとします。
アプリケーションが起動している最中にもう一度、Exe本体やショートカットにファイルを D&D するともう一つアプリケーションが起動しませんか?あまり素敵じゃないですよね?

貴方がお望みの動作は、たぶんアプリケーションは一つだけ立ち上がっていて MDI 子ウィンドウで新しく D&D されたファイルを開きたいというものでしょう?そこで以下のTipsを利用します。

・二重起動の判定(t269)
・簡易アプリケーション間通信(t268)

t269 のままでは Halt 手続きによってアプリケーションが終了してしまうので、引数に渡されたファイル名を t268 を利用して送信します.

halt 手続きの変わりに呼び出される CopyDataToOld 手続きを作成します.


procedure CopyDataToOld;
var
  wnd: HWND;
begin
  { 既に存在している TForm1 を探す }
  Wnd := FindWindow('TForm1', nil);  
  if Wnd<>0 then
  begin
    // SIGNATURE_FILEOPEN 定数で ParamStr の内容を送信するとする
    // SendMessage(wnd, WM_COPYDATA, ...); // t268 参照
  end;
end;

そして、送信された WM_COPYDATA を受け取るメッセージハンドラを実装します。

インターフェス部

type
  TForm1 = class(TForm)
  // …省略…
  private
    procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;
  public
  end;

実装部

procedure TForm1.WMCopyData(var Msg: TWMCopyData);
var
  ArriveStr: String;
begin
  if Msg.CopyDataStruct.dwData=SIGNATURE_FILEOPEN then
  begin
    // 受信処理 : t268 参照
    // ArriveStr に受け取った文字列が入るとする

    // ※ 受け取ったファイル名で開く
    FileOpen(String(pcData));  //例です
  end;
end;

以上のソースでは※印部分では D&D されるファイルは一つだとしか考慮していません。
参照: [Delphi-ML:42587] [Tips:268] [Tips:269] <その他Windows関連> <アプリケーション> <Windows>

0269  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/19 K.Takaoka rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/19 K.Takaoka 編集
二重起動の判定

該当記事で以下のようなユニットが紹介されています

unit Unique;

interface

uses
  Windows, Sysutils;

implementation

var
  UniqueName : string;
  hMutex: THandle;

initialization
  UniqueName := ExtractFileName(ParamStr(0));
  hMutex := OpenMutex(MUTEX_ALL_ACCESS, false, pchar(UniqueName));
  if hMutex <> 0 then
  begin
    CloseHandle(hMutex);
    Halt;
  end;
  hMutex := CreateMutex(nil, false, pchar(UniqueName));

finalization
  ReleaseMutex(hMutex);
end.

Mutex は同じ名前のものは 2 つ存在することはできません.
ここでは ExtractFileName(ParamStr(0)) を mutex の名前にしています.
複数のアプリケーションで(意図的な場合は除いて)同じ名前の mutex を作成しようとすると問題になる可能性が高いため、できるだけユニークな名前を割り当てるようにしなければなりません.

また、このユニットではすでに mutex が存在していた場合に Halt 手続きを実行しています.
該当部分を書きかえることによって二重起動時に任意のアクションを起こすことができるでしょう.
参照: [Delphi-ML:6240] <その他Windows関連> <Windows>

0268  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/19 K.Takaoka rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/19 K.Takaoka 編集
簡易アプリケーション間通信

Win32 環境で 2 つのアプリケーションがお互いに通信する方法は非常に多くあります.
同じコンピュータ上の 2 つのフォーム(ウィンドウ)の間で簡単に通信を行うには WM_COPYDATA というメッセージを使うという方法があります.
これは、2 つのフォームが同じアプリケーションであっても違うアプリケーションであっても問題ありません.

WM_COPYDATA を利用するには, 相手の WindowHandle が分かっている必要があります. Form1 の WindowHandle は Form1.Handle で取得できます.
画面内にあるフォーム(ウィンドウ)の検索は FindWindow API を用いて行うことができます.
ここでは相手の WindowHandle の得方については言及しません.

受信側では TForm1 のインターフェス部にメッセージハンドラを追加します. private でかまわないでしょう.

  private
    procedure WMCopyData(var msg: TWMCopyData);
      message WM_COPYDATA;


送信側では、CopyDataStruct 構造体に送信するデータを格納してから、WM_COPYDATA を送信します.


procedure TForm1.Button1Click(Sender: TObject);
var
  buf: PChar;
  i: Integer;
  cd: TCopyDataStruct;
begin
  cd.dwData := SIGNATURE_STRING;
  cd.cbData := Length(Memo1.Lines.Text)+1;
  cd.lpData := StrAlloc(cd.cbData);
  try
    StrCopy(cd.lpData, PChar(Memo1.Lines.Text));
    SendMessage(Handle, WM_COPYDATA, WPARAM(Handle), LPARAM(@cd));
  finally
    StrDispose(cd.lpData);
  end;
end;


この例では, Memo1 の内容を自分自身に送信しています.
このメッセージの受信側実装は


procedure TForm1.WMCopyData(var msg: TWMCopyData);
var
  i: Integer;
  buf: PChar;
begin
  if msg.CopyDataStruct.dwData=SIGNATURE_STRING then
  begin
    buf := StrALloc(msg.CopyDataStruct.cbData);
    try
      StrCopy(buf, msg.CopyDataStruct.lpData);
      Memo2.Lines.Text := buf;
    finally
      StrDispose(buf);
    end;
  end
  else
    inherited;
end;


このような感じになります. この例では受信した文字列を Memo2 に設定しています.
受信した CopyDataStruct の内容は読み出し専用になっていますので注意してください.

双方で使われている SIGNATURE_STRING は適当な DWORD 値を指定します.たとえば

  cosnt SIGNATURE_STRING: DWORD = $00000001;

のような値でも良いでしょう, 重要なのは送信側と受信側で同じ値を使うことです.

CopyDataStruct には 3 つの要素 dwData と cbData と lpData があります.
lpData に目的のデータを格納し cbData には lpData に保持されたデータのバイト数を格納します.
dwData は独立して利用できますが, 一般的には lpData の内容を示すユニークな値を格納しておきます.
参照: [Delphi-ML:4527] [Tips:90] <通信>

0264  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/19 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/19 西坂良幸 編集
インターネット エクスプローラを起動したい/その情報を取得したい

オフィス97のCD-ROM
 \VALUPACK\ACCESS\WEBHELP\Webrowse.hlpに
InternetExPlorerオブジェクトの詳しい解説があります。
これを使うと、OLE オートメーションを利用してインターネット エクスプローラのインスタンスを作成し、操作することができます。

このオブジェクトはComObj.pas で定義されているCreateOleObject関数で使えます。
変数とメソッドを定義し、
  private
    IExp:Olevariant;
  public
    procedure ExecuteIE(Url: String = '');


uses ActiveX,ComObj;

procedure TForm1.ExecuteIE(Url: String = '');
begin
  if IUnKnown(IExp) = nil then
  begin
    IExp := CreateOleObject('InternetExplorer.Application');
    IExp.Height:=400;
    IExp.Width:=600;
    IExp.MenuBar:=1;
    IExp.StatusBar:=1;
    IExp.ToolBar:=1;
    IExp.Visible:=true;
  end;
  if Url = '' then
    IExp.Gohome
  else
    IExp.Navigate(Url);
end;

// ホームで起動
procedure TForm1.Button1Click(Sender: TObject);
begin
  ExecuteIE;
end;

// URLを指定して起動
procedure TForm1.Button2Click(Sender: TObject);
begin
  ExecuteIE('http://www2.big.or.jp/~osamu/Delphi/Tips');
end;

// インターネット エクスプローラを終了するには、Quit メソッドを使用します。
procedure TForm1.Button3Click(Sender: TObject);
begin
  if IUnKnown(IExp) <> nil then
  begin
    IExp.Quit;
    IExp:= Unassigned;
  end;
end;


便利なプロパティやメソッドがたくさんあります。
参照: <その他Windows関連> <ShellApi> <Windows>

0024  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.5
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/19 西坂良幸 編集
Sqr()の結果が負になる!?

Sqr()関数は引数にIntegerを渡すと結果にIntegerが返ってきます。

ヘルプで
    function Sqr(X: Real): Real;
と書いてあるにもかかわらずです。
Sqr()関数は引数が整数型だと結果は整数型で返り、
引数が実数型だと結果は実数型で返ります。
これが仕様です。

なお、整数型を渡した場合、オーバーフローのチェックは行われません。そのため渡す値によっては

    sqr(x)+sqr(y)

の結果が負になる場合があり、これを実行時に検出することはできません。自乗した場合の結果が Integer の制限を越えることが予想できる場合には、引数を実数型にキャストして渡す必要があります。
参照: [Delphi-ML:7250] <バグ> <計算> <PASCAL>

0044  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.5
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/17 おばQ 編集
起動中のブラウザからURLを取得する/ブラウザにURLをセットする方法

DDE を用いれば、ブラウザが現在表示している URL を取得したり、逆に URL をブラウザにセットすることができます。

Form1 に DdeClientConv1 を配置し、ConnectMode プロパティを ddeManual にします。

type  TBrowserType = (btIE, btNN);
const BrowserServices : array [TBrowserType] of string =
                ('Iexplore', 'netscape');

を用意して、

function TForm1.GetBrowserURL(BrowserType: TBrowserType): string;
var
  ServiceStr, TopicStr, ItemStr, UrlStr: String;
  UrlPch: PChar;
begin
  ServiceStr := BrowserServices[BrowserType];
  TopicStr   := 'WWW_GetWindowInfo';
  UrlStr     := '';

  with DdeClientConv1 do
  begin
    if SetLink(ServiceStr, TopicStr) then
      if OpenLink then
      begin
        ItemStr:= '0xFFFFFFFF';
        UrlPch := RequestData(ItemStr);
        UrlStr := UrlPch;
        StrDispose(UrlPch)
        CloseLink;
      end;
  end; {with}

  Result := copy( UrlStr, 2, Pos('",',UrlStr) - 2);
end;

GetBrowserURL(btIE) とすると起動中のインターネットエクスプローラの URL を文字列として取得出来ます。btNN とするとネットスケープから URL を取得します。
ブラウザは起動しておいてください。

URL をセットするには以下の関数を使います。

function TForm1.SetBrowserURL(BrowserType: TBrowserType; UrlStr: String): Boolean;
var
  ServiceStr, TopicStr: String;
  Pch: PChar;
begin
  Result := false;

  ServiceStr := BrowserServices[BrowserType];
  TopicStr   := 'WWW_OpenURL';

  with DdeClientConv1 do
  begin
    if SetLink(ServiceStr, TopicStr) then
      if OpenLink then
      begin
        Pch := RequestData( PChar(UrlStr) );
        CloseLink;
        StrDispose(Pch);
        Result := true; {成功すれば戻り値がTrue}
      end;
  end; {with}
end;

IE の場合は起動中のブラウザ画面にセットされた URL のページが表示されます。NN の場合は新しく Window を開いてページを表示するようです。
参照: [Delphi-ML:42589] [Delphi-ML:42621] <その他Windows関連> <WWW> <Windows> <通信>

0263  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/16 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/16 osamu 編集
StringGrid でセル編集終了のイベントを得たい

StringGrid で表計算のような動作をさせようとすると、セル編集終了のイベントで、関係し合うセルの再計算を行いたくなります。OnSetEditText というイベントが利用できそうなのですが、このイベントはユーザのキー入力の一文字ごとに発生するため使えません。

で、少なくとも Delphi3 では、以下のようにすると、セル編集終了時を検出することができます。

これは、セル編集終了時に、OnSetEditText が2度続けて同じ Value 値で呼び出されるという現象を利用しています。Delphi の今後のバージョンで動作が保証されるわけではありませんので、注意が必要です。また、Options に goAlwaysShowEditor が含まれている場合には、Enter キーで値を確定することができないという不具合(?)が生じます。

procedure TForm1.StringGrid1SetEditText(Sender: TObject; ACol, ARow: Integer;
        const Value: String);
const
    MagicValue = 'd0308|ybh<_lfds$t083q()'#1#5; // 入力値としてありえない値
    PreviousEditorValue: string = MagicValue;   // C でいう static 変数の代り
begin
    if Value<>PreviousEditorValue then begin    // まだ編集中
        PreviousEditorValue:= Value;
        Exit;
    end;

    // 編集終了時には、同じ値が二度続けて送られてくる
    case ACol of
    0: ;
    1: ;  // ここで入力後の処理
    2: ;
    end;

    // 次回のために絶対にありえない文字列を代入
    PreviousEditorValue:= MagicValue;
end;
参照: [Delphi-ML:42663] <Additional> <コンポーネント >

0262  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/16 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/16 osamu 編集
TStringGrid の列の ReSize イベントの取得

ColWidthsChanged を overrideすることで、実現できます。

■interface

TStringGrid_Ex = class(TStringGrid)
private
  FOnColWidthsChange:TNotifyEvent;
ptotected
  procedure ColWidthsChanged; override;
published
  property OnColWidthsChange:TNotifyEvent
    read  FOnColWidthsChange
    write FOnColWidthsChange;
end;

■implementation

procedure TStringGrid_Ex.ColWidthsChange;
begin
  inherited;
  if Assigned(FOnColWIdthsChange) then
    FOnColWidthsChange(Self);
end;


■利用方法

procedure TForm1.Grid1OnColWidthsChange(Sender:TObject);
var
  idx :Longint;
begin
  //条件
  //  Grid1.ColCount = Grid2.ColCountであること

  if Sender = Grid1 then begin
    for idx:=0 to Grid1.ColCount-1 do begin
      Grid2.ColWidths[idx] := Grid1.ColWidths[idx];
    end;
  end else begin
      for idx:=0 to Grid2.ColCount-1 do begin
        Grid1.ColWidths[idx] := Grid2.ColWidths[idx];
      end;
    end;
  end;
end;

同様に、RowHeighsChangedもoverrideできます。
参照: [Delphi-ML:31921] <Additional> <コンポーネント >

0234  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/04 西坂良幸 rev 1.8
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/16 osamu 編集
Pascal で文字列を効率良く扱う(例:文字列を逆順にする)。

MLの全体がコーディングの勉強ですが、[Delphi-ML:42129] から始まる一連のスレッド「文の逆」は、Pascal で文字列(文)を効率良く扱う様々なコーディングの例が示されています。いろいろな方法があることがわかりますね。勉強になります。

実装で気をつけるのは、2バイト文字と、CR/LF の順を入れ替えないようにしなければならないというところです。

(1) 何も考えないで作る
function StrReverse(s: string): string;
var i: Integer;
    LeadBytes: set of Char;
begin
  i:= 1;
  Result:= '';
  LeadBytes:= SysUtils.LeadBytes + [#13];
  while i<=Length(s) do begin
    if s[i] in LeadBytes then begin
        Result:= Copy(s,i,2) + Result;
        i:= i+2;
    end else begin
        Result:= Copy(s,i,1) + Result;
        i:= i+1;
    end;
  end;
end;

この関数が、ループ中で何百回も一度に呼ばれるとは考えにくいので、実はこれで十分かもしれませんが、後学のために工夫の余地を考えてみることにしましょう。

(2) [Delphi-ML:42142] 基本的な形です。(ただし、処理速度を考慮しています。)
function StrReverse(const s: string): string;
var
  i, L: integer;
begin
  L := Length(s);
  SetLength(result, L);
  i := 1;
  while i <= L do
  begin
    if (s[i] in SysUtils.LeadBytes) or
      ((s[i] = #13) and (S[i+1] = #10))
    then
    begin
      result[L-i] := s[i];
      result[L-i+1] := s[i+1];
      Inc(i, 2);
    end
    else
    begin
      result[L-i+1] := s[i];
      Inc(i);
    end;
  end;
end;

コード(1)も同じなんですが、実はこれデータによっては s[Length(s)+1] を参照してしまいます。不正な文字列の場合は無視するにしても、改行を常に #13#10 と仮定して(1)のように比較部分を単純化するか、i=Length(s) のときには s[i+1] を参照しないか、どちらかにしないと意味が無いです。

ま、それは置いといて、、、
 文字列の生成回数を減らす(Copy 関数は値を返すのに string を生成する)
 文字列の足し算の回数を減らす(足し算も内部で新しい文字列を作る)
 関数の呼び出しを最小限にする(Length の値を L にキャッシュ)
 i:=i+1 の代わりに Inc 関数を使う(C での ++ 演算子と同等)
 引数に const をつける(これも文字列の生成を押さえられる)
などが高速化部分。効果が大きい順に並べてみました。今回の目的には後ろの3つはたいした違いは生みません。特に、Length 関数のコストはそれほど大きくないことは覚えておいても良いと思います。逆に文字列の連結は時間がかかるので注意。

(3) [Delphi-ML:42157] ポインタの使い方の見本のような例ですね。
function StrReverse(const s: string): string;
var
  p, pn, pr: PChar;
begin
  SetLength(Result, Length(s));
  p := PChar(s);
  pr := PChar(Result) + Length(s);
  while p^ <> #0 do begin
    if (p^ = #13) and ((p+1)^ = #10) then
      pn := p + 2
    else
      pn := CharNext(p);
    System.Move(p^, (pr-(pn-p))^, pn-p); Dec(pr, pn-p);
    p := pn;
  end;
end;

コード(2)から、さらに [ ] の使用を無くして高速化を図ったものです。Pascal の [ ] は C の [ ] に比べてかなり時間がかかります。CharNext という関数も覚えていてよさそうですね。でも高々2バイトの転送に System.Move を使うよりは、(2) のように SysUtils.LeadBytes を使って判定して1バイトずつ ^ で転送した方がずっと速いでしょう。

2バイト文字の判断で2バイト目が #0 でないことを確認しないと、不正なデータが与えられた時に、メモリを破壊してシステムをハングアップさせる危険性があります。p_end:=PStr(s)+Length(s); としておいて、while の比較を、p<=p_end とすればハングアップを防ぎつつさらに高速化にもなりますね。

(4) [Delphi-ML:42148] ポイントは再帰ですね。
function StrReverse(const s: string): string;
var
  L: integer;
begin
  result := '';
  L := Length(s);
  if L = 0 then
    exit;
  if IsDBCSLeadByte(Byte(s[1])) then
    result := StrReverse(copy(s, 3, L-2)) + s[1] + s[2]
  else
    result := StrReverse(copy(s, 2, L-1)) + s[1];
end;

コードはすっきりしますが、速度的には(1)よりずっと悪いです。なにより、長〜い文字列を渡すと再帰が深くなりすぎて、スタックオーバーフローを起こしかねないので、この目的には使えません。えっと、この例だけ改行文字を考慮していないですね。

(5) [Delphi-ML:42155] WideStringを使う発想です。
function StrReverse(s: WideString): WideString;
const
  WCharCR : WideChar = #$0d;
  WCharLF : WideChar = #$0a;
var
  i  : Integer;
begin
  SetLength(Result, Length(s));
  for i:=1 to Length(s) do begin
    if (s[i] = WCharCR) and (s[i+1] = WCharLF) then begin
      s[i] := WCharLF; s[i+1] := WCharCR;
    end;
    Result[Length(s)-i+1] := s[i];
  end;
end;

WideString を使うことで、2バイト文字を考えなくても良くなります。もし、改行文字が含まれないことが分かっていれば、if 文は必要無くなりますから、非常にすっきりしたコードになります。WideString <-> string の変換はキャストの必要無く自動で行われます。変換は時間がかかりますが、初めと終わりの2回だけなので、この場合には気にする必要は無いでしょう。美しいコードです。

(6) [Delphi-ML:42173] 文字列の両端から交換していこうというアイディア
function StrReverse(const s: string): string;
var
  len, i : integer;
  L, R : pchar;
  tmp : char;
  p : pchar;
begin
  Result := s;
  len := length(s); if len = 0 then exit ;
  p := PChar(Result);
  L := p; R := L + len - 1;
  while L < R do
  begin
    if (L^ in Sysutils.LeadBytes) or
      ((L^ = #13) and ((L+1)^ = #10)) then
    begin
      tmp := L^; L^ := (L+1)^; (L+1)^ := tmp;
      inc(L, 2);
    end
    else
      inc(L);
  end;
  L := p; R := L + len - 1;
  for i := 1 to (len div 2) do
  begin
    tmp := L^; L^ := R^; R^ := tmp;
    inc(L); Dec(R);
  end;
end;

うーん何やら複雑。改行文字や2バイト文字が無くて、なおかつ関数が
    procedure StrReverse(var s: string): string;

のように、直接引数を書きかえるものなら、メリットはあるかもしれません。。。この場合には、ほぼ最後の for 文だけになってしまいます。

基本的に、ループの中で何度も繰り返し呼ばれるので無ければ、実行速度を求めて読みにくいコードを書くのは愚とされます。したがって、この問題に限って言えば、(1) や (5) のように分かりやすく書けるものがお勧めです。
ただし、実行効率を考慮しないといっても限度があり、(4) のように、長い文字列を渡すとスタックオーバーフローを起こすようなコードは、いかに見やすくても不適当でしょう。

あなたならどう書きますか? アイデアある方はどんどん加筆して下さい。
参照: [Delphi-ML:42134] <文字列> <PASCAL>

0261  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/15 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/15 osamu 編集
漢数字で位取り表示

数字を漢数字で位取り表示(4桁単位)する関数を作ってみました。

function RhKnjNumber(const Num: Currency): string;
begin
  Result := FormatFloat('####"兆"####"億"####"万"####円', Num);
  while True do {余計な文字を取り去る}
    if ByteType(Result, 1) = mbLeadByte then
      Result := Copy(Result, 3, Length(Result) - 2)
    else
      Break;
end;
参照: [Delphi-ML:34500] <文字列> <PASCAL>

0260  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/15 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/15 osamu 編集
Win98 でタイトルバーのグラデーション色を得る

const
  COLOR_GRADIENTACTIVECAPTION   = 27;
  COLOR_GRADIENTINACTIVECAPTION = 28;

という前提で、GetSysColor() API を使用してください。
DWORD の色がかえります。( TColor に代入できます )

どーせやるなら、

const
  COLOR_GRADIENTACTIVECAPTION   = 27;
  COLOR_GRADIENTINACTIVECAPTION = 28;
  clGradientActiveCaption   = $80000000 + COLOR_GRADIENTACTIVECAPTION;
  clGradientInactiveCaption = $80000000 + COLOR_GRADIENTINACTIVECAPTION;

としておくと便利かもしれません。
この状態で、 Delphi4 の ColorToRGB のソースを見るかぎりでは

  ColorToRGB(clGradientActiveCaption)

は正常に動作します。

ところで…この定数ですが、、、、Delphi4 にも定義されていないようです。
# たんに、私が未確認なだけでしょうか?

勝手に Graphic.pas (Desktop 版では Graphic.int)に書き足しておいても問題はないと思うのですが…。。。
参照: [Delphi-ML:34285] <描画>

0259  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/15 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/15 osamu 編集
子に override されたメソッドを孫クラスから呼び出す

TClassA というクラスがあって、TClassB がその子供 TClassC がさらにその子供であるとします。
TClassB が override した TClassA の手続き AProc を、TClassB 内から呼び出すには、inherited AProc; と書けば良いのは皆さんご存知だと思いますが、TClassC の中から呼び出すにはちょっとしたテクニックが必要になります。

type
TClassA = class
  protected
    procedure AProc; virtual;
end;

TClassB = class(TClassA)
  protected
    procedure AProc; override;
end;

とし、

type
TClassC = class(TClassB)
  protected
    procedure AProc; override;
end;

という場合です。これには、ダミーのクラス TClassD を使って、以下のようにします。

procedure TClassC.AProc;
type
    TClassD = class(TClassA) end;    {4番目のダミークラス}
    TAProc  = procedure of object;   { AProc の型 }
var
    method: TMethod;
begin
    with method do begin
        Data := Self;
        Code := @TClassD.AProc;
    end;
    TAProc(method);

    //  TClassC 特有の処理
end;

スコープをうまく操作して「Delphi を騙してる」感じです。
参照: [Delphi-ML:2958] [Delphi-ML:34246] <PASCAL>

0258  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/15 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/15 osamu 編集
TRichEdit.Add でリソース不足

> 現在、通信関係のソフトを開発しているのですが、RichEdit の Add メソッドで
> EOutOfResources(リソース不足)の例外が発生するようになってしまい
> ました。
>
> RichEdit の MaxLength には、20000000 の値を入れており、まだそんなに
> Add していない状態で発生します。

Lines.Add メソッドで読み込んでいるということですね。
私も同じトラブルを経験しましたが、Lines.Add の代わりに、一旦 TMemoryStream に書き出してから、LoadFromStream メソッドを使うという方法で回避しました。
参照: [Delphi-ML:34075] <Win95> <コンポーネント >

0257  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/15 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/15 osamu 編集
TPageControl に OnDblClick を追加する

> PageControl や TabControl にクリックイベントやダブルクリックイベントを
> 付けたいのですがどのようにしたらよろしいのでしょうか?

以下の派生クラスでお望みのイベントが生成されます。
# ただ、PageControl の仕様をよく調査しないで作ったので、
# もしかしたら Click関係で弊害があるかもしれません。

uses
  Classes, Controls, ComCtrls;

type
  TxxPageControl = class(TPageControl)
  public
    constructor Create(AOwner: TComponent); override;
  published
    property OnDblClick;
  end;

implementation

constructor TxxPageControl.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csClickEvents];
end;
参照: [Delphi-ML:34074] <Win95> <コンポーネント >

0256  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/15 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/15 osamu 編集
TTreeView で5つ以上のオーバレイ・イメージを使う

>TreeView で同時に指定可能なオーバーレイ・イメージの最大数は
>使用する ImageList のメソッド Overlay で設定可能な最大数
>(4つ、TOverlay の範囲内で指定) になると解釈しています。
>現在、この制限を越えた数のオーバーレイ・イメージを使いたいの
>ですが、何か良い方法は無いでしょうか?

Overlay は ComCtl32.dll が 4.70 以前は4個まで、4.71 以降で 15個までに拡張されたようです。4.70 以前の場合は、同時に4つまでしか使用できませんが、4.71 以降では、

  ImageList_SetOverlayImage(ImageList1.Handle, 8, 5);

のように直接設定すれば OK です。(^^)/
参照: [Delphi-ML:32333] <Win95> <コンポーネント >

0255  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/15 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/15 osamu 編集
Install Shield でアンインストール時にレジストリが掃除されない

Install Shield で作ったアンインストーラは、元々有ったレジストリのキーは削除しないようにできています。

したがって、同じソフトをアンインストールしないで、2度続けてインストールすると、

 1 最初のインストールで、キーを作る。
 2 2回目のインストール時に、キーが既に有るので、
   「これは、元々有ったキーに値を設定するのだな」と認識される。
 3 Unistall Shield が起動したときに、1で作ったキーは
   2で「元々有ったキー」と認識されているので、削除されない。

という風になってレジストリの情報が残ってしまうみたいです。バージョンアップの配布などでは何か策を講じる必要がありそうですね。
[Delphi-ML:32250] の質問の原因がこれかどうかはちょっと疑問
参照: [Delphi-ML:32315] <配布>

0253  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/13 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/13 osamu 編集
TFontDialog で標準以外のサイズを選択肢に表示したい

> ルビをうつフォントを指定しようと思い、TFontDialogで
> 片付けようと思いましたが、TFontDialogで、MSゴシック
> など8Pt以下のポイントが出てきません。指定できるように
> する方法をどなたかご存知でしょうか。

思いっきり強引ですけど

unit FontDialogEx;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics,
  Controls, Forms, Dialogs;
type
  TFontDialogEx = class(TFontDialog)
  protected
    function TaskModalDialog(DialogFunc: Pointer;
                             var DialogData): Bool; override;
  end;

procedure Register;

implementation

uses Dlgs, CommDlg;

const
  WM_FONTDIALOGEX = WM_USER + 256;
  str1: string = '4';
  str2: string = '5';
  str3: string = '6';
  str4: string = '7';

var
  OldHook: function(Wnd: HWnd; Msg: UINT; WParam: WPARAM;
                    LParam: LPARAM): UINT; stdcall;

function FontDialogHookEx(Wnd: HWnd; Msg: UINT; WParam: WPARAM;
                          LParam: LPARAM): UINT; stdcall;
begin
  if (Msg = WM_COMMAND) and (LOWORD(WParam) = cmb1) then begin
    PostMessage(Wnd, WM_FONTDIALOGEX, 0, 0);
  end;

  if Msg = WM_FONTDIALOGEX then begin
    SendDlgItemMessage(Wnd, cmb3, CB_RESETCONTENT, 0, 0);
    SendDlgItemMessage(Wnd, cmb3, CB_ADDSTRING, 0, LongInt(PCHAR(str1)));
    SendDlgItemMessage(Wnd, cmb3, CB_ADDSTRING, 0, LongInt(PCHAR(str2)));
    SendDlgItemMessage(Wnd, cmb3, CB_ADDSTRING, 0, LongInt(PCHAR(str3)));
    SendDlgItemMessage(Wnd, cmb3, CB_ADDSTRING, 0, LongInt(PCHAR(str4)));
    Result := 1;
    exit;
  end;
  Result := OldHook(Wnd, Msg, WParam, LParam);
end;

function TFOntDialogEx.TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
begin
  OldHook := TChooseFont(DialogData).lpfnHook;
  TChooseFont(DialogData).lpfnHook := FontDialogHookEx;
  inherited TaskModalDialog(DialogFunc, DialogData);
end;

procedure Register;
begin
  RegisterComponents('NkCtrls', [TFontDialogEx]);
end;

end.

一応動いてます(^^ フォント名毎に表示するサイズリストを変えたい場合は、cmb1 に選択されているフォント名を確認するコードが必要になるでしょう。

一瞬元のポイントサイズがコンボボックスに表示されてしまいますが今のところ他に良い手を思いつきません(^^;
参照: [Delphi-ML:42562] <ダイアログ> <Dialogs> <描画> <コンポーネント >

0223  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/28 おばQ rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/11 K.Takaoka 編集
Editコントロールで入力を数値専用にする

入力を数値のみにする場合は、Handleの生成を確認した後
SetWindowLong(Edit1.Handle, GWL_STYLE,
    GetWindowLong(Edit1.Handle,GWL_STYLE) or ES_NUMBER);
でできます。

SetWindowLong による指定はウィンドウの再生成が行われた時に無効になりますので、Delphi4 のドッキングウィンドウや、Toolbar97 などのコンポーネントを同時に利用される場合には CreateParams をオーバーライドしたコンポーネントを作成するかフローティング状態の変更通知を受け取るたびに SetWindowLong を行う必要があります。
参照: [Delphi-ML:9195] [Delphi-ML:41622] <コンポーネント > <Standard>

0243  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/11 K.Takaoka 編集
TMemo のキャレットを非表示にする

> メモコンポーネントでキャレットを消したいのです。

以下のコードでうまくいっています

// TExMemo=class(TMemo)
// TExMemo.WMSetFocusはWM_SETFOCUSのメッセージハンドラ
Procedure TExMemo.WMSetFocus(var Msg:TWMKeyDown);
Begin
 Inherited;
 HideCaret(Handle);
End;


参照: [Delphi-ML:33802] <Standard> <コンポーネント >

0235  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/06 西坂良幸 rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/11 K.Takaoka 編集
エディットコントロールにポップアップウィンドウをつけたい

エディットコントロールにボタンをつけた、コンボボックスもどきは、カスタムコントロールでよく見かけます。ボタンを押すと小ウィンドウが開くヤツです。これはどのように作るのでしょうか。

このような小ウィンドウをインプレースコントロールと呼びます。
ポイントは、小ウィンドウの親をコントロールにすることと、独自のフォーカスを与えないことです。これさえ理解できれば後は、小ウィンドウのVisbleの切り替えで開いたり閉じたりします。

ここでは、プロパティを受け渡すことを無視し、ただ開閉だけをやってみます。(マウス右ボタンで開く)

//  定義部
  TxEdit = class;

  // インプレースコントロール ここではリストボックス
  TinPlaceList = class(TListbox)
  private
    FEdit: TxEdit;
  protected
    procedure CreateWnd; override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  public
    constructor CreateList(AOwner: TComponent; Edit: TxEdit);
  end;

  // ここでは、TEditから継承する
  TxEdit = class(TEdit)
  private
    FInplaceList:TListbox;
  protected
    procedure Mousedown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
  public
    constructor Create(AOwner: TComponent);override;
    destructor Destroy;override;
    procedure DropDown;
  end;

// 実装部

//コンストラクタでコントロールに接続させる
constructor TInplaceList.CreateList(AOwner: TComponent; Edit: TxEdit);
begin
  inherited Create(AOwner);
  // 小ウィンドウに親のポインタを持たせて接続する
  FEdit := TxEdit(Edit);
  Visible := false;
end;

// インプレースコントロールの生成とフォーカス制御
procedure TInplaceList.CreateWnd;
begin
  inherited CreateWnd;
   //親の変更を行う
  if not (csDesigning in ComponentState) then
    Windows.SetParent(Handle, 0);
  //独自のフォカスメッセージを避ける
  CallWindowProc(DefWndProc, Handle, WM_SETFOCUS, 0, 0);
end;

//とりあえずマウス(左右)で閉じることにする
procedure TInplaceList.MouseUp(Button: TMouseButton; Shift: TShiftState;
    X, Y: Integer);
begin
  inherited MouseUp(Button, Shift, X, Y);
  if Button = mbLeft then
  begin
    // プロパティの受け渡しをここらで行う
    Hide;
  end;
  if Button = mbRight then
    Hide;
end;

// コンストラクタで、インプレースコントロールを生成
constructor TxEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FInplaceList := TInplaceList.CreateList(Self, Self);
  with FInplaceList do
  begin
    Parent := Self;
    TabStop := false;
    Visible := false;
    Top := FInplaceList.Top + Self.Height;
  end;
end;

// デストラクタで念のため明示的に解放する
destructor TxEdit.Destroy;
begin
  FInplaceList.free;
  inherited Destroy;
end;

// ドロップダウンリストの開閉のメソッドを作成する
procedure TxEdit.DropDown;
var
  xyPos: TPoint;
begin
  if (FInplaceList <> nil) and not FInplaceList.Visible then
  with FInplaceList do
  begin
    xyPos := Self.ClientToScreen(Point(0 + Self.Width - Width,  Self.Height));
    SetWindowPos(Handle, 0, xyPos.X, xyPos.Y, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE);
    Windows.SetFocus(Handle);
    Visible := not Visible;
    // プロパティの受け渡しをここらで行う
  end;
  Invalidate;
end;

// マウス右ボタンで開く
procedure TxEdit.Mousedown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  if Button = mbRight then
    DropDown;
  inherited Mousedown(Button, Shift, X, Y);
end;

TListBoxのかわりに、何でも使えます。TPanelなら、電卓、カレンダなどになりますね。TGridでもいいですね。
実際にカスタムコントロールを作るときは
・やはりボタンをつける
・キーボード入力にも対応させる
・必要なプロパティの受け渡しを行う
・ドロップダウンなどイベントを記述する
・ロストフォーカスで開きっぱなしにしない
などが必要でしょうか。

参照: [Delphi-ML:40241] <コンポーネント開発> <コンポーネント > <Standard>

0250  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/09 osamu 編集
文字列を TDateTime に変換する

文字通り StrToDateTime という関数もあるんですが、これは yyyy/mm/dd などの形式にしか対応していません。ちょっとひねって VarToDateTime を使えば、ほぼどんな形式でもうまく変換できます。string -> Variant は自動で変換されるので、そのまま文字列を渡すだけで使えます。

MyDateTime := VarToDateTime('平成1年1月1日午後1時1分1秒');

全角数字もOKですが、さすがに '平成九年九月九日' は無理でした。

VarToDateTime('1999/1/2') = VarToDateTime('1/2/1999');

の結果は、True になりました。

注意点として、VerToDateTime は StrToDateTime と違い、ShortDateFormat グローバル変数を見ていないようです。

    ShortDateFormat:='DD/MM/YY';
    ShowMessage(FloatToStr(VarToDateTime('2/1/1999')-VarToDateTime('平成11年2月1日')));

の結果は 0 になります。
参照: <文字列> <日時> <PASCAL>

0251  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/09 osamu 編集
経過日数を取得する

> 1998年12月3日 − 1998年11月29日 = 4日
> という答えが欲しいのですが、年・月をまたがっても、
> 日数が帰って来るようにするにはどうしたらよいでしょう?

TDateTime 型は日数を単位とする double 値 (1899/12/30 0:0:0 からの経過日数) なので、Trunc して引き算すれば望みの結果が得られます。

Days := Trunc(Now) - VarToDateTime('昭和20年8月15日');

あるいは、D3 以前ならば、

Days := Trunc(Now) - EncodeDate(1945,8,15);
参照: [Delphi-ML:33577] <日時> <PASCAL>

0249  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/09 osamu 編集
1時間後を取得する

TDateTime 型は日数を単位とする double 値 (1899/12/30 0:0:0 からの経過日数) なので、一時間後の時刻を得るには 1/24 を足してやれば良いです。1時間20分後などを得るには

a := Now + StrToTime('1:20:00');    // 現時刻の1時間20分後
b := Now + EncodeTime(1, 20, 0, 0); // これも1時間20分後

EncodeDate、DecodeDate、EncodeTime、DecodeTimeを使うと環境に依存しないので、a より b がおすすめです。
参照: [Delphi-ML:33577] <日時> <PASCAL>

0248  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/09 osamu 編集
Metafile が Draw で1ピクセル小さく描画される

>拡張メタファイルを作成するツールを作ろうとしています。
>そこで、メタファイルに編集を加えるたびに以前編集した像が
>1ドット(?)ずつ縮小してしまう問題があるのです。

TMetafile.Draw を見ると

  R := Rect;
  Dec(R.Right);  // Metafile rect includes right and bottom coords
  Dec(R.Bottom);
  PlayEnhMetaFile(ACanvas.Handle, FImage.FHandle, R);

となっていて、描画先矩形を 1ドット分縮小しているのが原因のようです。
Win32 Programmer's Ref. で PlayEnhMetafile を見ると、

Points along the edges of the rectangle are included in the picture.

なんて微妙なことが書いてあるのですが、実際には Win98 で試してみた限り矩形領域を小さくするのは正しくないようです。Dec をコメントにすると完全に同じ大きさの図形が得られます。

対処としては graphics.pas を修正するか、Right, Bottom を一つ大きめに指定して StretchDraw するしかないようです。

ただ、ディスプレイデバイスとメタファイルの参照デバイスが異なると多少の誤差は避けられないようです。この辺を考慮して高精度のメタファイルを作るにはメタファイルを直接編集するしかないと思います。
参照: [Delphi-ML:33593] <画像> <バグ> <描画>

0247  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/09 osamu 編集
TWebBrowser を使って HTML の描画イメージを取得する

WebBrowser1.ControlInterface.Width と 同.Height を保存し、ページのサイズにして OleDraw の後で復元したところ、イメージが取得できました。

IWebBrowser の Width, Height は表示しているコントロールの Width/Height にイコールであるため、TWebBrowser(TOleContainer)の大きさが可変であることが必要なのがちょっと困者ですが、なんとかなった、、、ことにします。

  web: TWebBrowser;

var
  bmp: TBitmap;
  body: OleVariant;
  w, h: Integer;
begin
  body := (Web.Document as IHTMLDocument2).Body;

  bmp := TBitmap.Create;
  try
    // 軽くマージンをつけておかないとスクロールバーがついちゃいます。
    bmp.Width  := body.scrollWidth  + 16;
    bmp.Height := body.scrollHeight + 16;

    (* ここで WindowLock(Web.Handle) すべきでしょうか?
       CPU などの性能によってはチラつきそうです。       *)

    // 現在値を保存してリサイズします。
    w := Web.ControllInterface.Width;
    h := Web.ControllInterface.Height;
    Web.ControllInterface.Width  := bmp.Width;
    Web.ControllInterface.Height := bmp.Height;

    // 描画します。
    OleDraw(Web.ControllInterface, DVASPECT_DOCPRINT, bmp.Canvas.Handle,
            Rect(0, 0, bmp.Width, bmp.Height));

    // 元の大きさに戻します。
    Web.ControllInterface.Width  := w;
    Web.ControllInterface.Height := h;

    (* ここで WindowLock() してるなら戻す *)
    (* ここでいろいろ bmp を使って遊べます *)

  finally
    bmp.Free;
  end;
end;

一応、上記のようなかんじなのですが、dislable なスクロールバーがつくものの、全体をイメージにできました。scrollbar の幅と高さを GetSystemMetrics などで手にいれてカットすれば okay っぽいのですが、常に scrollbar がついているか…など検証が必要そうです。

# IWebBrowser 関連を操作して、強制的に消せましたっけ?
参照: [Delphi-ML:33701] <WWW> <通信>

0246  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/09 osamu 編集
DLL 内で TDBCtrlGrid を使うときの注意事項

>DLL化したアプリのフォームにDBCtrlGrid,DBCheckBoxを置いてローカルDB
>の内容を表示させているのですが、DLL化した途端にカレントレコードしか
>表示されなくなってしまいました。

この現象は以下の理由で発生します。

1.DLLの中では、何もしなければApplication.Handle=0です。
2.DBCtrlGridに配置されるコンポーネントの一部(DBCheckBoxを含む)はカレントレコード以外へ複製表示を行うために、Application.Handleを利用しています。

具体的にはDBCtrls.pasのTPaintControl.GetHandleで、次のようなコードで表示用の別ウインドウを生成しています。
  with Params do
    FHandle := CreateWindowEx(ExStyle, PChar(FClassName),
      PChar(TWinControlAccess(FOwner).Text), Style or WS_VISIBLE,
      X, Y, Width, Height, Application.Handle, 0, HInstance, nil);

Application.Handle=0 だと CreateWindowEXは失敗し、FHandle=0となるので複製表示が正常に行われないのです。

対処方法としては、Delphiヘルプの TApplication.Handle に書いてありますが、EXE ホストのメインウィンドウのウィンドウハンドルを DLL の Application.Handleに割り当てます。

別の方法としては、上記の TPaintControl.GetHandle の Application.Handle を FOwner.Handle に書き換えてもいいでしょう。

このスレッドではさらに、TApplication.MainForm.Handle を渡すべきか、TApplication.Handle を渡すべきか。また、TApplication.Handle を渡す際には、DLL 側の uses から Forms を削除しなければ、など、使い方に関する細かい注意点が議論されています。
参照: [Delphi-ML:33636] [Delphi-ML:33791] <データベース> <コンポーネント > <DataControls>

0245  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/09 osamu 編集
サブネットマスク値など TCP/IP 関連パラメータを取得する

>ネットワークコンピュータに設定されているTCP/IPのアドレスは
>gethostbynameで取得できると思いますが、サブネットマスクの
>アドレスはどうやって取得すればよいのでしょうか。

こういうことは MS で検索しましょう。

http://support.microsoft.com/support/

で WindowsNT workStation を SUBNETMASK で検索すると

http://support.microsoft.com/support/kb/articles/q120/6/42.asp?FR=0

が見つかります。
TCP/IP 関連パラメータの格納場所が公開されています。
参照: [Delphi-ML:33813] <通信>

0244  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/09 osamu 編集
UDP 通信で NoParam ???

Q:
UDPで受信するコードを書こうとしています。
ヘルプで調べてみたのですが、以下のNoParamの部分が分かりません。

procedure TForm1.UDP1DataArrival(Sender: TObject; bytesTotal: Integer);
begin
  UDP1.GetData(data, NoParam); //データを取得する
  Memo1.Lines.Append(data); //表示を追加する
end;

A:
function NoParam: Variant;
begin
  TVarData(Result).VType := varError;
  TVarData(Result).VError:= DISP_E_PARAMNOTFOUND;
end;

わかりにくいのですが、一応載っています。「パラメータの省略」というページです。
参照: [Delphi-ML:33778] <通信>

0242  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/09 osamu 編集
デフォルトプリンタの設定

>「通常使うプリンタ」を変更したいのですが、よい方法が見つかりません。

最近 SetPrinter API の使い方を覚えました。これで出来ます(^^

procedure SetDefaultPrinter(Index: Integer);
begin
var Device, Driver, Port: array[0..511] of Char;
    hDevMode: THandle;
    hPrinter: THandle;
    pInfo2: ^TPrinterInfo2;
    Size: DWORD;
begin
  Printer.PrinterIndex := Index;
  // デバイス名を得る
  Printer.GetPrinter(Device, Driver, Port, hDevMode);

  // プリンタハンドルを作る。
  Win32Check(OpenPrinter(Device, hPrinter, Nil));
  try
    // Printer_Info_2 に必要なバッファサイズを取得
    WinSpool.GetPrinter(hPrinter, 2, pInfo2, 0, @size);

    // バッファ確保
    GetMem(pInfo2, size);
    try
      // プリンタ情報を取得
      Win32Check(WinSpool.GetPrinter(hPrinter, 2, pInfo2, Size, @size));

      // デフォルトプリンタにする
      pInfo2.Attributes := pInfo2.Attributes or
                           PRINTER_ATTRIBUTE_DEFAULT;

      // プリンタ情報をプリンタへセットする
      Win32Check(WinSpool.SetPrinter(hPrinter, 2, pInfo2,
                          PRINTER_CONTROL_SET_STATUS));
    finally
      FreeMem(pInfo2);
    end;
  finally
    ClosePrinter(hPrinter);
  end;
end;

Win98 でしか確認していません。あしからず。
参照: [Delphi-ML:33386] <印刷>

0241  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/09 osamu 編集
TPageControl でタブをドラッグして順序入れ替え

>マウスでTabSheet上のTabをドラッグして
>Tabの順序を交換するにはどうしたらよいのでしょうか?

面白そうなので、D3 でやってみました。

--- 以下 例文 ---
procedure TForm1.PageControl1MouseDown(Sender: TObject;...);
begin
  PageControl1.BeginDrag(false);
end;

procedure TForm1.PageControl1DragOver(Sender, ...);
begin
  if Sender is TPageControl then
    Accept := true;
end;

procedure TForm1.PageControl1DragDrop(Sender, ...);
var
  i: Integer;
  r: TRect;
begin
  if not (Sender is TPageControl) then
    Exit;

  with PageControl1 do
  begin
    for i := 0 to PageCount - 1 do
    begin
      Perform(TCM_GETITEMRECT, i, LPARAM(@r));

      if PtInRect(r, Point(X, Y)) then
      begin
        if i <> ActivePage.PageIndex then
          ActivePage.PageIndex := i;

        Exit;
      end;
    end;
  end;
end;
参照: [Delphi-ML:33411] <Win95> <コンポーネント >

0240  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/08 osamu 編集
任意のドライブをセクタ単位で読み書きする

Q:
MS-DOS Ver.2.1でフォーマットされたFDをWin95で読込みたいのですが、どのようにすればよいのでしょうか?
セクタ単位で読込む方法が解りません。

A:
'\\.\A:' で該当のドライブ( A: の部分を適宜変更)に対して CreateFile() すればアクセスできます。

# You can use the CreateFile function to open a disk drive
# or a partition on a disk drive. The function returns a
# handle to the disk device; that handle can be used with
# the DeviceIOControl function. The following requirements
# must be met in order for such a call to succeed:
#
# The caller must have administrative privileges for the
# operation to succeed on a hard disk drive.
# The lpFileName string should be of the form \\.\PHYSICALDRIVEx
# to open the hard disk x. Hard disk numbers start

注意として GetDiskFreeSpace() でセクタサイズを調べて FILE_FLAG_NO_BUFFERING でアクセスしてください。
参照: [Delphi-ML:32482] <ファイル>

0239  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/08 osamu 編集
IME に未確定文字列を入力

> プログラム中からIMEに未変換・未確定文字列として送りたいのですが。。。
>
> 例
> プログラムで渡す文字列    へいせい10ねん
>           ↓
>          IME              「へいせい10ねん」(未変換・未確定)

方法1
  「へいせい10ねん」を「heisei10nenn」もしくは、
  「ヘイセイ10ネン」(ほんとは半角)に変換し、キーボードイベントとして
  sendkeysや、keybd_event APIでIMEに送る。
  ローマ字変換か、カナ変換かは、ImmGetConversionStatus APIで
  判断出来ます。

  Edit1.SetFocus;
  SendKeys('heisei10nenn',true);

方法2
  ImmSetCompositionString APIでIMEに直接セットする。

  var
    IMC:HIMC;
    BufLen:longint;
    Buf:string;
  begin
    Edit1.SetFocus;
    IMC:=ImmGetContext(Edit1.Handle);
    Buf:='へいせい10ねん';
    BufLen:=length(Buf);
//MS-IME98
    ImmSetCompositionStringA(IMC,SCS_SETSTR,PChar(Buf),BufLen,nil,0);

//ATOK12
    ImmSetCompositionStringW(IMC,SCS_SETSTR,PChar(Buf),BufLen,nil,0);

    ImmReleaseContext(Edit1.Handle,IMC);
  end;

MS-IME98とATOK12でテストしましたが、ATOK12の場合、UniCodeの方のAPIで実行しないとちゃんと動作しませんでした。
なぜなのかは、よくわかりません(^^;

#詳しくは、英語のヘルプやAPIの解説書等で調べてください。
参照: [Delphi-ML:32185] <その他Windows関連> <Windows> <コンポーネント > <Standard>

0143  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/08 osamu 編集
フォルダのタイムスタンプを変更する

ファイルのタイムスタンプを変更するのはできるのですがフォルダのタイムスタンプはどのようにして変更したらよいのでしょうか?

procedure ChangeDirTime(DirName : String;Date : TDateTime);
var
  FHandle   : integer;

Begin
 FHandle := CreateFile(Pchar(DirName),  { ディレクトリ名最後に\はいらない }
   GENERIC_WRITE,    { 書きこみ許可しないと変えられない }
   FILE_SHARE_Read,   { 最低他からアクセスできないとハンドルがもらえない }
   nil,     { セキュリティは無視(いいのかな?) }
   OPEN_EXISTING,    { ディレクトリは存在していることを前提 }
   FILE_FLAG_BACKUP_SEMANTICS,   { APIのヘルプをみてね }
   0);
 FileSetDate(FHandle,DateTimeToFileDate(Date));
 CloseHandle(FHandle);
End;

タイムスタンプの設定にAPIのSetFileTimeを使う手もありますがフォルダならこれで十分です。

D3+Win98 では動きませんでした。NT では動くのかな???
参照: [Delphi-ML:24889] <Windows> <ファイル>

0013  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.9
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/08 osamu 編集
Delphi3 でコンポーネントパレットを複数行にする

RegEdit.exeで

キー  :"HKEY_CURRENT_USERS\Software\Borland\Delphi\?.0\Desktop"
名前  :"TabMultiLine"
文字列:"1"

を追加する。
参照: <開発環境>

0003  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/08 osamu 編集
ショートカットキーに'+'を使う。

Delphi2.0 以上では、『!"#$%&'()=~|^{}`*+_?><』など、101のフルキー側(テンキーを除いた部分)で、Shiftと同時にキーを押さなければ入力できない文字はショートカットに使えない。
テンキーがついてたり、JISキーボードならばワンキーで押せるものもあるのに。

こういったキーを使うには、ShortCut プロパティにキーコードを直接セットすればいい。

たとえば、

    Test2.ShortCut:=$6B;  // <- + キーのキーコード

でも、これだとメニューの右端にキー名が表示されない。 (;_;)
対処方法は [Tips:4]
参照: [Delphi-ML:17954] [Tips:4] <コンポーネント > <Standard> <メニュー>

0224  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/28 おばQ rev 1.1.1.5
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/07 西坂良幸 編集
右寄せ・数値入力可能なEditコンポーネントを作りたい。

Win98 以降では、次のようにすれば完璧な右寄せエディタが作成できます。
 WindowsNT4 では SP3 (User32.Dll が 03/11/97 07:04p Intel, 03/11/97 06:14p Alpha) から利用できます。


type
 TRgEdit = class(TEdit)
 protected
   procedure CreateParams(var params: TCreateParams); override;
 end;

procedure TRgEdit.CreateParams(var params: TCreateParams);
begin
 inherited CreateParams(params);
 with Params do
   Style := Style or ES_RIGHT;
end;

 追記のバージョン以前、またDelhi3以前は、
   Style := Style or WS_MULTILINE or ES_RIGHT and not WS_VSCROLL and not WS_AUTOVSCROLL ;

とします。
また、入力を数字専用される場合は、上記にES_NUMBERを論理和
させます。

以下は、Alignment、NumOnly の各プロパティを作成する例です
(FAlignment、FNumOnlyやプロパティ定義部分は省略しています)

procedure TRgEdit.CreateParams(var params: TCreateParams);
const
 Alignments: array[TAlignment]of Word = (ES_LEFT, ES_RIGHT, ES_CENTER);
 NumlOnlies: array[Boolean]of Word = (0, ES_NUMBER);
begin
 inherited CreateParams(Params);
 Params.Style := Params.Style  
         or Alignments[FAlignment]
         or NumlOnlies[FNumlonly];
end;

procedure TRgEdit.SetAlignment(NewValue: TAlignment);
begin
  if FAlignment <> NewValue then
  begin
    FAlignment := NewValue;
    RecreateWnd;// CreateParamsを呼び出すのではないことに注意
  end;
end;

procedure TRgEdit.SetNumlOnly(NewValue: Boolean);
begin
  if FNumlOnly <> NewValue then
  begin
    FNumlOnly := NewValue;
    RecreateWnd;
  end;
end;
参照: [Delphi-ML:9195] [Delphi-ML:41622] <コンポーネント > <Standard>

0011  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 西坂良幸 編集
メッセージボックスを独自にカスタマイズしたものを使いたい。

メッセージボックスを使ってたのですが、動きはほとんど同じで表示のアイコンやボタンをカスタマイズする方法って言うのはないものでしょうか? 決まりきった疑問符や感嘆符などではなく、ユーザが自由にビットマップを貼り付けられるようにしたいのですが。

CreateMessageDialog関数を使えば簡単にできます。
以下の例を試して見て下さい。あなた好みのメッセージボックスのイメージが沸いてきますよ。

CreateMessageDialogは、メッセージダイアログのインスタンスを返します。
このダイアログ(TForm)の上のコンポーネントは
                         クラス       名前
Components[0]が、TImage      'Image'
Components[1]が、TLabel      'Message'
Components[2]が、TButton     たとえば 'Yes','No' など
Components[3] ・・・ボタンがつづく
となっています。

function MyMessageBox(Const Msg: String): integer;
var
  Dlg:TForm;
begin
   Dlg:=CreateMessageDialog(Msg, mtError, [mbYes,mbNo]);
   with Dlg do
   try
     Dlg.Caption := '登録確認';
     TImage(Components[0]).Picture.Icon.LoadFromFile('C:\Program Files\Borland\Delphi 4\IMAGES\ICONS\Technlgy.ico');
     TButton(Components[2]).Caption := '登録';
     TButton(Components[3]).Caption := '中止';
     ret := ShowModal;
   finally
     Free;
   end;
end;

// テスト
procedure TForm1.Button1Click(Sender: TObject);
begin
  if MyMessageBox('データを登録しますか?') = mrYes then
    // 登録処理
  else
    ; // 無視
end;

てな具合で絵(BitmapやIcon)を変える事ができます。
LeftやTopを使って配置を換えることも可能です。
HelpContextなども設定できます。

絵は32x32サイズに作っておいた方がいいです。
大きさが違う場合には位置の調整をしなければならなくなりますが、ダイアログ上のコントロールに名前がついていないので苦労します。(D4以降は上記のように名前も付いています)
ボタンについても同様です。
参照: [Delphi-ML:5100] <ダイアログ>

0001  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 osamu 編集
Delphi 2.0/3.0でCPUウィンドウを出す

RegEdit.exeで

キー  :"HKEY_USERS\.Default\Software\Borland\Delphi\?.0\Debugging"
名前  :"EnableCPU"
文字列:"1"

を追加する。
参照: [Delphi-ML:6088] <開発環境>

0005  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 西坂良幸 編集
メインフォーム以外のフォームをタスクバーに入れたい。

フォームのウィンドウスタイルにWS_EX_APPWINDOWを加えます。

  TForm2 = class(TForm)
    :
    procedure FormClose(Sender: TObject; var Action: TCloseAction);  
  protected
    procedure CreateParams(var Params: TCreateParams);
  override;
    :
  end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Action := caFree; // これを忘れないこと
 Form2 := nil;
end;

procedure TForm2.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
end;

とします。[Delphi-ML:7921]

また、タスクバーにも入れたくないときは、
 Application.OnMinimize := AppMinimize;
を設定し、

procedure TForm2.AppMinimize(Sender: TObject);
begin
   ShowWindow(Form1.Handle, SW_HIDE);
end;

ですね。
参照: [Delphi-ML:3429] [Delphi-ML:6234] [Delphi-ML:17682] <タスクバー> <Windows> <フォーム>

0232  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/01 西坂良幸 rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 西坂良幸 編集
APPのフォームを最小化して起動したい

メインフォームのWindowStyleをwsMinimizedに設定しておくと自分で起動するときは、最小化されタスクバーに入ります。
しかし、他のAPPから起動する時やAPIのShowWindowやショートカットやタスクトレイなどで起動する時はちょっとやっかいです。
これは、Application(変数)のフォームとメインフォームの同期がとれないからです。これはメインフォームに送られてくるスタイルフラッグに合わせて、Applicationのスタイルを合わせてやる必要があります。
この方法は、MLではいくつも紹介されています。[Delphi-ML:13173] [Delphi-ML:13185]
(混乱ということでは、古いバージョンでは、GetStartupInfoで取得できるwShowWindow値が、CmdShowと必ずしも一致しないという問題や、D2→D3で仕様が変わっているということもあります。)

以下のコードはどうでしょうか。

procedure TForm1.FormCreate(Sender: TObject);
var
  SI : TStartupInfo ;
begin
  // D4では、常にCmdShow = SI.wShowWindowですが念のため
  GetStartupInfo( SI ) ;
  CmdShow := SI.wShowWindow ;

  // 最小化に関係するスタイルフラッグにすべて対応
  case cmdShow of
    SW_SHOWMINIMIZED,
    SW_MINIMIZE,
    SW_SHOWMINNOACTIVE :
      Application.Minimize ;// 同期させる
  end ;
end;


なお、子フォームの場合をDeskTopでなく、タスクバーに入れるには、0005番「メインフォーム以外のフォームをタスクバーに入れたい。」を参照して下さい。
参照: [Delphi-ML:13173] [Delphi-ML:3426] [Delphi-ML:23218] [Delphi-ML:25557] <タスクバー> <Windows> <フォーム>

0238  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/06 西坂良幸 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 西坂良幸 編集
メッセージボックスのデフォルトボタンを変えたい

ボタンが、[はい、いいえ]ならNoの方に、デフォルトが、[はい、いいえ、キャンセル]ならキャンセルにデフォルトを置きたい場合があります。
APIのMessageBoxのヘルプから、スタイルフラッグを調べて下さい。ApplicationのMessageBox メソッドを使えば簡単です。

  Application.MessageBox('デフォルトボタンを変えています', PChar(Application.Title), MB_ICONQUESTION + MB_YESNO + MB_DEFBUTTON2);

   Application.MessageBox('デフォルトボタンを変えています', PChar(Application.Title), MB_ICONQUESTION + MB_YESNOCancel + MB_DEFBUTTON3);


がわかりやすいでしょう。

CreateMessageDialog関数を使われるなら、次のような自作関数はどうでしょうか。
Defaultパラメータを、2とか3にすれば、デフォルトボタンを変えることができます。

function MessageDlgEx(const Msg: string; AType: TMsgDlgType; AButtons: TMsgDlgButtons; HelpCtx: Longint = 0; default: Word = 1): Word;
var
  Dlg: TForm;
begin
  Dlg := CreateMessageDialog(Msg, AType, AButtons);
  try
    // 最初のボタンが Components[2]である
    if (Default <1) or (Default >= Dlg.ComponentCount - 1) then Default := 1;
    Dlg.HelpContext := HelpCtx;
    Dlg.ActiveControl := TWinControl(Dlg.Components[default + 1]);
    result := Dlg.ShowModal;
  finally
    Dlg.Free;
  end;
end;

参照: [Delphi-ML:5944] [Delphi-ML:32505] <ダイアログ>

0123  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 西坂良幸 編集
ButtonのCaptionで改行を使って文字を複数段で表示したい

Windows95では #13#10 挿入することにより思った通り表示できるのですが
WindowsNTの場合は改行されません。

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetWindowLong(Button1.Handle, GWL_STYLE, GetWindowLong(Button1.Handle, GWL_STYLE) or BS_MULTILINE);
  Button1.Caption := 'ABC' + #13#10 + 'DEF';
end;


なお、コンポ−ネント化する場合はCreateParamsをオーバーライドして下さい。
この方法は、TButtonControl系(TRadioButton,TCheckBox)でほとんど使えますが、オーナードロー系(TBitBtn,TSpeedButtonなど)のボタンではできません。

また、以下のプロパティエディッタをインストールすれば、オブジェクトインスペクタで,改行コードを入力を'\n'ですることが出来るようになります。

// 定義部
type
  // 複数行の入力を\nで受け入れるプロパティエディッタ
  TMultCapProperty = Class(TCaptionProperty)
  Public
    Function GetValue: string; Override;
    Procedure SetValue(const Value: string); Override;
  End;

procedure Register;


// 実装部
// 置き換える関数
procedure ReplaceStr(var Source : string; Search, Replace : string);
  function XPos(Source, Search : string):integer;
  begin
    if StrPos(PChar(Source), PCHar(Search)) = nil then
      result := 0
    else
      result := StrPos(PChar(Source), PCHar(Search)) - PChar(Source) + 1;
  end;
var
  p, L1, L2 : Integer;
begin
  L2 := Length(Search);
  p := XPos(Source, Search);
  while p <> 0 do
  begin
    L1 := Length(Source);
    if p = 1 then
      Source := Replace + Copy(Source, L2 + 1, L1)
    else
      Source := Copy(Source, 1, p - 1) + Replace +
              Copy(Source, p + L2, L1);
    p := XPos(Source, Search);
  end;
end;

function TMultCapProperty.GetValue: string;
begin
  Result := GetStrValue;
  // 以下3つのパターンがある
  ReplaceStr(Result, #13 + #10, '\n');
  ReplaceStr(Result, #10, '\n');
  ReplaceStr(Result, #13, '\n');
end;

procedure TMultCapProperty.SetValue(const Value: string);
var
  Caption : string;
begin
  Caption := Value;
  ReplaceStr(Caption, '\n', #13);
  SetStrValue(Caption);
end;

// プロパティエディタとして登録する
procedure Register;
begin
  // TLabelのCaptionプロパティエディタの登録--'\n'で改行入力
  RegisterPropertyEditor(TypeInfo(TCaption), TLabel; , 'Caption', TMultCapProperty);
  // TButtonのCaptionプロパティエディタの登録--'\n'で改行入力
  // ただし上記BS_MULTILINEが設定されていないとダメ
  RegisterPropertyEditor(TypeInfo(TCaption), TButton; , 'Caption', TMultCapProperty);
end;

参照: [Delphi-ML:17735] [Delphi-ML:39679] [builder:6270] <コンポーネント開発> <コンポーネント > <Standard>

0063  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 西坂良幸 編集
キーボードでボタンを押したとき、ボタンをちゃんと沈ませたい

BM_SETSTATE メッセージを使うとできます。
コンポーネント化は、ちょっと長くなるので、詳細は [Delphi-ML:19607] を見てください。

以下、スペースキーでの例です。
procedure TForm1.Button1KeyPress(Sender: TObject; var Key: Char);
begin
  if Key = #32 then
    SendMessage(Button1.Handle,BM_SETSTATE,1,0);
end;

procedure TForm1.Button1KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = 32 then
    SendMessage(Button1.Handle,BM_SETSTATE,0,0);
end;


コーディングだけで呼ぶ場合は

  SendMessage(Button1.Handle,BM_SETSTATE,1,0);
  Button1.Click;
  Sleep(100);   // 適当に好みで決める
  PostMessage(Button1.Handle,BM_SETSTATE,0,0);

参照: [Delphi-ML:19607] <コンポーネント > <Standard>

0237  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/06 西坂良幸 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 西坂良幸 編集
カーソルキーでボタン(TButton)のフォーカス移動をやめさせたい


TButtonのOnKeyPress、OnKeyDownなどでやってみてもダメですね。これは、Windowsのボタンの仕様です。
フォームへのCM_DialogKeyメッセージをとらえて処理すると可能です。

procedure TForm1.CMDialogKey(var Msg:TCMDialogKey);
begin
    case Msg.CharCode of
    VK_UP,VK_DOWN,VK_LEFT,VK_RIGHT :  Msg.CharCode:=0;
    end;
    inherited;
end;


このメッセ−ジはタブキー(VK_TAB)もとらえることが出来ます。
参照: [Delphi-ML:3691] [Delphi-ML:33541] <フォーム> <コンポーネント > <Standard>

0236  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/06 西坂良幸 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 西坂良幸 編集
エディットコントロールにコンボボックスのようなボタンをつけたい


エディットをParentとするフォーカスを持たないTSpeedButtonを、貼り付けてやれば簡単です。
注意するのは、編集領域がボタンに重ならないようにEM_SETRECTNPを送ることですが、このメッセージが有効になるには、TEditのスタイルフラッグにES_MULTILINEを加えなければなりません。

以下の例は、ボタンを押せば単にメッセージボックスがでるだけのものです。

// 定義部
  TxEdit = class(TEdit)
  private
    FButton: TSpeedButton;
    FOnButtonClick: TNotifyEvent;
    procedure SetEditRect;
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
  protected
    procedure ButtonClick (Sender: TObject);
    procedure CreateParams(var Params: TCreateParams); override;
    procedure CreateWnd; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property OnButtonClick: TNotifyEvent read FOnButtonClick write FOnButtonClick;
  end;

// 実装部
constructor TxEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  // ボタンを作成する
  FButton := TSpeedButton.Create (Self);
  with FButton do
  begin
    Parent := Self;
    Width := 18;
    Height := Height - 4;
    // リソースから ▼ のビットマップ(10×8程度×2)を読むのは省略
    // NumGlyphs := 2;
    // result.Glyph.LoadFromResourceName(HInstance,'????');
    CurSor := crArrow;
    OnClick := ButtonClick;
  end;
end;

// スタイルフラッグにES_MULTILINEが必要です。
procedure TxEdit.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.Style := Params.Style or ES_MULTILINE;
end;

// ハンドルが生成されてからSetEditRectを呼ぶ
procedure TxEdit.CreateWnd;
begin
  inherited CreateWnd;
  SetEditRect;
end;

// エディット(編集)領域を再設定する(ボタンの部分を排除)
procedure TxEdit.SetEditRect;
var
  Loc: TRect;
begin
  SendMessage(Handle, EM_GETRECT, 0, LongInt(@Loc));
  Loc.Right := ClientWidth - FButton.Width - 2;
  SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@Loc));
end;

// 常に左端にアジャストさせる
procedure TxEdit.WMSize(var Message: TWMSize);
begin
  inherited;
  if FButton <> nil then
  begin
    if NewStyleControls and Ctl3D then
      FButton.SetBounds(Width - FButton.Width - 4, 0, FButton.Width, Height - 4)
    else FButton.SetBounds (Width - FButton.Width, 1, FButton.Width, Height - 2);
    SetEditRect;
  end;
end;

// ボタンのクリックに対応するイベントを設定する
procedure TxEdit.ButtonClick (Sender: TObject);
begin
  if Assigned(FOnButtonClick) then FOnButtonClick(self);
  ShowMessage('ボタンが押されました')
  // ここに必要な処理を書く
end;

この他、CM_EnabledChangeを捕まえて、EditとボタンのEnabledを同期させることが必要でしょうか。
参照: <コンポーネント開発> <コンポーネント > <Standard>

0225  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/28 西坂良幸 rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/05 藤中理香 編集
数値の2進数への変換で効率的な方法


ML[Delphi-ML:32617][Delphi-ML:32720]のスレッドにいろいろな変換関数例が示されています。

ベンチワークしたわけではありませんが、効率ということでは、中川さんのコードがお勧めでは?
「10進から2進数への変換に標準関数はありませんが、デルファイではTBitsという
似て非なるクラスがあります。(定義はclassesの中)
そこを見てみますと、インラインアセンブラが使われています。ということで、題材的に
インラインアセンブラが向いているのではないかと思い作ってみました。」[Delphi-ML:32720]中川

以下、中川さんの例示コードをIntToHex型パラメータの関数にしたものです。(4桁ごとのスペースはありません)

function IntToBin(Int: LongInt; Digits: Integer = 32): string;
  // 変換の関数
  procedure ToBin(Int: LongInt; x: pointer);
  asm
    push ebx;         // ebxは使用不可なので保存
    mov edx,x;        // 文字列の先頭アドレス
    mov eax,int;      // 変換する整数
    mov ecx,32;       // 32回のループのセット
    @MAWASU:
       mov bl,'0';    // とりあえず文字「0」とする
       sal eax,1;     // 整数を左シフトして、1ビットを取り出す
       jnc @TOBU;     // ビットが0ならそのまま
       inc bx;        // ビットが1ならば文字を「1」にする
    @TOBU:
       mov [edx],bl;  // 文字を書き込む
       inc edx;       // 文字列のポインタを進める。
       loop @MAWASU;  // これを繰り返す
    mov bl,0;         // 文字列の最後は空文字
    mov [edx],bl;     // 最後の空文字の書き込み
    pop ebx;          // ebxを呼び戻す
  end;
var
  Buff: array[0..63] of Char;
begin
  if (Digits> 1) and (Digits <= 32) then
  begin
    ToBin(Int, @Buff);
    result := StrPas(Buff + 32 - Digits);
    exit;
  end;
  raise EConvertError.Create('第二パラメータが範囲外です。');
end;

// テスト
procedure TForm1.Button1Click(Sender: TObject);
begin
   Edit1.Text := IntToBin(16,8);
   Edit2.Text := IntToBin(-1);
   Edit3.text := IntToBin(Integer($F0F0F0F0));
end;

参照: [Delphi-ML:32720] <計算> <PASCAL>

0198  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/07/09 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/05 西坂良幸 編集
ドッカブルメニュー(ツールバー形式のメニュー)を実現したい。

 Delphi4でドッカブルメニューを実現するにはどうしたら良いのでしょうか?
 IDEでは実現されているので、出来るとは思うのですが...。

アメリカのインプライズのサイトで、ドッカブルメニューのコンポが配られていますよ。使用した感じ日本語環境でも大丈夫そうです。まぁ、多分かなりの問い合わせがあったんでしょうね。

TMenubar -> http://www.borland.com/devsupport/delphi/downloads/index.html
このコンポーネントを使わない場合は、以下の手順で行います。[Delphi-ML:35243][Delphi-ML:35223] Oyats、fumika

・フォームにTCoolBarを配置し、そのTCoolBarの上にTToolBarを配置
・TToolBarのShowCaptionプロパティをTrue、FlatプロパティをTrue、EdgeBordersのedTopプロパティをFalseにする
・フォームにTMainMenuを配置
・TMainMenuのメニューエディッタで、作りたいメニューを作る(MenuItemの作成)
・TToolBarの上にTToolButtonを作成し、各TToolButtonのMenuItemプロパティにTMainMenuの各MenuItem(Parent)を対応させる
・各TToolButtonのGroupedプロパティをTrue、AutoSizeプロパティをTrueにする
・フォームのMenuプロパティをnilにする(メニュー表示を消す)
・フォームのOnShortCutイベントに次のハンドラを設定する

procedure TForm1.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
  Handled := Handled or MainMenu1.IsShortCut(Msg);
end;


TMenuBarを使う人も
http://member.nifty.ne.jp/cosmic/delphi/tips_vcl.html#tmenubar
は覗いておきましょう。
参照: [Delphi-ML:32742] [Delphi-ML:35223] <Win95> <コンポーネント > <Standard>

0079  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/02 西坂良幸 編集
Windowsの「ファイルの検索」ダイアログをプログラムから使いたい

「ファイルの検索」ダイアログを出すには、DDEを使います。

フォームに TDdeClientConv コンポーネント(Systemタブ)を乗っけて、

procedure TForm1.Button1Click(Sender: TObject);
var
  Macro:string;
begin
  DdeClientConv1.SetLink('Folders','AppProperties');
  DdeClientConv1.ServiceApplication:='Explorer';
  DdeClientConv1.OpenLink;
  Macro := Format('[FindFolder("%S")]', ['D:\Delphi 3']);
  DdeClientConv1.ExecuteMacro(PChar(Macro),False);
  DdeClientConv1.CloseLink;
end;

てなふうにします。D:\Delphi 3 フォルダがカレントになります。
ちなみにどこで見つけたかというと、レジストリの

 HKEY_CLASSES_ROOT\Directory\shell\find\ddeexec

です。

なお、終了させる場合は

procedure TForm1.Button2Click(Sender: TObject);
var
 hDialog;
begin
 hDialog:=FindWindow('#32770',nil); {ダイヤログのハンドル}
 SendMessage(hDialog, WM_CLOSE, 0, 0);  {終了}
end;


が簡単でいいでしょう。
参照: [Delphi-ML:20377] <その他Windows関連> <ShellApi> <Windows> <ダイアログ>

0228  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/29 西坂良幸 rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/01 西坂良幸 編集
フォームの最小化、最大化をアニメーションでやりたい。(DELPHI)


過去のMLを検索してみましたが案外少ないようです。「最小化」の話題は結構あるのに。このような機能をもつコンポーネントがたくさんあるし、あまり重要な機能でもないということですか。

これは当然ですが、SetBoundsメソッドなんかをいじっていてもダメですね。
また、WM_SYSCOMMANDメッセージをとらえて
procedure TForm1.WMSysCommand(var msg: TWMSysCommand);
begin
  if msg.CMdType = SC_MINIMIZE then
    WindowState := wsMinimized;
  inherited;
end;

としてもだめですね。[Delphi-ML:939]

結論的に言うと、MovWindowというAPIを使うんですが、このためのちょっとした工夫が、メッセージの理解やその処理の仕方について大変勉強になります。(コンポーネント貼り付けるだけが能ではない!)

ということで、今回はちょっと解説を。
・フォーム(メインも含めて)とApplicationの同期を考慮しなければならないので、双方のWindProcをオーバーライドしなければならない。
・自分のメソッドのWindProcは、オーバーライドは簡単ですよね、
・では、ApplicationのWndProcはどうすればオーバーライドのようにできるのか。
というようなことを考えて下さい。

  TForm1 = class(TForm)
    PopupMenu1: TPopupMenu;
    N1: TMenuItem;
    N2: TMenuItem;
    N3: TMenuItem;        // ボタンではなく、メニューでテストがミソ
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure N1Click(Sender: TObject);
    procedure N2Click(Sender: TObject);
  private
    NewAppWndProc: Pointer;
    OldAppWndProc: Pointer;
  protected
    procedure WndProc(var Msg: TMessage); override;
    procedure AppWndProc(var Msg: TMessage); virtual;
  public
  end;

//  途中省略

uses MMSystem;

{$R *.DFM}
// AppliCationのWndProcをすり替えている
procedure TForm1.FormCreate(Sender: TObject);
begin
  if Application.MainForm = nil then
  begin
    // WndProcのインスタンスを作成
    NewAppWndProc := MakeObjectInstance(AppWndProc);
    // 元のApplicationのWndProcアドレスを保存
    OldAppWndProc := Pointer(GetWindowLong(Application.Handle, GWL_WNDPROC));
    // ApplicationのWndProcアドレスをNewAppWndProcに変更
    SetWindowLong(Application.Handle, GWL_WNDPROC, Longint(NewAppWndProc));
  end;
end;

// 終わる時は後始末をする
procedure TForm1.FormDestroy(Sender: TObject);
begin
  if (Application.Handle <> 0) and (OldAppWndProc <> nil) then
  begin
    // 元のWndProcに戻す
    SetWindowLong(Application.Handle, GWL_WNDPROC, Longint(OldAppWndProc));
    // インスタンスを解放
    FreeObjectInstance(NewAppWndProc);
  end;
end;

//ウィンドウプロシージャを書き直す
procedure TForm1.WndProc(var Msg: TMessage);
var
  SaveTitle: string;
begin
  with Msg do  // ここでメッセージを横取り
  begin
    if (Msg = WM_SYSCOMMAND) and (WParam = SC_MINIMIZE) then
      with Application do
      begin
        SaveTitle := Title;
        Title := Caption;
        // 再び手前に表示−−おまじない
        NormalizeTopMosts;
        // トップ レベルでアクティブ ウィンドウ化
        SetActiveWindow(Handle);
        // ウィンドウの位置と寸法を変更
        MoveWindow(Handle, Left, Top, Width, Height, True);
        // サウンドを再生  ふろくだから無視してください
        PlaySound('Minimize', 0, Snd_Alias or Snd_NoDefault or Snd_ASync);
        // 表示状態を設定
        ShowWindow(Handle, SW_MINIMIZE);
        Title := SaveTitle;
      end
  end;
  inherited WndProc(Msg);
end;

//アップリケーションプロシージャに置き換えられた偽のWndProc
procedure TForm1.AppWndProc(var Msg: TMessage);
begin
  with Msg do     // ここでも横取りする
  begin
    if (Msg = WM_ERASEBKGND) then
      Result := 1
    else if (Msg = WM_SYSCOMMAND) and (WParam = SC_RESTORE) then
      with Application do
      begin   // 戻す
        PlaySound('RestoreUp', 0, Snd_Alias or Snd_NoDefault or Snd_ASync);
        // トップ レベルでアクティブ ウィンドウ化
        SetActiveWindow(Handle);
        ShowWindow(Handle, SW_RESTORE);
        // わり算を大きくするとスム−ス
        MoveWindow(Handle, Screen.Width div 4, Screen.Width div 4, 0, 0, False);
        Result := 1;
      end
    else if (Msg = WM_SYSCOMMAND) and (WParam = SC_MINIMIZE) then
    begin    // 最小化
      PlaySound('Minimize', 0, Snd_Alias or Snd_NoDefault or Snd_ASync);
      // フォーム
      Perform(WM_SYSCOMMAND, SC_MINIMIZE, 0);
    end
    else
      Result := CallWindowProc(OldAppWndProc, Application.Handle, Msg, WParam, LParam);
  end;
end;


これをヒントに自分でコンポーネント化するのは簡単でしょう。
もう一つ、フォームへのメッセージを横取りするWndProcをコンポーネントで書くということです。

MLで話題になっていたので、ひとこと。ボタンやメニューで最小化する時は

procedure TForm1.N1Click(Sender: TObject);
begin
  Application.minimize;  // これはダメ アニメーションしない(当然)
end;

procedure TForm1.N2Click(Sender: TObject);
begin
  Perform(WM_SYSCOMMAND, SC_MINIMIZE, 0); // これでうまくいく
end;

逆のRestoreの場合は、
  Application.minimize;
  Perform(WM_SYSCOMMAND, SC_RESTORE, 0);
でも似たようなものになります。
なぜか?  → MLを再読されたし。
参照: [Delphi-ML:939] [Delphi-ML:34432] <Windows> <フォーム>

0216  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/25 おばQ rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/01 おばQ 編集
RichEditでHTMLタグを色・書式付き表示をする

HTMLソースを表示する時タグだけ色分けや書式付きで表示されると便利です。
以下のソースを入力して、RichEditにHTMLソースを表示させて
ボタンを押すと、なかなか高速にタグだけに色がつきます。
テキストを検索してSelAttributesで色付けしてもいいのですが、
あまりにも遅いのでほとんどAPIを使います。

タグを入力してリアルタイムに色をつけることは少々ムズカシそうだったので
実装していません。こちらと組み合わせてみるのもよいでしょう。
そちらの方法は、自分で考えてね(^^;;;

//関数部
procedure RichEditHTMLTagPickUp(RichEdit: TRichEdit; TagColor: TColor);
    function ColorToStringHex(Value: TColor): string;
    begin
      Result := '$00' + IntToHex(ColorToRGB(Value),6)
    end;
var
  mask: Longint;
  CFmt: TCharFormat;
  Str: String;
  PTop, PPos, PEnd, PNext: PChar;
  CR: TCharRange;
begin
  try
    RichEdit.Lines.BeginUpdate;//高速化、1

    mask := SendMessage(RichEdit.Handle, EM_GETEVENTMASK, 0, 0);//高速化、2
    SendMessage(RichEdit.Handle, EM_SETEVENTMASK, 0, 0);
    with RichEdit do
    begin
        SelStart := length(Text);//高速化、3
        Perform(EM_SCROLLCARET, 0, 0);

        case 1 of
          0:
          begin
            CFmt.cbSize := sizeof(CFmt);
            CFmt.dwMask := CFM_BOLD;
            CFmt.dwEffects := CFE_BOLD;
          end;
          1:
          begin
            CFmt.cbSize := sizeof(CFmt);
            CFmt.dwMask := CFM_COLOR;
            CFmt.crTextColor := ColorToRGB(TagColor);
          end;
        end;

        Str := RichEdit.Text;
        PTop := PChar(Str);
        PPos := PTop;

        while (AnsiStrScan(PPos, '<') <> nil) do//高速化、4
        begin
          PPos := AnsiStrScan(PPos, '<');
          PEnd := PPos;
          while (AnsiStrScan(PEnd +1 , '>') <> nil) do
          begin
            PNext := AnsiStrScan(PEnd +1 , '>');
            PEnd := PNext +1;
              while (PEnd = PChar(#13)) or (PEnd = PChar(#10)) do
                Inc(PEnd);
              if PEnd <> PChar('<') then Break;
          end;
          CR.cpMin := PPos - PTop;
          CR.cpMax := PEnd - PTop;
          RichEdit.Perform(EM_EXSETSEL, 0, lParam(@CR));
          RichEdit.Perform(EM_SETCHARFORMAT, 1, lParam(@CFmt));//書式決定
          PPos := PEnd;
        end;
    end;
  finally
    SendMessage(RichEdit.Handle, EM_SETEVENTMASK, 0, mask);//高速化、2終
    RichEdit.Lines.EndUpdate;//高速化、1終
  end;
end;

//実装部
procedure TForm1.Button2Click(Sender: TObject);
begin
  RichEditHTMLTagPickUp(RichEdit1, Form1.Color);
end;

注意:タグが綺麗に閉じられていないと無限ループに
   はまってしまう事が考えられます。気をつけてください

内部でcase文に1を設定している所があります。
ここを0にしますとHTMLタグがBold属性になります。
1の場合ですとForm1.Colorになります。
適当に書きなおしてください。

RichEditのUndoバッファは影響を受けますので注意です。

元々はC++BuilderMLでのC++Builder用のTipsでしたが、
Delphiに書き換えました。
MLのC++BuilderでのサンプルソースはMLを参照してください。
Delphi版とほぼ同じ内容です。
参照: [builder:8463] <WWW> <通信> <Win95> <コンポーネント >

0231  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/31 おばQ rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/31 おばQ 編集
LinesプロパティエディタでTabを入力する

TMemoやTRichEditでは設計時にLinesプロパティを
設定することが出来ます。

文字列リストの設定ダイアログ(という名前か?)
というLinesのプロパティエディタが表示されて編集します。
常識ですね。

さて、ここでTabキーを押してもTabが入力出来ません!
さあ、困った困ったどうしよう。

そういう時にはCtrl+Tabキーを押します。
参照: <Win95> <Standard> <コンポーネント >

0230  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/31 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/31 osamu 編集
全角文字が半角文字の2倍幅になるフォントの選び方

等幅フォントを使っても、全角文字と半角文字を混ぜて使うと、桁の位置がずれて見づらくなってしまう場合があります。これは、特定のフォントサイズ以外では、全角文字が半角文字の2倍の幅にならないことに起因しています。

ピクセル単位とポイント単位の変換は以下のようになっています。

Point  = 72 * ( Pixels / GetDeviceCaps(hDC, LOGPIXELS_) )
Pixels = Point / 72 * GetDeviceCaps(hDC, LOGPIXELS_)

ここで、LOGPIXELS_ は LOGPIXELSX または LOGPIXELSY ですが、幅を問題にする場合には、LOGPIXELSX を使います。

Pixels が整数になるような Point 数の等幅フォントを使えば、全角文字がちょうど半角文字二つ分の幅になり、エディタのように使った場合に、「ずれ」が生じません。

たとえば、画面の設定が 96dpi の時、第2式は
Pixels = 4 * Point / 3
となりますので、適するサイズは、3の倍数ポイントのフォントということになります。
参照: <描画>

0215  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/25 花井@自宅 rev 1.5
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/31 花井@自宅 編集
RichEdit の全パラグラフのタブ幅を設定する

RichEdit では、各パラグラフごとにタブ位置を設定できます。
[DelphiML:41963]にて、全パラグラフに一定間隔のタブ位置を
設定する関数を紹介しています。等幅フォント専用です。

(補足)
Tab の幅は書式なので書式付きテキストの OLE D&D と
ペースト処理時にはTabの幅が変化すると予想されます。
ペースト時の書式消しは可能ですが OLE D&D を防ぐ事は
まず無理ですので、そのあたりはご容赦ください。
参照: [Delphi-ML:41963] <Win95> <コンポーネント >

0211  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/21 おばQ rev 1.7
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/31 花井@自宅 編集
TRichEdit.Paragraph.Tab[] の設定(Tab位置の設定)

<書式>

RichEdit1.Paragraph.Tab[iIndex] := ptsAbsolute

<値>
iIndex: Byte
    タブインデックス。段落の何番目のタブ位置を設定するかを示す。
    範囲は 0 から MAX_TAB_STOPS - 1 まで。
    (定数 MAX_TAB_STOPS は RichEdit.pasで定義)
ptsAbsolute: LongInt
    タブ位置。コントロール水平端からの絶対位置で単位は論理ポイント。
    (1論理ポイントは 1/72論理インチ)

<解説>
・現在選択範囲のパラグラフのタブ位置設定を行います。範囲選択がされて
  いないときは、キャレット(文字カーソル)のあるパラグラフになります。
ptsAbsoluteにスクリーンのピクセル値を元にした値を設定
  したい場合には、次のように変換します。
  (論理ポイント) =
         72 * ( ピクセル値 / 水平方向1論理インチ当りのピクセル数 )

<備考>
・Delphi のバージョンによっては、バグのために Tab[] プロパティの設定
  が行われないパターンが発生します。詳細は[Delphi-ML:41966] をご覧下さい。
  (Delphi 4.0 Update 3 には存在しています。)
  

<サンプル>
  テキスト選択範囲内にあるパラグラフの最初のタブ位置をコントロール
  中央に設定します


// 四捨五入します
function RoundOff(X: Extended): LongInt;
begin
  if X >= 0 then
    Result := Trunc(0.5 + X)
  else
    Result := Trunc(-0.5 + X);
end;

// テキスト選択範囲内にあるパラグラフの最初のタブ位置を
// コントロール中央に設定します
procedure TForm1.RichEdit1SetFirstTabAtCenter;
var
  DC: HDC;
  PixelsPerInch: Integer;
  CenterByPixels: Currency;
  CenterByPoints: Currency;
begin
  // 水平方向1論理インチ当りのピクセル数を取得します。
  DC := GetDC(0);
  PixelsPerInch := GetDeviceCaps(DC, LOGPIXELSX);
  ReleaseDC(0, DC);

  // RichEdit1 の中央を得ます(ピクセル値)
  CenterByPixels := RichEdit1.ClientWidth / 2;
  // スクリーンのピクセル値から論理ポイント値に変換します
  CenterByPoints := 72 * (CenterByPixels / PixelsPerInch);

  // タブ位置を設定します。
  RichEdit1.Paragraph.Tab[1] := 0;  // バグ回避のため
  RichEdit1.Paragraph.Tab[0] := RoundOff(CenterByPoints);
end;

// RichEdit1SetFirstTabAtCenter を呼び出します。
procedure TForm1.Button1Click(Sender: TObject);
begin
  RichEdit1SetFirstTabAtCenter;
end;


参照: [Delphi-ML:41923] [Delphi-ML:41966] <Win95> <コンポーネント >

0227  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/29 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/30 osamu 編集
メインフォーム以外のフォームを最小化した時もAPP全体を最小化したい


複数のフォームを持つAPPで、メインフォームでないフォームのMiniMizeボタンを押すとこのフォームは左下にタイトルバー形式にアイコン化され、メインフォームはそのまま残っています。これはこれで意味があるのですが、どのフォームを最小化してもAPP全体を最小化したい時があるものです。

これは、WM_SYSCOMMANDメッセージをとらえて、Appicationを最小化すればできます。

// Form2は、メインフォームでないフォームです。

type
  TForm2 = class(TForm)
    // コントロールいろいろ
  private
    procedure WMSysCommand(var Message: TWMSysCommand);message WM_SYSCOMMAND;
  public
    { Public 宣言 }
  end;

var
  Form2: TForm2;

implementation

{$R *.DFM}

procedure TForm2.WMSysCommand(var Message: TWMSysCommand);
begin
 if (Message.CmdType and $FFF0 = SC_MINIMIZE) then
    Application.Minimize
  else
    inherited;
end;


最小化された状態の判定は、
  IsIconic(Application.Handle); で行います

「元のサイズに戻す」のは、
  Application.Restore;    ですね。

TCustomFormのWM_SYSCOMMANDメッセージ処理は

  if (Message.CmdType and $FFF0 = SC_MINIMIZE) and
    (Application.MainForm = Self) then
    Application.Minimize
  else
    inherited;

のようになっていることからもわかるように、本来メインフォームとApplicationフォームとは別のものです。
この違いからWindowStyleプロパティの独特の仕様が生まれているのでしょうか?
左下にアイコン化するときは、WindowStyleプロパティは変化しないようです。フォームのWindowStyleプロパティは、メインフォームでないときは注意が必要です。
参照: [Delphi-ML:25286] [Delphi-ML:40312] <Windows> <フォーム>

0229  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/30 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/30 osamu 編集
Pascal 版の yacc & lex

Turbo PASCAL 版の yacc と lex のセットです。

http://www.idiom.com/free-compilers/LANG/Lex-1.html
http://www.filelibrary.com/Contents/DOS/77/17.html

のあたりに、lyprg.zip とか、 lex_yacc.zip とかいう名前で、
転がっています。

数式評価ルーチンくらいならこれで簡単に書けますね。
どっかに Object Pascal のパーサ転がってませんかね?
参照: <開発環境> <PASCAL>

0222  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/28 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/28 西坂良幸 編集
データコントロールのDataLinkオブジェクトを取得する方法(ReadOnlyプロパティのバグの解決法)


VCLでは、DataControlのFDataLinkは、プロパティになっていないので、アクセスできませんが、
DataControlにCM_GETDATALINKメッセージを投げる事で取得(参照)できます。[Delphi-ML:41387]田原
多重継承ができないので、こうなっているそうです。

これによって、MLでも多い質問ですが、いわゆる「極東仕様」問題、すなわち、TDBEdit の ReadOnly と継承元の TCustomEdit のReadOnly の同期がとれないバグを解決することができます。[Delphi-ML:41051]藤中

以下は、藤中さんの例示コード(省略部あり)です。

// このデータコントロール(フィールド対応)は編集可能か?
function IsCanModifyFieldDataControl(Control: TControl) : Boolean;
var
  DataLink : TFieldDataLink;
begin
  // データリンクを取得
  DataLink := TFieldDataLink(Control.Perform(CM_GETDATALINK,0,0));
  if (DataLink = nil) then
     DatabaseError('CM_GETDATALINK は無効', Control);
  // データリンクが編集可能かどうか調べる
  Result := DataLink.CanModify and
          ( DataLink.DataSource.AutoEdit or
           (DataLink.DataSource.State in [dsInsert, dsEdit]) );
end;

// たとえば、Table1のAfterScrollイベントなどで動的にReadOnlyを変更する

type TCustomEditCracker = class(TCustomEdit);

procedure TForm1.Table1AfterScroll(DataSet: TDataSet);
var
  Flg :Boolean;
begin
  // 条件
  if DataSet.FieldByName('制御フラグ').AsString = '1' then
    Flg := True
  else
    Flg := False;
  // 以下でReadOnlyを変更
  DBEdit1.ReadOnly := Flg;
  if (Flg = False) then
  begin
    TCustomEditCracker(DBEdit1).ReadOnly :=
               not IsCanModifyFieldDataControl(DBEdit1);
  end
  else begin
    TCustomEditCracker(DBEdit1).ReadOnly := True;
  end;
end;

参照: [Delphi-ML:41387] [Delphi-ML:17611] [Delphi-ML:41051] <データベース> <バグ> <コンポーネント > <DataControls>

0206  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/18 西坂良幸 rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/26 西坂良幸 編集
ダイヤラを呼び出す。(TAPI32.DLLの使用)


TAPI32.DLLのtapiRequestMakeCall関数を呼び出します。


function tapiRequestMakeCall(pDestAddress,pAppName,pCalledParty,pComment: PChar): LongInt; stdcall; external 'TAPI32.DLL';

procedure CallDialar(Number, DName , Comment : string);
begin
  tapiRequestMakeCall(pChar(Number),
    PChar(Application.Title), pChar(DName), PChar(Comment));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  CallDialar('06-5556-1234', '山田太郎', '');
end;


で、ダイアラが起動します。


本格的にTAPIを使う場合は、Tapi32.dll用の定義ユニットが必要です。

なお、TAPIの定義ユニットは、
外国製ですが、
 d_tapi.zip (28K)のTapi.pas
 tapid3.zip (28K)のTapih.pasなどがあります。

これらは、桜島子宮さんの ページ
http://www.kobira.co.jp/sakura/d_net_RasAPI.htm

からダウンロードできます。
参照: [Delphi-ML:6833] [Delphi-ML:17807] [Delphi-ML:41356] <ShellApi> <Windows>

0182  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/26 西坂良幸 編集
他のアプリの起動パスを取得する


> (ウィンドウハンドルの場合)
> GetWindowLong(hwnd, GWL_HINSTANCE) でモジュールハンドルを取り出す。
> (モジュールハンドルの場合)
> GetModuleFileName(hModule, strBuffer, nBufferSize) でファイル名を得る。

 残念ですがこの方法では、他のアプリの起動パス は取得できません。自分自身のExe名しか取得できません。(私も最初はこれではまった。)(^.^)

 モジュールハンドルはプロセス毎に独立して管理されるので、他のアプリ(他のプロセス)のモジュールハンドルを持ってきても意味がありません。

http://www.microsoft.com/japan/support/kb/articles/J041/6/32.htm

にシステム内で稼働中のプロセスを列挙する方法がでてますから、参考にしてください。ウィンドウハンドルが判っているのでしたら、
GetWindowthreadProcessID でプロセスIDを求めて、列挙中にこれと合致するプロセスを探せばよいでしょう。

たとえば、Win95/98用(WinNTではダメ)ですが、


uses TLHelp32;

// ハンドルからファイル名を得る
function GetProcesFileNameFrom(Handle: hWnd):string;
var
  PID: DWORD;
  SnapShot: THandle;
  ProcessEntry32: TProcessEntry32;
begin
  // ハンドルから作成スレッドを調べてプロセスIDを得る
  GetWindowThreadProcessId(Handle, @PID);
  // TProcessEntry32構造体の初期化
  ProcessEntry32.dwSize := SizeOf(TProcessEntry32);
  // システム中の情報のスナップショットをとる
  SnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  try
    // 最初のプロセスの検索
    if Process32First(SnapShot, ProcessEntry32) then
    begin
      repeat
        // IDが一致したら
        if ProcessEntry32.th32ProcessID = PID then
        begin
          Result := string(ProcessEntry32.szExeFile);
          break;
        end;
      // 次のプロセスの検索
      until Process32Next(SnapShot, ProcessEntry32) = False;
    end;
  finally
    CloseHandle(SnapShot);
  end;
end;

などです。
参照: [Delphi-ML:30032] <アプリケーション> <Windows> <ファイル>

0219  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/26 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/26 西坂良幸 編集
セルのテキストをドラッグイメ−ジにしてグリッド(TStringGrid)でドラッグ&ドロップを行う


やり方は2つあって、Drag Object をすりかえる方法と
コントロール側で DoStartDrag, DoEndDrag, GetDragImages 等を
override する方法があります。[d40216]中村

以下は、[d40948]で須賀さんが書いたコードを若干省略したものです。
Drag&Dropのやり方として大変参考になりますね。


type
  TForm1 = class(TForm)
    //<省略>
   ・・・・・
  public
     CursorSave:TCursor;
  end;

  type

  TCustomDragObject = class(TDragControlObject)
  public
    function GetDragImages: TDragImageList; override;
    procedure HideDragImage; override;
    procedure ShowDragImage; override;
    function GetDragCursor(Accepted: Boolean; X, Y: Integer)
      : TCursor; override;
    procedure Finished(Target: TObject; X, Y: Integer;
                      Accepted: Boolean); override;
  end;

    //<省略>
   ・・・・・

var  // ローカルに宣言
  w_x,w_y:integer; // もとのcellの位置を取っておく
  Images: TImageList; // Image作成用
  drag_sizex,drag_sizey:integer;  // 作成したimageのサイズ
  drag_enter_sw:smallint;   // drag start時かどうかのsw

function TCustomDragObject.GetDragImages: TDragImageList;
begin
  Result := Images;
end;

procedure TCustomDragObject.HideDragImage;
begin
  GetDragImages.HideDragImage;
end;

procedure TCustomDragObject.ShowDragImage;
begin
  GetDragImages.ShowDragImage;
end;

procedure TCustomDragObject.Finished;
begin
  inherited;
  Free;
end;

function TCustomDragObject.GetDragCursor;
begin
  Result := crDeFault;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  drag_enter_sw := 0;   // drag start時かどうかのSwをクリア
  Grid1.ControlStyle := ControlStyle + [csDisplayDragImage];

  // 適当にセルに文字列を・・・
  Grid1.cells[1,1]:='AAA';
end;

procedure TForm1.Grid1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
var
   acol,arow:integer;
begin
  if source is TCustomDragObject then
  begin
    Accept := True;
    Grid1.mousetocell(x, y, acol, arow);
    if (acol<0) or (arow<0) then   //
    begin
      Grid1.DragCursor := crNoDrop;
      exit;
    end
    else begin
      Grid1.DragCursor := crDrag;
    end;
    if State=dsDragMove then
    begin
      if drag_enter_sw = 0 then  // start drag時以外のとき
      begin
        if (y-drag_sizey) <= Grid1.rowheights[1] then  // 上にscroll
        begin
          if Grid1.toprow > 1 then
          begin
            Grid1.toprow := Grid1.toprow - 1 ;
            Grid1.repaint;
          end;
        end;
        if (y >= (Grid1.height - 5)) then   // 下にscroll
        begin
          if (Grid1.rowcount - Grid1.visiblerowcount)>Grid1.toprow then
          begin
            Grid1.toprow := Grid1.toprow + 1;
            Grid1.repaint;
          end;
        end;
      end
      else
       drag_enter_sw := 0;
    end;
  end;
end;

procedure TForm1.Grid1StartDrag(Sender: TObject;
  var DragObject: TDragObject);
var Size: TSize;
  bm: TBitmap;
  acol,arow:integer;
begin
  drag_enter_sw := 1;  
  // drag start時にswをたてる
  Grid1.mousetocell(Grid1.screentoclient(mouse.CursorPos).x,Grid1.screentoclient(mouse.CursorPos).y, acol, arow);
  w_x := acol;   // drag開始時のcellの位置を取っておく
  w_y := arow;   // drag開始時のcellの位置を取っておく
  // textのimageを作成
  bm := TBitmap.Create;
  bm.Canvas.Font := Font;
  Size := bm.Canvas.TextExtent(Grid1.cells[acol, arow]);
  bm.Width := Size.cx;
  bm.Height := Size.cy;
  drag_sizex := Size.cx;
  drag_sizey := Size.cy;
  bm.Canvas.TextOut(0, 0, Grid1.cells[acol, arow]);
  Images := TImageList.Create(Self);
  Images.Width := Size.cx;
  Images.Height := Size.cy;
  Images.Add(bm, Nil);
  bm.Free;
  Images.SetDragImage(0, Size.cx, Size.cy);
  Images.EndDrag;
  // カーソル処理
  CursorSave := Screen.Cursor;
  Screen.Cursor := crDefault;
  // DragImageを作成
  DragObject := TCustomDragObject.Create(Grid1);  // dragobjectの差し替え
end;

procedure TForm1.Grid1EndDrag(Sender, Target: TObject; X, Y: Integer);
begin
  Screen.Cursor := CursorSave;
  Grid1.repaint;
  images.free;   // drag終了時にTImageListの開放   これを忘れていました !!
end;

procedure TForm1.Grid1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
   acol,arow:integer;
begin
  Grid1.mousetocell(x, y, acol, arow);
  if (acol < 0) or (arow < 0) then  // scroll barや最後の行より下のところにdropしたときは何もしない
  begin
    Grid1.DragCursor := crNoDrop;
    exit;
  end;
  if (Sender = Grid1) then    //  drag開始時のcellの内容をdropしたcellにcopy
  begin
    Grid1.mousetocell(x, y, acol, arow);
    Grid1.cells[acol, arow] := Grid1.cells[w_x, w_y];
    Grid1.repaint;
  end;
end;


なお、落とし穴があります。
IDEの中では、ドラッグカーソルとドラッグイメージの合成処理の過程で(TCustomImageList.CombineDragCursor)
Win95/98 が落ちることが前は良く起きました。Video Driver の問題らしいのですが、いまだに原因が良く判らないそうです。
EXEレベルではこの障害はでません。
参照: [Delphi-ML:22670] [Delphi-ML:40662] [Delphi-ML:40977] <Windows> <コンポーネント > <その他コンポーネント関連>

0220  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/26 西坂良幸 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/26 西坂良幸 編集
ツリービューのノードをドラッグ&ドロップで移動させる


TTreeViewでは、DragImageにこだわらなければ,DragModeプロパティを dmAutomatic に設定すれば、OnDragOver、OnDragDropイベントを使うだけで簡単にできます。

OnDragOverイベントのAcceptは,ユーザーがドロップするオブジェクトをそのコントロールが受け入れることを示すだけです。

ツリー構造ですので、移動が無限ルーチンに陥らないように工夫します。
下記では、
IsFamilyメソッドで、ファミリー内にその上位ノードを移動するのか
を判定し、MoveNodeメソッドですべての子ノードが移動できるように
しています。

type
  TForm1 = class(TForm)
    // <省略>
    ・・・・・
    ・・・・・
  private
    procedure MoveNode(Parent, Source: TTreeNode);
    function IsFamily(Parent, Source: TTreeNode):boolean;
  public
  end;

    // <省略>
    ・・・・・
    ・・・・・

procedure TForm1.FormCreate(Sender: TObject);
var
  i:integer;
  Node:TTreeNode;
begin
  // 適当にtreeを作成
  for i := 1 to 20 do
  begin
    node := TreeView1.Items.Add(nil,'A00'+IntToStr(i));
    node.ImageIndex := 0;
    node.SelectedIndex := 1;
  end;
end;

// 移動と削除−−すべての子ノードを移動する
procedure TForm1.MoveNode(Parent, Source: TTreeNode);
var
  node: TTreeNode;
begin
  node := TreeView1.Items.AddChild(Parent,Source.Text);
  node.ImageIndex := Source.ImageIndex;
  node.SelectedIndex := Source.SelectedIndex;
  while Source.Count > 0  do
    // 再帰させる
    MoveNode(Node, TTreeNode(Source.Item[0]));
  Source.Delete;
end;

// Sourceの一族にParentがあれば true の判定
function TForm1.IsFamily(Parent, Source: TTreeNode):boolean;
var
  i:integer;
  node: TTreeNode;
begin
  result := false;
  for i := 0 to Source.Count - 1 do
  begin
    node := Source.Item[i];
    if Node.AbsoluteIndex = Parent.AbsoluteIndex then
      result := true
    else
      // 再帰させる
      result := IsFamily(Parent, Node);
    if result then break;
  end;
end;

// ドロップ後の処理
procedure TForm1.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
Var
  Node:TTreeNode;
begin
  if (Sender is TTreeView) and (Source is TTreeView) then
  begin   //ツリーからツリー
    with Sender, Source as TTreeView do
    begin
      //新親の親
      Node := GetNodeAt(X,Y);
      if Node = Selected then
      begin
        MessageDlg('同じ所に移動はできません。', mtInformation, [mbOk], 0);
        Exit;
      end;
      //ツリーのアイテムを移動し削除
      Items.BeginUpdate;
      if IsFamily(Node, Selected) then
        //無限循環を避ける
        MessageDlg('この移動はできません。', mtInformation, [mbOk], 0)
      else
        MoveNode(Node, Selected);
      Items.EndUpdate;
    end;
  end;
end;

// ソースを確認する
procedure TForm1.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
  Accept := (Source as TTreeView) = TreeView1;
end;

参照: [Delphi-ML:3727] [Delphi-ML:22691] [Delphi-ML:30411] <Win95> <コンポーネント >

0217  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/26 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/26 西坂良幸 編集
書式付きメモ型項目へアクセスしたい


ヘルプなどでは、Streamをつかった方法が紹介されています。

DataSet.FieldByName('Field1').AsString := RichEdit1.Text;

DataSet.FieldByName('Field1').AsVariant := RichEdit1.Text;

では、PlainText となり、書式が保存されません。

 Field1  書式付きメモ型とし、
 DataSetは開かれているとします。

// リッチエディットからフィールドへの書き込み
procedure TForm1.Button8Click(Sender: TObject);
var
  Stream1 : TMemoryStream;
begin
  Stream1 := TMemoryStream.Create;
  try
    RichEdit1.Lines.SavetoStream(Stream1);
    Query1.Edit;
    TBlobField(Query1.FieldByName('Field1')).LoadFromStream(Stream1);
    Query1.Post;
  finally
    Stream1.Free;
  end;
end;

// フィールドからリッチエヂットへの読み出し
procedure TForm1.Button4Click(Sender: TObject);
var
  Stream1 : TBlobStream;
begin
  Stream1 := TBlobStream.Create(TBlobField(Query1.FieldByName('Field1')), bmRead);
  try
    RichEdit1.Lines.LoadFromStream(Stream1);
  finally
    Stream1.Free;
  end;
end;


TRichEdit系は、いくつかのバグが報告されています。
データが大きくなるとヤバイという噂です。
D4では、大部改善されたようですが、気をつけて下さい。

バグ情報は
http://www.dataweb.nl/~r.p.sterkenburg/indexpag.htm
参照: [Delphi-ML:5484] [Delphi-ML:41858] <データベース> <DataAccess> <コンポーネント >

0214  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/23 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/23 西坂良幸 編集
デスクトップのウィンドウのタイトルとハンドルを取得する


稼働中のウィンドウのタイトルとハンドルを取得するには、
APIのENumWindows関数を使います。
第一パラメータのコールバック関数は、タイトルとハンドル
をどのように処理するかを工夫します。

次の例はListBoxに列挙し、Labelにその数を示します。

function CallBackTest(WH: HWND; LP: LParam): BOOL stdcall;
var
  Buf: array [0..255] of Char;
begin
  // スタイル ビットがセットされているもののみ
  if IsWindowVisible(hwnd) then
    // タイトル バーのテキストをBufにコピー
    if GetWindowText(WH, Buf, 255) <> 0 then
      TListBox(LP).Items.AddObject(Buff, Pointer(hwnd));
  Result := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ListBox1.Clear;
  EnumWindows(@CallBackTest, Longint(ListBox1));
  Label1.Caption := IntToStr(ListBox1.Items.Count);
end;

参照: [Delphi-ML:2378] [Delphi-ML:23203] <Windows> <デスクトップ>

0213  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/23 西坂良幸 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/23 西坂良幸 編集
プロセスの実行ファイル名を列挙する


  Tipsの別項、[Win95/98で、ウィンドゥハンドルから、実行アプリ名を知る]および、[WinNTで、ウィンドゥハンドルから、実行アプリ名を知る]の例にある
  EnumProcesses95、EnumProcessesNTを使えば
汎用関数のようなものができます。

同名の関数がありますので、OverrLoad指定を忘れないで下さい。

procedure EnumProcesses(lpEnumFunc: TEnumProcs; lParam: longint);overload
begin
  case Win32Platform of
   VER_PLATFORM_WIN32_NT: EnumProcessesNT(lpEnumFunc, lParam);
   VER_PLATFORM_WIN32_WINDOWS: EnumProcesses95(lpEnumFunc, lParam);
  else
   raise Exception.Create('未対応のOSかバージョンです。');
  end;
end;

// 以下の例は、リストボックスに列挙しています。
function CallBackTest(ID: DWord; Str: PChar; LP: LParam):bool;stdcall;
begin
  TListBox(LP).Items.Addobject(Str,Pointer(ID));
  Result := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ListBox1.Items.Clear;
  EnumProcesses(@CallBackTest,Longint(ListBox1));
end;

参照: [Delphi-ML:30064] <その他Windows関連> <Windows>

0212  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/23 西坂良幸 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/23 西坂良幸 編集
Win95/98で、ウィンドゥハンドルから、実行アプリ名を知る

Win95 では、ToolHelp32 を使って取得できます。WinNT ではこの方法では使えません。
  http://www.microsoft.com/japan/support/kb/articles/J041/6/32.htm

に、Win95/NT 両方で使える方法が C 言語で書かれてます。

ここでは、上記の部分的丸写しですが、ToolHelp32を使った例を示します。
コールバック関数を適切に作れば、プロセスIDとファイル名が列挙できますので、ウィンドゥハンドルからID(ProcessID)を
  GetWindowThreadProcessID(WH: hWnd; @ID); 関数
で取得し、一致するものを探せば実行アプリ名を取得できます。


uses TLHelp32;

type
  TEnumProcs = function(ID: DWord; Str: PChar; LP:  LParam):bool; stdcall;

procedure EnumProcesses95(lpEnumFunc: TEnumProcs; lParam: longint);
var
  // 関数ポインタ
  CreateToolhelp32Snapshot: TCreateToolhelp32Snapshot;
  Process32First: TProcess32First;
  Process32Next: TProcess32Next;
  // 変数
  hLib: THandle;
  Snapshot: THandle;
  ProcEntry: TProcessEntry32;
  Flag: boolean;
begin
  // Kernel32.DLL のロード
  hLib := LoadLibraryA('Kernel32.dll');
  if hLib = 0 then
   raise Exception.Create('Kernel32.dll がロードできません。');
  // API のアドレス取得(使用するのは以下の3個)
  CreateToolhelp32Snapshot := TCreateToolhelp32Snapshot(
    GetProcAddress(hLib, 'CreateToolhelp32Snapshot'));
  Process32First := TProcess32First(GetProcAddress(hLib, 'Process32First'));
  Process32Next := TProcess32Next(GetProcAddress(hLib, 'Process32Next'));
  // ロードをチェック
  if (not Assigned(CreateToolhelp32Snapshot))
     or (not Assigned(Process32First))
     or (not Assigned(Process32Next)) then
   begin
     FreeLibrary(hLib);
     raise Exception.Create('API のアドレスを取得できません。');
   end;
  // スナップショットを行う
  Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if Snapshot = INVALID_HANDLE_VALUE then
   begin
     FreeLibrary(hLib);
     raise Exception.Create('Toolhelp32 スナップショットが取得できません。');
   end;
  // TProcessEntry32構造体の初期化
  ProcEntry.dwSize := SizeOf(TProcessEntry32);
  // 最初のプロセスの取得
  Flag := Process32First(Snapshot, ProcEntry);
  while Flag do
   begin
     // コールバック関数呼び出し
     if not lpEnumFunc(ProcEntry.th32ProcessID, ProcEntry.szExeFile, lParam) then
       break;
     // 次のプロセスの取得
     Flag := Process32Next(Snapshot, ProcEntry);
   end;
  // 解放
  CloseHandle(Snapshot);
  FreeLibrary(hLib);
end;

// コールバック関数の例
function CallBackTest(ID: DWord; Str: PChar; LP: LParam): bool; stdcall;
begin
  TListBox(LP).Items.Addobject(Str,Pointer(ID));
  Result := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ListBox1.Items.Clear;
  EnumProcesses95(@CallBackTest,Longint(ListBox1));
end;

参照: [Delphi-ML:8519] [Delphi-ML:19427] <Windows>

0051  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/23 西坂良幸 編集
WinNT でウィンドウハンドルから実行アプリ名を知る

WinNT では、ToolHelp32 が使えないので、Win95 で良く知られた方法(ToolHelp32)は使えません。
  http://www.microsoft.com/japan/support/kb/articles/J041/6/32.htm

に、Win95/NT 両方で使える方法が C 言語で書かれてます。

ここでは、PSAPIを使っています。
上記の部分的丸写しですが。

uses PsApi;

type
  TEnumProcs = function(ID: DWord; Str: PChar; LP:  LParam):bool; stdcall;

procedure EnumProcessesNT(lpEnumFunc: TEnumProcs; lParam: longint);
var
  // 関数ポインタ
  EnumProcesses: TEnumProcesses;
  EnumProcessModules: TEnumProcessModules;
  GetModuleFileNameEx: TGetModuleFileNameEx;
  // 変数
  hLib: THandle;
  Process: THandle;
  hMod: DWORD;
  PIDs: array[0..2047] of DWORD; // 動的配列ポインタの扱いを簡素化(^^;
  Size, Size2, Index: DWORD;
  ProcessName: array[0..MAX_PATH] of char;
begin
  hMod := 0;
  // PSAPI.DLL のロード
  hLib := LoadLibraryA('PSAPI.DLL');
  if hLib = 0 then
   raise Exception.Create('PSAPI.DLL がロードできません。');
  // API のアドレス取得(以下の3個を使う)
  EnumProcesses := TEnumProcesses(GetProcAddress(hLib, 'EnumProcesses'));
  EnumProcessModules := TEnumProcessModules(GetProcAddress(hLib, 'EnumProcessModules'));
  GetModuleFileNameEx := TGetModuleFileNameEx(GetProcAddress(hLib, 'GetModuleFileNameExA'));
  // ロードのチェック
  if (not Assigned(EnumProcesses))
     or(not Assigned(EnumProcessModules))
     or(not Assigned(GetModuleFileNameEx)) then
   begin
     FreeLibrary(hLib);
     raise Exception.Create('API のアドレスを取得できません。');
   end;
  // プロセスの数は2048まで
  Size2 := 2048 * SizeOf(DWORD);
  if not EnumProcesses(@PIDs, Size2, Size) then
  begin
     FreeLibrary(hLib);
     raise Exception.Create(SysErrorMessage(GetLastError));
  end;
  if Size >= Size2 then
  begin
    FreeLibrary(hLib);
    raise Exception.Create('2048 個以上のプロセスがあるみたいです。');
  end;
  Size := Size div SizeOf(DWORD);
  for Index := 0 to Size - 1 do
  begin
    // プロセスを読み出す
    Process := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,
        False, PIDs[Index]);
    if Process <> 0 then
    begin
      // プロセスのモジュールをチェック
      if EnumProcessModules(Process, PDWORD(hMod), SizeOf(hMod), Size2) then
      begin
        // ファイル名を取得
        if GetModuleFileNameEx(Process, hMod, ProcessName, SizeOf(ProcessName)) = 0 then
        begin
          ProcessName:='';
        end;
      end;
      CloseHandle(Process);
    end
    else
      ProcessName:='';
    // コールバック関数を呼び出し
    if not lpEnumFunc(PIDs[Index], ProcessName, lParam) then
    else Break;
  end;
  // 解放
  FreeLibrary(hLib);
end;

// 使用例
function CallBackTest(ID: DWord; Str: PChar; LP: LParam):bool;stdcall;
begin
  TListBox(LP).Items.Addobject(Str,Pointer(ID));
  Result := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ListBox1.Items.Clear;
  EnumProcessesNT(@CallBackTest,Longint(ListBox1));
  // リストボックスに列挙する
end;


参照: [Delphi-ML:19427] <Windows>

0210  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/21 おばQ rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/21 おばQ 編集
クリップボードのフォーマットを知る

クリップボードのフォーマットは
ヘルプを見ると幾つか定義されています。

プロフェッショナル版以上のDelphiに付属する
VCLのソースをみると
windows.pasに定義されていることが分ります。
CF_TEXTは単に1という値で定義されています

こちらの定義を用いれば現在のクリップボードのフォーマットが分ります。
定義されていないクリップボードフォーマットもありますが
その場合には単に数値として取得してみます。

procedure ClipFormat;
    function ShowMessageCF(Value: Integer): String;
      case Value of
        CF_TEXT:
          Result := 'CF_TEXT';
        CF_BITMAP:
          Result := 'CF_BITMAP';
        CF_METAFILEPICT:
          Result := 'CF_METAFILEPICT';
        CF_SYLK:
          Result := 'CF_SYLK';
        CF_DIF:
          Result := 'CF_DIF';
        CF_TIFF:
          Result := 'CF_TIFF';
        CF_OEMTEXT:
          Result := 'CF_OEMTEXT';
        CF_DIB:
          Result := 'CF_DIB';
        CF_PALETTE:
          Result := 'CF_PALETTE';
        CF_PENDATA:
          Result := 'CF_PENDATA';
        CF_RIFF:
          Result := 'CF_RIFF';
        CF_WAVE:
          Result := 'CF_WAVE';
        CF_UNICODETEXT:
          Result := 'CF_UNICODETEXT';
        CF_ENHMETAFILE:
          Result := 'CF_ENHMETAFILE';
        CF_HDROP:
          Result := 'CF_HDROP';
        CF_LOCALE:
          Result := 'CF_LOCALE';
        CF_MAX:
          Result := 'CF_MAX';
        CF_OWNERDISPLAY:
          Result := 'CF_OWNERDISPLAY';
        CF_DSPTEXT:
          Result := 'CF_DSPTEXT';
        CF_DSPBITMAP:
          Result := 'CF_DSPBITMAP';
        CF_DSPMETAFILEPICT:
          Result := 'CF_DSPMETAFILEPICT';
        CF_DSPENHMETAFILE:
          Result := 'CF_DSPENHMETAFILE';

        CF_PRIVATEFIRST:
           Result := 'CF_PRIVATEFIRST';
        CF_PRIVATELAST:
          Result := 'CF_PRIVATELAST';

        CF_GDIOBJFIRST:
          Result := 'CF_GDIOBJFIRST';
        CF_GDIOBJLAST:
          Result := 'CF_GDIOBJLAST';
        else
          Result := IntToStr(Value);
      end;//case
      ShowMessage(Result);
    end;
var
  i: Integer;
begin
  for i := 0 to 1100 do
    if Clipboard.HasFormat(i) then
      ShowMessageCF(i);
end;

1100までループさせているのは最後のCF_GDIOBJLASTが
1023で定義されていたからです。

FormにButton1を貼り付けて以下のように実装してみてください。

procedure TForm1.Button1Click(Sender: TObject);
begin
  ClipFormat;
end;

ボタンを押すと現在のクリップボードデータのフォーマットがShowMessageで表示されます
参照: <その他Windows関連> <Windows>

0209  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/21 おばQ rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/21 おばQ 編集
クリップボードが更新された時のイベントを取得する

クリップボードが更新された時、いろいろしたいことがあると思います。
少々ややこしいですが以下のようにすれば
クリップボードの更新を監視する事が出来ます。
そうするとクリップボード履歴機能を持つソフトが作れますね。

Formのメンバーに以下のように定義します

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    FClipNextHandle: HWND;

    procedure WMDrawClipboard(var Msg: TWMDrawClipboard);
        message WM_DRAWCLIPBOARD;
    procedure WMChangeCBChain(var Msg: TWMChangeCBChain);
        message WM_CHANGECBCHAIN;
  public
  end;

↑適当に省略しています

implimention部に以下のように実装します。

procedure TForm1.WMDrawClipboard(var Msg: TWMDrawClipboard);
//クリップボード更新フック
//更新された後に流れてくる。
//アプリが立ち上がった瞬間も流れる
begin
  inherited;
//------------------------------


{ここにテキストバックアップ処理等を行えば。
  クリップボード履歴機能が実装できます。}
  ShowMessage('クリップボード更新されたよ');

//------------------------------
  if FClipNextHandle<>0 then
    SendMessage(FClipNextHandle,WM_DRAWCLIPBOARD, 0, 0);
end;

procedure TForm1.WMChangeCBChain(var Msg: TWMChangeCBChain);
begin
  if Msg.Remove = FClipNextHandle then
    FClipNextHandle := Msg.Next;
  if FClipNextHandle <> 0 then
    SendMessage(FClipNextHandle, WM_CHANGECBCHAIN, Msg.Remove,Msg.Next);
end;

procedure TForm1.FormCreate(Sender: TObject);
    procedure ClipboardSetHandle;//クリップボード履歴の為に必要な初期化
    begin
      FClipNextHandle := SetClipboardViewer(Form1.Handle);
      if FClipNextHandle = 0 then
        if GetLastError <> 0 then {本当にエラーだったら}
          ShowMessage('なぜかクリップボードのフックに失敗しました(T_T)');
    end;
begin
  ClipboardSetHandle;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ChangeClipboardChain(Handle, FClipNextHandle);
  //クリップボード監視処理の破棄
end;
参照: [Delphi-ML:5296] <その他Windows関連> <Windows>

0208  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/19 西坂良幸 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/19 西坂良幸 編集
インターネットエクスプローラのアドレス帳を呼び出す


アドレス帳(IE4以上)の起動は、使用しているアドレスデータとともに呼び出すことが重要です。
このデータは、レジストリの
HKEY_CURRENT_USER\Software\Microsoft\WAB\WAB4\Wab File Name
に示される 拡張子 wab のファイルにあり、
これを「ファイルの関連づけ」機能(IEをインストールすれば自動設定される)をつかって呼び出すのが簡単です。

procedure TForm1.Button1Click(Sender: TObject);
var
  RegIniFile: TRegIniFile;
  Wab:String;
  Comm: array[0..128] of Char;
  Ret:Integer;
begin
  Wab := '';
  Ret := 0;
  // レジストリからwabファイルを探す。
  RegIniFile := TRegIniFile.Create('Software\Microsoft\WAB\WAB4');
  try
    Wab := RegIniFile.ReadString('Wab File Name', '', '');
  finally
    RegIniFile.Free;
  end;

  if Wab <> '' then
  if FileExists(Wab) then
  begin
    StrPCopy(Comm, Wab);
    Ret := Shellexecute(Handle, 'Open', Comm, '', '', SW_SHOWNORMAL);
  end;
  if Ret < 32 then
       ShowMessage('呼び出しに失敗しました。');
end;

参照: [Delphi-ML:39621] <その他Windows関連> <Windows>

0205  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/17 osamu 編集
PASCAL ソースの整形ツール

Tips Lounge で花井さんが紹介してくれました。Delphi Super Page
http://sunsite.icm.edu.pl/delphi/
にある delforex.zip というファイルです。D2-D4 にインストールして使えるエキスパートで、他人の書いた汚い(?)ソースをワンキーで自分好みに変換することが出来ます。便利々々。
参照: <PASCAL>

0089  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/14 osamu 編集
Delphi2/3.x における Cardinal 型の妙な定義

>Delphi3.1のWindows.pasの中で、
>  DWORD = Integer; と定義されていますが、
>  DWORD = Cardinal; ではないのでしょうか。
>
>また、ヘルプ及びマニュアルに
>  Cardinal 0〜2147483647 符号なし 32 ビットと書かれていますが、
>  0〜4294967295 ではないのでしょうか.。

残念ながらマニュアルの通りです。
また Cardinal 型の変数には マイナス値や 2147483647 を超える定数値を代入することは出来ませんが、「オプション」の「範囲チェックエラー」をオフにしておくと 計算の結果負数を持つことは出来ます。
例えば

var i: Cardinal;
   :
   :
  i := 10;
  i := i - 20;
  if i >= 0 then ShowMessage('Plus')
            else ShowMessage('Minus');

は Minus と表示されます。つまり Integer とほとんど変わりません。

[Delphi-ML:23120]によれば、Delphi4 ではちゃんと Cardinal=(0..2^32-1) になっているようです。
参照: [Delphi-ML:20567] [Delphi-ML:23120] <バグ> <PASCAL>

0035  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/14 osamu 編集
MS-Word 97 で作成した rtf ファイルがヘルプコンパイラでエラーを起こす

Delphi付属のヘルプコンパイラではMS-Word97で作成したrtfファイルをコンパイルできません。
    http://support.microsoft.com/support/downloads/dp2677.asp
から、Word97対応のヘルプコンパイラがダウンロードできます。
参照: [Delphi-ML:6924] [Delphi-ML:16043] [Delphi-ML:18838] <バグ> <ヘルプ>

0012  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/14 osamu 編集
カスタムコントロールの子コントロールをオブジェクトインスペクタに表示させない

オブジェクトインスペクタには、OwnerがFormであるコントロールだけが表示されるので、カスタムコントロールの内部で作成するコンポーネントならば、OwnerにSelfを与えればよいです。
サンプルコンポーネントのTSpinEditなどを参照しましょう。
参照: [Delphi-ML:5112] <コンポーネント開発>

0004  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/14 osamu 編集
ショートカットキーのキー名を独自に設定する

例えば、テンキーの + キーをショートカットにした場合に、'Num +'とか表示させたい。
TMenuItem.AppendTo()を参照すると、

    TestMenu1.Caption:=TestMenu1.Caption+#9+'Num +'+#0;

とすればよいことが分かる。

キャプションとショートカット名との間にはさんだタブ文字と、自動で追加されるショートカットを隠すために最後にくっつけられた #0 とが味噌。
参照: [Delphi-ML:17989] <コンポーネント > <Standard> <メニュー>

0180  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/10 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/14 osamu 編集
Object Pascal のコーディングスタイル

>   最近 Delphi でプログラムを書いているのですが、インデントの仕方や
> begin, end をどこに書いたらいいのか迷っています。

  以下の書籍にコーディングスタンダードが記載されています。購入していないので何章かは忘れました。

「Delphi 4 プログラミング技法 Vol.1 Win32プログラミングテクニック 」
  ザビエル・パチェコ+スティーブ・テイクセラ(日向 俊二 訳)

ボーランドの開発者も使用しているらしく、VCLやサンプルプログラムでは、大半がこのガイドにしたがっています。

また、以下のサイト(著者のサイト)に同様の内容があります。(但し英語)

Delphi 4 Developer's Guide
   http://www.xapware.com/ddg/

また、[Delphi-Doc:00906]で中村@NECさんが、Borland の Delphi チームが実践しているコーディングスタイルを紹介したページを報告してくださいました。

http://www.borland.com/techvoyage/articles/DelphiStyle/StyleGuide.html
参照: [Delphi-ML:38485] <PASCAL>

0203  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/13 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/13 osamu 編集
TColor 値を文字列に変換する

レジストリに TColor 型の値を格納したいような場合、ColorToString 関数を使えば TColor から AnsiString に変換できるので、あとは TRegistry の WriteString で書き出してやればいいと思います。
反対に AnsiString から TColor に戻すのは StringToColor 関数を使えばいいです。
詳しくはヘルプを見てください。
参照: [builder:17839] <文字列> <PASCAL> <描画>

0095  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/07/28 osamu 編集
HTML-Help を作りたい

HTML-Help に関する情報ソースです。

Microsoftから
HTML Help Web site
  http://msdn.microsoft.com/workshop/author/htmlhelp/default.asp
latest version Microsoft HTML Help Workshop
  http://msdn.microsoft.com/workshop/author/htmlhelp/download.asp

国内では
  http://www.takenet.or.jp/~ryuuji/delphi/

またDelphi用のUNITが、
  http://www.mygale.org/~jlucm/
からダウンロードできます。
参照: [Delphi-ML:20899] <Windows> <ヘルプ>

0200  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/07/14 久保田 宏光 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/07/14 久保田 宏光 編集
基本的な階層プロパティ定義の例


// 子にするクラスの宣言

// ・TPersistentから継承する
// ・プロパティ内に、さらに他のクラスを定義する場合はAssignでコピーする。
//   直接代入を許さないように留意する(SetListメソッドを参照)
//   メソッドをprotectedにする場合はvirtualにする。
//   また、隠蔽したい場合はprivateに置く。
//   ※protected/privateが良く分からない場合はprotected/virtualが無難
// ・クラスにAssignを実装する必要がある。

type
  TChild = class(TPersistent)
  private
    FList:TStrings;
  public
    constructor Create;
    destructor  Destroy; override;
    procedure   Assign(Source:TPersistent); override ;
  protected
    procedure SetList(Value:TStrings); virtual;
  published
    property List :TStrings read FList write SetList;
  end;

//親側のクラス宣言

//・こちらでも、Childプロパティの書き込みにSetChildを実装する。

type
  TParent = class(TComponent)
  Private
    FChild:TChild;
  public
    constructor Create(AOwner:TComponent); override;
    destructor  Destroy; override;
  protected
    procedure SetChild(Value:TChild); override;
  published
    property Child :TChild read FChild write SetChild;
  end;

//実現部(子)

//・抽象クラスで宣言したプロパティは、こちらで実装クラスとして
//  create/freeする。
//・プロパティのwriteはメソッドになっている。間違っても
//   List := TStringList.Create
//   ~~~~   などとしないように。
//・コンポーネントがTStrings内でObjectsを使用している場合のみ、
//  free時に解放する。
//  
//  例 )
//  for i:=0 to FList.count - 1 to
//    FList.Objects[i].Free;
//  FList.Free;

constructor TChild.Create;
begin
  inherited Create;
  FList := TStringList.Create;
end;

destructor TChild.Destroy;
begin
  FList.Free;
  inherited Destroy;
end;

procedure TChildSetList(Value:TStrings);
begin
  if Value <> FList then
    FList.Assign(Value);
end;

Procedure TChild.Assign(Source:TPersistent);
begin
   if Source is TChild then
      FList.Assign(TChild(Source).List);
   inherited Assign(Source);
end;

//実現部(親)

//・FChildをcreate/freeするのを忘れないように。

constructor THyperText.Create(AOwner:TComponent);
begin
  inherited Create(AOWner);
  FChild := TChild.Create;
end;

destructor THyperText.Destroy;
begin
  FChild.Free;
  inherited Destroy;
end;

参照: <コンポーネント開発> <PASCAL>

0197  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/07/09 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/07/09 osamu 編集
@ 演算子の働き

Hidetoshi NAKAI さんは書きました:
> すごく初歩的な質問だと想うのですが、変数の前に
> "@" (アットマーク) を付加すると、どういう効果が
> あるのでしょうか?

初歩的でもないですよ。結構知らない人がいます。

手続き(メソッド)型でない変数の場合:
  その変数を指すポインタを返します。ポインタの型は
  {$T-} の状態では Pointer 型に、{$T+} の状態では
  ^[変数の型] になります。

手続き型(メソッド型)の変数の場合:
  変数が手続きの呼び出しと解釈されることを抑止し、
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  手続き(メソッド)へのポインタが入っている変数として
  扱うことを強制します。従って変数のポインタを 取得
  したい場合は @@A という具合に @ を2個書きます。

手続き名、関数名、メソッド名の場合:
  手続き、関数、メソッドもエントリポイントを指す
  ポインタ(メソッドポインタ)が返ります。

詳しくは @ 演算子のヘルプを見てください。
参照: [Delphi-ML:32704] <PASCAL>

0195  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/07/07 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/07/07 osamu 編集
CapsLock の状態を変更する

> ある入力コントロールにフォーカスが移った時に、CapsLockを
> プログラムにて On/Off することは出来ないでしょうか?

keybd_event で CAPS キーを押したことにしてあげれば良いです。この方法は、いろいろ応用がききそうです。

// CapsLock を Off にする場合
procedure TForm1.Edit1Enter(Sender: TObject);
begin
  if GetKeyState(VK_CAPITAL) and 1 = 1 then begin
    keybd_event(VK_CAPITAL, 0, 0, 0);
    keybd_event(VK_CAPITAL, 0, KEYEVENTF_KEYUP, 0);
  end;
end;

// CapsLock を On にする場合
procedure TForm1.Edit2Enter(Sender: TObject);
begin
  if GetKeyState(VK_CAPITAL) and 1 <> 1 then begin
    keybd_event(VK_CAPITAL, 0, 0, 0);
    keybd_event(VK_CAPITAL, 0, KEYEVENTF_KEYUP, 0);
  end;
end;
参照: [Delphi-ML:33786] <Windows>

0193  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/06/08 おばQ rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/06/08 おばQ 編集
LhasaのようなUIを持つアプリケーションの作成方法

Lhasaという有名な圧縮解凍ソフトをご存知だと思います。
そのUIはファイルをexeにDrag&Dropした時は解凍を行い、
普通に起動の場合、Formが開きます。

つまり最小化起動して処理をして終了するアプリケーションです。
その基本的なUIを実現します。

普通にFormを作り以下のコードを書きます。

procedure TForm1.FormShow(Sender: TObject);
var
  i:Integer;
begin
  if ParamCount=0 then
//Drag&Dropされていない場合はParamCount=0
  begin
    Application.Title := 'サンプルプログラム';
//普通に起動します。
  end else
  begin
    Application.Title := '処理中';
    Application.Minimize;//最小化起動

    for i:=1 to ParamCount do
    begin
    {
    ここでDrag&Dropされたファイルに対しての処理を行う
    ParamStr(i)でファイル名がパス名付きで取得できるので
    読込み、処理を行い、書きこむと良いです。
    }
    end;
    Application.Terminate;  
//最小化起動したアプリを終了させる
  end;
end;

参照: <アプリケーション>

0192  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/28 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/28 osamu 編集
TFileListBox にファイル名が重複して表示されてしまう

TFileListBox.Mask に、'*.txt;*.?x?' などと入力した場合、もし複数の Mask に合致するファイル(例えば、example.txt)があると、そのファイルはダブって表示されてしまいます。これを回避する単純な方法は、TDirectoryListBox.OnChange にて、重複しているファイル名を削除してやることです。

procedure Form1.DirectoryListBox1Change(Sender: TObject);
var i: Integer;
begin
    for i:=FileListBox1.Items.Count-2 downto 0 do
        if FileListBox1.Items[i]=FileListBox1.Items[i+1] then
            FileListBox1.Items.Delete(i+1);
end;

この位のことは、TFileListBox 自身で面倒を見てもらいたいものですが。。。
参照: <System> <コンポーネント >

0191  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/19 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/19 osamu 編集
コンボボックスのリスト部分の幅を指定する

>コンボボックスをクリックして表示されるリストの幅を
>コンボボックスコントロール自体の幅よりも広くして
>表示することはできないでしょうか?

ComboBox1->Perform(CB_SETDROPPEDWIDTH, 幅, 0);

です。詳細は Win32.hlp(English) を参照してください。
参照: [builder:12689] <Standard> <コンポーネント >

0136  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/19 osamu 編集
独自メッセージとして自由に使える値の範囲

MSDN (99/01 版)をみた感じでは、

$0000          - $03FF (WM_USER-1) システム用予約領域
WM_USER ($0400)- $7FFF (WM_APP -1) WindowClass 用
WM_APP  ($8000)- $BFFF             アプリケーション用
$C000          - $FFFF             RegisterWindowMessage 用
$10000         - last              今後のために予約

で、自由に使用できるのは、WM_USER から $BFFF であると読み取れます。ただし、WM_USER 〜 $7FFF はアプリケーションの制御ではなく、その部品になっているウィンドウコントロールのために予約しておくほうがよいので、コード中から独自メッセージを PostMessage するような場合には、WM_APP〜$FFFF までを使うとよいようです。
参照: [Delphi-ML:24086] <その他Windows関連> <Windows>

0189  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/19 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/19 osamu 編集
「送る」の 516 文字制限について

> エクスプローラー等の右クリックの「送る」に機能を
> 追加するソフトを開発しています。SendToフォルダに
> ショートカットを置くことで、上の機能を実現してい
> るのですが、コマンドラインからの起動(?)の516文字
> 制限に困っています。

おそらく、「送る」に頼らず自力でシェルエクステンションを登録するという解決策が一番実現しやすいかなと思っています。
言い換えれば、右クリックしたとき独自のメニューを表示させ、あとはそのメニューに関連付けられたdllがファイル名を処理するというわけです。
参照: [Delphi-ML:37241] <Windows>

0188  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/19 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/19 osamu 編集
TRichEdit の内容を高速に変更する

> RichEdit の Lines の内容を、次の様に変更しているんですが、
> 3000行で10秒もかかってしまいます。
>
> var sl: TStringList;
>
>   for i:=1 to 3000 do
>     sl.Add(IntToStr(i));
>   RichEdit1.Lines.Assign(sl);


ストリームを経由すると速いですよ。

var ms: TMemoryStream;

  ms := TMemoryStream.Create;
  try
    sl.SaveToStream(ms);
    ms.Position := 0;
    RichEdit1.Lines.LoadFromStream(ms);
  finally
    ms.Free;
  end;

3000行で一秒以下でした。(Pentium 150MHz)
参照: [builder:16379] <Win95> <コンポーネント >

0186  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/14 おばQ rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/14 おばQ 編集
文字数のカウント方法

普通にLength関数で文字数をカウントすると半角文字の数になります。例えばLength('あいうえおABCDE')は15です。

全角文字を1文字としてカウントするにはWideStringを使います。Length(WideString('あいうえおABCDE'))は10です。

WideStringにキャストするより高速な手法としてByteToCharLenを使う方法もあります。
ByteToCharLen('あいうえおABCDE', Length('あいうえおABCDE'))は10です。
参照: <文字列> <PASCAL>

0187  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/14 おばQ rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/14 おばQ 編集
システムカラーを得る、設定する

ひきさんのページ『日本Delphi振興会』にも載っていますが
更に情報を加えておきます。

WindowsAPIでWindowsのシステムカラーを得たり設定したりする事が出来ます。それぞれGetSysColor、SetSysColorというAPI関数です。

サンプルとしてButton1を押すと色の設定情報を読込み
Button2を押すと読込んだ情報を設定するというものを作りました。

Button1を押して
その後にコントロールパネルでWindowsの色設定を変更しても
Button2を押す事で変更前の色設定になります。

const
  SysColorMaxNumber=28;
type
  TForm1 = class(TForm)
…省略…
  private
    FList: array[0..SysColorMaxNumber] of Integer;
    FColorList: array[0..SysColorMaxNumber] of TColor;
    FRGBList: array[0..SysColorMaxNumber] of Longint;
  end;

…省略…
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  for i:=0 to SysColorMaxNumber do
  begin
    FList[i] := i;
    FColorList[i] := TColor(GetSysColor(i));
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i: Integer;
begin
  for i:=0 to SysColorMaxNumber do
    FRGBList[i] := ColorToRGB(FColorList[i]);
  SetSysColors(SysColorMaxNumber,FList,FRGBList);
end;

GetSysColor(COLOR_ACTIVECAPTION)という定数も指定出来ます。この定数はwindows.pasに定義されています。

Delphiで定義されている色のclBtnFaceやclActiveCaptionとAPIでのGetSysColor(COLOR_ACTIVECAPTION)との違いは以下のようなコードで理解できるでしょう。

ShowMessage(IntToHex((clRed),8));
ShowMessage(IntToHex((clBtnFace),8));
ShowMessage(IntToHex(GetSysColor(COLOR_BTNFACE),8));
ShowMessage(IntToHex(ColorToRGB(clRed),8));
ShowMessage(IntToHex(ColorToRGB(clBtnFace),8));
ShowMessage(IntToHex(ColorToRGB(GetSysColor(COLOR_BTNFACE)),8));
参照: <描画>

0185  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/12 花井@自宅 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/12 花井@自宅 編集
コードエディタで「キーボードマクロ」を使う

 [Ctrl] + [Shift] + R で、動作の記録 On/Off
 [Ctrl] + [Shift] + P で、記録した動作の再生
参照: [Delphi-ML:24437] <開発環境>

0076  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/12 花井@自宅 編集
コードエディタで選択部分をまとめてインデントする

デフォルトのキーマップなら、次のショートカットが使えます。

 [Ctrl] + [K] + [I]      インデント
 [Ctrl] + [K] + [U]      アンインデント

もしくは
 [Ctrl] + [Shift] + [I]  インデント
 [Ctrl] + [Shift] + [U]  アンインデント


ヘルプの「キーボードショートカット」を見ると、他にも便利な機能を発見することができるかもしれません。
参照: <開発環境>

0075  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/12 花井@自宅 編集
コードエディタで矩形領域を選択する

(キーボード)
デフォルトキーマップでしたら、
  [Alt] + [Shift] + 矢印キー
で、できます。ただ、この後は普通に選択しても矩形になってしまいます。
元の選択モードに戻すのは、
  [Ctrl] + [O] + [K]
です。ちなみに、矩形選択モードへは
  [Ctrl] + [O] + [C]
で行けます。

(マウス)
Altキーを押しながら、エディタ領域をマウスでドラッグすればよいです。
こちらはキーボードと違って一時的に矩形選択モードになるだけなので便利です。
参照: [Delphi-ML:24425] [Delphi-ML:24478] <開発環境>

0181  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/08 osamu 編集
改行コードの違いについて

テキストを扱っていると、何かと改行コードについて気になります。

改行コードは Windows では CRLF、Macでは CR のみ、Unix 系では LF のみで示されます。制御コードとして CR が復帰 LF が改行と呼ばれます。Delphiでは CR=Char(13) または #13、LF=Char(10) または #10 として指定できます。

Label 等ではテキストの改行を行う場合、CRLF, CRのみ, LFのみ、どの場合でも改行が行えますので
Label.caption := '1行目'#10'2行目'という表現も可能です。

また、改行コードが、CR のみ、LF のみ、LFCR になっているテキストを CRLF シーケンス(つまりWindows標準形式)に変換する関数としてAdjustLineBreaks というものがあります。逆に CRLF から、CR のみLF のみ、に変換するには

  function DeleteCR(S: string): string;
  begin
    while pos(#13,S)<>0 do
      Delete(S,pos(#13,S),1);
    Result := S;
  end;

このようなものを使ってください。DeleteLFも作れるでしょう
(D4以降ではStringReplace関数が用意されていますのでそちらを使いましょう)
参照: [Delphi-ML:9035] <文字列> <PASCAL>

0179  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/01 おばQ rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/01 おばQ 編集
右の項目の幅が固定されるTStatusBar

Delphiで普通にTStatusBarを使用してスターテスバーを作り
複数のTStatusPanelを設定すると
Formをリサイズする時、右の項目の幅が変化します。

IEエクスプローラやワードパッドなどでは
WindowをResizeした時に
StatusBarの項目の右の方のものが幅が固定されていて
左の項目の幅が変化するものがあります。

推定ですが、VC++アプリケーションウィザードを普通に
用いるとこのようなものが自動で生成されるようです。

これをDelphiで実現します。
StatusBarのResizeイベントに以下のようなコードを書きます。

procedure TForm1.StatusBarResize(Sender: TObject);
const
  ResizePanelNumber=0;    //リサイズするStatusbarのパネル番号を指定
  MinSize=0;              //リサイズされても維持したい最小のWidthを指定
var
  BarWidth,i: Integer;
begin
  with StatusBar do
  begin
    BarWidth := 0;
    for i:=0 to Panels.Count-1 do
    begin
      if not(i=ResizePanelNumber) then
        BarWidth := BarWidth + Panels[i].Width;
    end;

    if (Width-BarWidth)<=MinSize then
      Panels[ResizePanelNumber].Width := MinSize
    else
      Panels[ResizePanelNumber].Width := Width - BarWidth;
  end;
end;

これで項目のうちResizePanelNumberで指定したパネルのWidthが
StatusBarのResize、つまりFormのリサイズに合わせてリサイズします。

また、
すべての項目において右の項目の幅が優先されて維持される
IEブラウザのような動作をさせるには工夫が必要です。

設計時のPanelのWidthを保持して
Panels.Widthを変化させます。

  TForm1 = class(TForm)
    …
  private
    FBarWidths: array of Integer;
  end;

procedure TForm1.FormCreate(Sender: TObject);
    procedure SetStatusBarWidth;  
    var  //右項目固定StatusBarの為に設計時のpanelのWidthを保存
      i: Integer;
    begin
      with StatusBar do
      begin
        SetLength(FBarWidths,Panels.Count);
        for i:=0 to Panels.Count-1 do
          FBarWidths[i]:=  Panels[i].Width;
      end;
    end;

begin
  SetStatusBarWidth;
end;


procedure TForm1.StatusBarResize(Sender: TObject);
var
  BarWidth,i,PointPanel,k: Integer;
begin
  BarWidth:=0;
  with StatusBar do
  begin
    PointPanel := Panels.Count;
    repeat
      dec(PointPanel);    //何番のパネルをリサイズするべきか決定する
      BarWidth := BarWidth + FBarWidths[PointPanel];
    until (Width < BarWidth)or(PointPanel=0) ;

    for i:=0 to PointPanel-1 do  //消えるべきパネルをWidth:=0にする
      Panels[i].Width := 0;

    BarWidth := 0;
    for i:=PointPanel+1 to Panels.Count-1 do
    begin
      Panels[i].Width := FBarWidths[i];
      BarWidth := BarWidth + FBarWidths[i];
    end;
    Panels[PointPanel].Width := StatusBar.Width - BarWidth;
  end;
end;


分かりにくい説明ですが、プログラムを実行すると分かります。
VCL化してみるのも面白いでしょう。
参照: <Win95> <コンポーネント >

0178  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/04/29 おばQ rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/04/29 おばQ 編集
TCoolBarを用いたツールバーの位置保存

クールバーでツールバーを作った場合、
その位置を起動時に前回の状態に戻す為の処理です。

この場合Delphi4で採用されているドッカブルツールバーには
対応していません。もう少し、工夫が必要になるでしょう。

今回はIniファイルにに保存すると言う前提で解説します。

クールバー上のツールバーの数をBandCountとして

const
  BandCount=5;

後はFormのクリエイトイベントとクローズイベントに
以下の様なコードを書きます。

procedure TForm1.FormCreate(Sender: TObject);
    procedure BandPositionRead;
    var
      ini: TIniFile;
      BandIDNumber,BandWidth: array[0..BandCount-1] of Integer;
      BandBreak: array[0..BandCount-1] of Boolean;
      i: Integer;
    begin
      ini := TIniFile.Create(
      ExtractFilePath(Application.ExeName)+'BandPos.ini');
      with ini do
      try
        for i:=0 to BandCount-1 do
        begin           //Bandの位置とBreakを読込む
          BandIDNumber[i]:=
            ReadInteger('Bar','Band'+IntToStr(i)+'ID',i);
          BandWidth[i]   :=
            ReadInteger('Bar','Band'+IntToStr(i)+'Width',200);
          BandBreak[i]   :=
            ReadBool('Bar','Band'+IntToStr(i)+'Break',true);
        end;
      finally
        Free;
      end;

      CoolBar1.Bands.BeginUpdate;
      for i:=0 to BandCount-1 do
      begin            //Bandの位置とBreakを復元します。
        CoolBar1.Bands.FindItemID(BandIDNumber[i]).Index := i;
        CoolBar1.Bands[i].Break := BandBreak[i];
        CoolBar1.Bands[i].Width := BandWidth[i];
      end;
      CoolBar1.Bands.EndUpdate;
    end;

begin
  BandPositionRead;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    procedure BandPositionWrite;
    var
      ini: TIniFile;
      i: Integer;
    begin
      ini := TIniFile.Create(
        ExtractFilePath(Application.ExeName)+'BandPos.ini');
      with ini do
      try
        for i:=0 to BandCount-1 do
        begin             //Bandの位置とBreakを書きこむ
          WriteInteger('Bar','Band'+IntToStr(i)
            +'ID',CoolBar1.Bands[i].ID);
          WriteInteger('Bar','Band'+IntToStr(i)
            +'Width',CoolBar1.Bands[i].Width);
          WriteBool('Bar','Band'+IntToStr(i)
            +'Break',CoolBar1.Bands[i].Break);
        end;
      finally
        Free;
      end;
    end;

begin
  BandPositionWrite;
end;


参照: [Delphi-ML:32427] <Win95> <コンポーネント >

0090  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/03/21 osamu 編集
アプリケーション間でデータの送受信(WM_COPYDATAを使う)

BCB1で記述してます。3用に手直しがあるかもしれません。

送り側アプリ

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    HANDLE handle;
    WPARAM wParam;
    LPARAM lParam;
    char   msgbuf[]="hogehoge";
    COPYDATASTRUCT cds;
    cds.dwData = 1;
    cds.cbData = strlen(msgbuf);
    cds.lpData = (LPVOID)msgbuf;

    handle = ::FindWindow(NULL,"受けアプリ");
    wParam = (WPARAM)Application->Handle;
    lParam = (LPARAM)&cds;
    ::SendMessage(handle,WM_COPYDATA,wParam,lParam);
}
//---------------------------------------------------------------------------

受け側アプリのヘッダ

public:         // ユーザー宣言
    void __fastcall EvWmCOPYDATA( TMessage message );
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_COPYDATA,TMessage, EvWmCOPYDATA)
END_MESSAGE_MAP(TForm)

浮け側アプリのソース

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
    Form1->Caption = "受けアプリ";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::EvWmCOPYDATA( TMessage message )
{
    COPYDATASTRUCT *cds;
    char           buf[80];
    cds = (COPYDATASTRUCT *)message.LParam;
    ::ZeroMemory(buf,sizeof(buf));
    memmove(buf,cds->lpData,cds->cbData);
    ::MessageBox(0,buf,"Oh!",MB_OK);
}
参照: [builder:5252] <Windows>

0169  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
BCB で実行ファイルのサイズを小さくするには

>   後、妙にファイルサイズの大きい dll が出来てしまうのが困り
> ものかも知れません (^^;; 。

VCLを使っていない場合、VCLをリンクしないようにすればファイルサイズが小さくなります。

・BCB3でVCLをリンクしないDLLの作り方
プロジェクトメイクファイルのALLOBJ行からsysinit.objを削除し、ALLLIB行のcp32mt.libをcw32mt.libに書き換える。

マルチスレッドを使っていないなら、cw32mt.libではなく、cw32.libをリンクすると、もう少し小さくなります。

VCLをリンクしない場合、空のDLLで50kバイト程度になります。
# まだ大きいですけど...
参照: [builder:6917] <C++>

0168  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
IME 入力で読み仮名を取得する

以下のコードを含んだ関数を作成し、追跡したいところで
     Application->OnMessage = AppMessage;
と書けばよいのではないでしょうか? はずしていたらすみません。

void __fastcall TForm1::AppMessage(TMessage &Msg, bool &Handled)
{
     if (Msg.message == WM_IME_ENDCOMPOSITION)
     {
          int nRetVal;                   //APIの戻り値を格納
          HIMC hImcIMEHandle;            //IMEのコンテキストを格納
          char cBuff[256];

          hImcIMEHandle = ImmGetContext(Handle);
          //変換結果の「読み」を取得
          nRetVal = ImmGetCompositionString(hImcIMEHandle,
GCS_RESULTREADSTR,
                cBuff, sizeof(cBuff));
          cBuff[nRetVal] = '\0';
          AnsiString strTemp = cBuff;
          //IMEのコンテキストを開放する
          nRetVal = ImmReleaseContext(Handle, hImcIMEHandle);

          //cBuffに対して処理をする(入力された文字列)
     }
}

でcBuffに入力された文字が入ってきていると思います。
このコードを実行するにはimm.hが必要です。
参照: [builder:6815] <その他Windows関連> <Windows> <コンポーネント > <Standard>

0167  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
デバッグ中に関数評価の戻り値をチェックしたい

> VB では ?関数名(引数) とか打ってエンターすると値が表示されます。
> でもこればかりはインタプリタ言語の特権ですね。

Delphi でも CTRL+F7 で 関数名(引数) とやって結果が表示されます。
・・・プログラムが一時停止中でないとできませんが。
参照: [Delphi-ML:32133] <開発環境> <デバッグ>

0166  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
フォームの破棄、生成を続けて行うときの注意事項

> プログラム中でフォームを破棄し、直後に生成するとイベントが妙な順で
> 発生してしまい困っています。
>
>   Form1.Release;
>   :
>   Form1 := TForm1.Create( Application );
>   :
>   Form1.Show;
>   処理A
>
> と、こんな感じで記述すると、Form1 の Create イベントや処理 A の後に、
> Form1のDestroy イベントが走っているようなのです。

Release の後で Application.ProcessMessages してみるとどうですか。Release のヘルプを見てみてください。
Form1 がアクセスされていないことが分かっているのなら、Free でも良いです(場合によって推奨されない方法です)。
参照: [Delphi-ML:31893] <フォーム>

0165  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
DBGrid のスクロールバーを非表示に

この DBGrid のスクロールバーを力で消す方法,大変参考になりました。じっと見ているとちらりと映りますが,言われなければたぶん誰も気づかないでしょう(^^)

>   private
>     { Private 宣言 }
>     FCellBottom : Integer;
>
> procedure TForm1.DBGrid1DrawColumnCell
> (Sender: TObject; const Rect: TRect;
> DataCol: Integer; Column: TColumn; State: TGridDrawState);
> begin
>   if (FCellBottom < Rect.bottom) then FCellBottom := Rect.bottom;
> end;
>
> procedure TForm1.Query1BeforeInsert(DataSet: TDataSet);
> begin
>   Abort;
> end;
>
> procedure TForm1.Query1AfterScroll(DataSet: TDataSet);
> begin
>   ShowScrollBar(DBGrid1.Handle, SB_VERT, False);
> end;
>
> procedure TForm1.Button1Click(Sender: TObject);
> begin
>   DBGrid1.Height := FCellBottom - DBGrid1.Top + 6;
> end;
参照: [Delphi-ML:31864] <データベース> <コンポーネント > <DataControls>

0164  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
プログラムからプリンタのスプーラ表示を開く

Delphiで『スタート』→『設定』→『プリンタ』にある複数のプリンタの中から,指定された特定の名前のプリンタ(たとえばEPSON LP-8000S)などを開いてスプーラの表示にしたいのですがどうすればいいでしょうか。
参照: [Delphi-ML:31750] <印刷>

0163  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
カレントユーザのデスクトップディレクトリを得る

>実行中に現在の(ユーザの)「デスクトップ」ディレクトリのパスを取得したい
>のですが、どうすれば良いのでしょうか?

こんなの有ります。
uses ShellAPI, SHlObj, ComObj, ActiveX;
  :
  :
function GetDesktopFolder: string;

  function GetDispName(shi: IShellFolder; pidl: PItemIDList): string;
  var DispName: TStrRet;
  begin
    shi.GetDisplayNameOf(pidl, SHGDN_FORPARSING, DispName);

    if DispName.uType = STRRET_CSTR then
      Result := DispName.cStr
    else if DispName.uType = STRRET_OFFSET then
      Result := PCHAR(LongInt(pidl) + DispName.uOffset)
    else
      Result := WideCharToString(DispName.pOleStr);
  end;

  var Pidl: PItemIDList;
      DesktopFolderI: IShellFolder;

begin
  OleCheck(SHGetSpecialFolderLocation(0, CSIDL_DESKTOPDIRECTORY, Pidl));
  try
    OleCheck(SHGetDesktopFolder(DesktopFolderI));
    Result := GetDispName(DesktopFolderI, Pidl);
  finally
    CoTaskMemFree(Pidl);
  end;
end;
参照: [Delphi-ML:31606] <Windows> <ファイル>

0162  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
IniFile に書き込みを行った後にはバッファのクリアが必要

Delphi4 になって追加されたメソッドに、TIniFile.UpdateFile というのがあります。

TIniFile.UpdateFile メソッドは,バッファリングされた INI ファイルのデータをディスクにフラッシュします。

function UpdateFile; override;

説明

UpdateFile メソッドを呼び出すと,バッファリングされた,INI ファイルからの読み取りや INI ファイルへの書き込みをディスクにフラッシュできます。UpdateFile は,Windows95 では便利ですが,Windows NT では INI ファイルの読み取りや書き込みをバッファリングしないので、効果がありません。

Delphi3 以前では自分で
    WritePrivateProfileString(nil, nil, nil, PChar(FileName));
などとして IniFile のキャッシュを書き込む必要があります。

>   Ini := TIniFile.Create(Filename);
>   with Ini do begin
>     WriteString(aaaa, bbbb, cccc);
>     WriteString(dddd, eeee, ffff);
>     Free;
>     //  以下の処理で、キャッシュをフラッシュ
>     WritePrivateProfileString(nil, nil, nil, PChar(Filename));
>   end;
参照: [Delphi-ML:31512] <アプリケーション> <Windows> <バグ>

0161  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
TFileStream で標準出力に表示

> テキストファイルの入出力は TStringList でやると便利です。
> そこで、コンソールアプリケーションの標準出力でも使いたいなと、
> SaveToFile('con') を実行したところ例外で失敗しました。
> VCLソースを追いかけてみたところ、TFileStream.Create() で例外が起きていました。
>
> ところが、SaveToFile('nul') を実行したところ、なにも出力されないとはいえ
> 例外が発生することなく実行できました。
>
> 簡単に使えないのはしかたないのですが、この違いはなんでしょうね?

これ、'con'の代わりに'conout$'だと行けるみたいですね。

ところで、ちょっと横道にそれますけど、'con'だと仮にopen出来ても
リダイレクトした場合にまでコンソールに表示されて場合によっては
不便じゃありませんか?
その場合は以下のようにした方が良いかと。

uses
  windows, classes, sysutils;

var
  s : TStringList;
  hs : THandleStream;
begin
  s := TStringList.Create;
  try
    hs := THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE));
    try
      s.SetText('一行目'#10'二行目'#10'三行目'#10);
      s.SaveToStream(hs);
    finally
      hs.free;
    end;
  finally
    s.free;
  end;
end.
参照: [Delphi-ML:31323] <Windows> <ファイル>

0160  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
半角カナを確定無しで直接入力させる

> IMEの制御についてお聞きしたいのですが、例えばTEditのIMEMode
> プロパティを半角カナに設定した時、「アイウエオ(半角)」と打
> ちこんだ後リターンキーで確定をしなければなりませんが、ここで
> 入力される文字(半角カナ)を随時確定していきたいのですが、どの
> ようにすればよろしいでしょうか?

[スマートな解法]

Edit1の ImeMode プロパティを imSKata にして

uses Imm;

procedure TForm1.Edit1Enter(Sender: TObject);
var
  Imc: HIMC;
  Conversion, Sentence: DWORD;
begin
  Imc := ImmGetContext(Handle);
  ImmGetConversionStatus(Imc, Conversion, Sentence);
  ImmSetConversionStatus(Imc, Conversion, IME_SMODE_NONE);
  ImmReleaseContext(Handle, Imc);
end;

[スマートではないがいろいろ応用が利きそう]

procedure TForm1.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
type
  TLetters = set of 'A'..'z';
const
  Vowels: TLetters = ['A', 'E', 'I', 'O', 'U', 'a', 'e', 'i', 'o', 'u'];
begin
  if (Key<>VK_RETURN) and (Chr(Key) in Vowels) then
  begin
    Keybd_event(VK_RETURN,0,0,0);
    Keybd_event(VK_RETURN,0,KEYEVENTF_KEYUP,0);
  end;
end;
参照: [Delphi-ML:31097] <その他Windows関連> <Windows> <コンポーネント > <Standard>

0159  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
CreateProcess を使うときは CloseHandle で後始末

CreateProcess で Process_Infomation に返されるプロセス/スレッドハンドルは、明示的に CloseHandle でクローズしないとまずいです。

Win32 Ref. より抜粋

The created process remains in the system until all threads within the process have terminated and all handles to the process and any of its threads have been closed through calls to CloseHandle. The handles for both the process and the main thread must be closed through calls to CloseHandle. If these handles are not needed, it is best to close them immediately after the process is created.

作成されたプロセスは、プロセス内の全てのスレッドが終了し、かつ全てのプロセスとスレッドのハンドルが CloseHandle でクローズされるまでシステム内に残る。プロセスとメインスレッドのハンドルは必ず CloseHandle でクローズしなければならない。もしこれらのハンドルを使わないならばプロセスを作成した直後にクローズするのが最も良い。
参照: [Delphi-ML:30914] <Windows>

0157  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1