Delphi Tips
>> Index
● 01/22 短いファイル名を長いファイル名に変換したい(COM版)。
● 07/18 スクリーンセーバーの作り方
● 06/27 Delphi によるレジストリの操作方法
● 06/27 コントロールパネルを作る
● 06/25 自己実行形式の動画
● 06/25 ActiveX でショートカットキーが使えない
● 05/17 ActiveX 内部から自身の親ウィンドウのハンドルを得る
● 12/28 Windows2000の新APIを使った半透明ウィンドウ
● 11/30 スクリーンセーバーの名前を変更する。
● 10/07 文字列リソースの編集ツール - 文字列テーブルエディタ
● 09/27 アップリケーションにサウンドリソースを埋め込んで使いたい。
● 09/20 エクスプローラのように、アプリケーションにブラウザページをつくりたい。
● 09/20 MDI等で二重起動を防止して新しいファイルを開く
● 09/19 二重起動の判定
● 09/19 インターネット エクスプローラを起動したい/その情報を取得したい
● 09/17 起動中のブラウザからURLを取得する/ブラウザにURLをセットする方法
● 09/08 IME に未確定文字列を入力
● 09/02 Windowsの「ファイルの検索」ダイアログをプログラムから使いたい
● 08/23 プロセスの実行ファイル名を列挙する
● 08/21 クリップボードのフォーマットを知る
● 08/21 クリップボードが更新された時のイベントを取得する
● 08/19 インターネットエクスプローラのアドレス帳を呼び出す
● 05/19 独自メッセージとして自由に使える値の範囲
● 02/11 IME 入力で読み仮名を取得する
● 02/11 半角カナを確定無しで直接入力させる
● 02/11 マウスがクリックされた正確な時刻が知りたい
● 02/11 クリップボードにコピーされたファイル・ディレクトリ
● 02/11 Bitmap のパレットに使いたい色を追加する
● 02/08 コントロールパネルのスクリーンセーバの設定画面を表示させる
● 02/08 メタファイルを wmf 形式でコピーするときの注意
● 02/08 スクリーンセーバーをプログラムから停止する
● 02/08 自作コントロールで IME 入力時の変換候補をキャレット位置に表示したい
● 02/08 TDDEClientConvで最初の行しか実行されない?
● 02/08 NT のタスクマネージャにアプリケーションのアイコンが表示されない
● 02/08 DDeClientConv を使ってスタートメニューにアイコンを登録
● 02/08 Windowsの「ファイルの検索ダイアログ」を表示させる
● 02/08 自作アプリで作ったオブジェクトを他のアプリに貼り付けたい
● 02/08 Delphi3.0でDLLにバージョン情報が入らない
最終更新: 6878 日前
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> <ファイル> <PASCAL>
0345 D1D2 D3 D4 D5 D6 D7 3.195 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>
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>
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>
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] <System> <Windows> <コンポーネント >
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> <バグ>
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>
0289 D1D2 D3 D4 D5 D6 D7 3.19598作成: 1999/12/19 Atsushi Shinoda rev 1.3 B1B3B4B5 B6 B7 NT3NT42K 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>
0252 D1D2 D3 D4 D5 D6 D7 3.195 98 作成: 1999/09/09 濱野 rev 1.3 B1 B3 B4 B5 B6 B7 NT3NT4 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>
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>
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>
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] <WWW> <ShellApi> <Windows> <通信>
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>
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>
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;
便利なプロパティやメソッドがたくさんあります。
参照: <ShellApi> <Windows>
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] <WWW> <Windows> <通信>
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> <コンポーネント > <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] <ShellApi> <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>
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>
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>
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>
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>
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> <コンポーネント > <Standard>
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> <コンポーネント > <Standard>
0155 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 編集
マウスがクリックされた正確な時刻が知りたい
> 現在は、ふつうに OnMouseDown イベントから、GetCurrentTimeMillis()
> しているのですが、 Windows のイベントスプールにマウスイベントが
> たまってしまった場合、正確に マウスイベントの時間を計測しているか
> どうか、疑わしいと思います。
GetMessageTime API はいかがでしょう? Thread Queue に置かれたときの時刻が手に入るみたいです。
参照: [Delphi-ML:30236] <Windows>
0147 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 編集
クリップボードにコピーされたファイル・ディレクトリ
> クリップボードからペーストなのですが、どのようにしたらファイル名
> なのか確認できますか?その取り出し方も教えていただけないでしょうか?
プログラム上、考慮することが2点(だけかな?)、あります。
1) Explorer上で「コピー」した場合は、クリップボード内にCF_HDROPフォーマットのデータが入るようになってます。この場合、ファイルの有無はこのフォーマットの有無で判断できます。例は下のほうに置いておきます。
2) IE4が出てから、Explorerに「アドレス」なるコンボボックスが付きやがりまして、ここでディレクトリ名の「コピー」、できちまうんスよ、ったく。こいつ、テキスト形式(CF_TEXT)なんでね、これも考慮するとくりゃ、テキストがファイル名として正しいのか、白黒つけなきゃならないんスね。あ〜こりゃこりゃ。ちと面倒なコトをするハメになりそうっスよ、ったく。くぁ〜、まぃったねぇ。あっしぁ、面倒みきれませんぜ。なんせ あっし、ほれ、バカなんで。
// uses Clipbrd, ShellAPI;
procedure TForm1.Button1Click(Sender: TObject);
var
i,
n: integer;
hDrop: THandle;
szFile: array[0..MAX_PATH-1] of Char;
begin
if HasFormat(CF_HDROP) then
begin
hDrop := GetAsHandle(CF_HDROP);
n := DragQueryFile(hDrop, $FFFFFFFF, szFile, MAX_PATH); // -1かな?(64bit用)
Caption := Format('FileCount : %d', [n]);
for i := 0 to n - 1 do
begin
DragQueryFile(hDrop, i, szFile, MAX_PATH);
ListBox1.Items.Add(szFile);
end;
end;
end;
参照: [Delphi-ML:25073] <Windows> <ファイル>
0138 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 編集
Bitmap のパレットに使いたい色を追加する
>どうやれば どんなBMP にでも 画像を悪化 せずに
>自分で指定した色で文字を描画出来るようになるのでしょうか
取りあえず、こんな処理はどうでしょう?
var bm: TBitmap;
pal: TMaxLogPalette;
PalSize: WORD;
i: Integer;
const Colors: array[0..15] of TColor =
(clBlack, clMaroon, clGreen, clOlive,
clNavy, clPurple, clTeal, clSilver,
clGray, clRed, clLime, clYellow,
clBlue, clFuchsia, clAqua, clWhite); // VGA Colors
:
:
bm := TBitmap.Create;
bm.LoadFromFile('c:\windows\雲.bmp');
// パレットエントリ数を得る
GetObject(bm.Palette, 2, @PalSize);
// パレットの色を取得
GetPaletteEntries(bm.Palette, 0, PalSize-1, pal.palPalEntry);
// パレットのエントリを16色分ずらす
for i := PalSize-1 + 16 downto 16 do
if i < 256 then
pal.palPalEntry[i] := pal.palPalEntry[i-16];
// ずらして空いた部分に VGA カラーを埋め込む
for i := 0 to 15 do begin
pal.palPalEntry[i].peRed := GetRValue(Colors[i]);
pal.palPalEntry[i].peGreen := GetGValue(Colors[i]);
pal.palPalEntry[i].peBlue := GetBValue(Colors[i]);
pal.palPalEntry[i].peFlags := 0;
end;
if Palsize + 16 > 256 then
pal.palNumEntries := 256
else
pal.palNumEntries := PalSize + 16;
pal.palVersion := $0300;
// VGA カラーを足したパレットをビットマップにセット
// TBitmap は新しいパレットで色の劣化が最小限に
// なるように自動的にカラーマッチをやり直してくれます。
bm.Palette := CreatePalette(PLogPalette(@pal)^);
これで VGA Color が描けるビットマップになると思います。
ほとんど色は劣化しません。ただ、パレットの後半に重要な色が有ると多少劣化するかも。そこまでやるには VGA Color を挿入する前にパレットの色を明るさの降順に並べ替える処理を入れた方がいいと思います。
また、VGA Colors と同色の色が有った場合、その色を挿入しないようにすれば、より品質が向上すると思います。
参照: [Delphi-ML:24045] <画像> <Windows>
0120 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
コントロールパネルのスクリーンセーバの設定画面を表示させる
> 画面のプロパティの設定ウィンドウを自作のアプリから
> 起動するにはどうすれば良いのでしょう?
---------------8<---------8<-------------------------------
> できれば、プロパティ設定画面の"スクリーンセーバー"のページが
> デフォルトで表示される方法をご教示頂ければ有り難いのですが。
コマンドラインだと
Rundll32 Shell32.dll,Control_RunDLL Desk.cpl,,1
アプリからでは
::ShellExecute( Handle ,"open","Rundll.exe",
"Shell32.dll,Control_RunDLL Desk.cpl,,1",
"",SW_SHOWNORMAL);
で"スクリーンセーバー"のページが表示されます。
(コンマの前後に空白は入れないこと。)
パラメータの最後の数値が 2 なら"デザイン"、3 では"ディスプレイの詳細"が表示されます。終端の数字が 0 或いは、コンマ・数字無しだとデフォルトの"背景"です。
参照: [builder:6442] <Windows>
0130 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
メタファイルを wmf 形式でコピーするときの注意
Word 95 などのように旧メタファイル形式にしか対応しないアプリにメタファイルをコピーするときの注意点です。
Windows はクリップボードにエンハンストメタファイルが有って CF_METAFILEPICT 形式のメタファイルを要求されるとメタファイルを自動的に変換(emf->wmf)します。
ところが Windows がメタファイルをエンハンストから旧メタファイルに変換するとき境界枠の大きさやアスペクト比が失われてしまいます。
以下のように、はじめから wmf でクリップボードにコピーしておくといいようです。
procedure SaveToClipAsWMF(mf: TMetafile);
var
hMetafilePict: THandle;
pMFPict: PMetafilePict;
DC: THandle;
Length: Integer;
Bits: Pointer;
h: HMETAFILE;
begin
DC := GetDC(0);
try
Length := GetWinMetaFileBits(mf.Handle, 0, nil,
MM_ANISOTROPIC, DC);
Assert(Length > 0);
GetMem(Bits, Length);
try
GetWinMetaFileBits(mf.Handle, Length, Bits,
MM_ANISOTROPIC, DC);
h := SetMetafileBitsEx(Length, Bits);
Assert(h <> 0);
try
hMetafilePict := GlobalAlloc(GMEM_MOVEABLE or
GMEM_DDESHARE,
Length);
Assert(hMetafilePict <> 0);
try
pMFPict := GlobalLock(hMetafilePict);
pMFPict^.mm := MM_ANISOTROPIC;
pMFPict^.xExt := mf.Width;
pMfPict^.yExt := mf.Height;
pMfPict^.hMF := h;
GlobalUnlock(hMetafilePict);
Clipboard.SetAsHandle(CF_METAFILEPICT, hMetafilePict);
except
GlobalFree(hMetafilePict);
raise;
end;
except
DeleteObject(h);
raise;
end;
finally
FreeMem(Bits);
end;
finally
ReleaseDC(0, DC);
end;
end;
参照: [Delphi-ML:23065] <画像> <Windows>
0072 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
スクリーンセーバーをプログラムから停止する
API の SetCursorPos() で強制的にマウスの位置を動かしてやることでスクリーンセーバを止めることができます。
95ではちょっと動かしてやれば止まりますが、NT4ではある程度以上大きく動かさないと止まってくれないそうです。
最近の報告では、この方法でNT4のスクリーンセーバを停止すると、その後いつまで経ってもスクリーンセーバが起動してくれないとのことです。
ちなみに、スクリーンセーバを開始させるには、uses 節に Messages を加えて、
SendMessage(Handle, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
でできます。
参照: [Delphi-ML:5062] [Delphi-ML:17211] [Delphi-ML:19836] <Windows>
0083 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
自作コントロールで IME 入力時の変換候補をキャレット位置に表示したい
IMEが編集を開始する直前にWM_IMESTARTCOMPOSITION というメッセージを送って来るので、そのメッセージを捕らえて設定してやります。
class TCustom : public TCustomControl
{
・・・・・・・・・・・・
void __fastcall IMEStart(TMessage& Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER( WM_IME_STARTCOMPOSITION ,TMessage,IMEStart)
END_MESSAGE_MAP(TCustomControl)
};
void __fastcall TCustom::IMEStart(TMessage& Message)
{
// IMEの位置をキャレットのポジションに設定
COMPOSITIONFORM CompForm;
POINT pt;
LOGFONT lf;
HIMC hImc=ImmGetContext(Handle);
//キャンバスのフォントと同じに設定する
GetObject(Canvas->Font->Handle,sizeof(LOGFONT),&lf);
ImmSetCompositionFont(hImc,&lf);
//キャレットのポジションに設定する
ImmGetCompositionWindow(hImc,&CompForm);
CompForm.dwStyle=CFS_POINT;
GetCaretPos(&pt);
CompForm.ptCurrentPos=pt;
ImmSetCompositionWindow(hImc,&CompForm);
ImmReleaseContext(Handle, hImc);
// その他の処理
・・・・・・・・・・・・・
}
参照: [builder:5269] <コンポーネント開発> <Windows> <コンポーネント > <Standard>
0084 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
TDDEClientConvで最初の行しか実行されない?
TDDEClientConv を使って、ステップ実行を行うとちゃんとマクロは実行されるのですが、そのまま実行すると、最初のコマンドのみ実行してその後が実行されません。
これは2.0からのバグです。3.0/3.1用のパッチを当てると直ると思います。
http://www.dataweb.nl/~r.p.sterkenburg/bugsall.htmが詳しいです。
日本語版でも通用する個所が多いです。参考にしてみて下さい。
1)必要なったらTDDEClientConvをCreate
2)マクロを実行
3)用が済んだらFree
で逃げられます。
参照: [Delphi-ML:19657] <System> <ShellApi> <Windows> <バグ> <コンポーネント >
0103 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
NT のタスクマネージャにアプリケーションのアイコンが表示されない
Delphi で作られるソフトすべてでこの問題が発生します。ちなみに、Delphi 自身も同じ問題を抱えています。
アプリケーションのクラスアイコンをセットしたら表示されるようになると思います。
プロジェクトソースかメインフォームの OnCreate イベントで、
SetClassLong(Application.Handle,
GCL_HICON,
Application.Icon.Handle);
を実行して下さい。
参照: [Delphi-ML:21168] <アプリケーション> <Windows> <バグ> <アイコン>
0105 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
DDeClientConv を使ってスタートメニューにアイコンを登録
3.1 のプログラムマネージャのときと同じですね。
DDEClientConv をフォームに置いて以下のようにします。
var strGroup:String;
strExeName:String;
strPrgName:String;
Temp:String;
begin
strGroup := 'グループ名';
strPrgName := 'ソフト名';
strExeName := Application.ExeName;
if not DDEClientConv1.SetLink('PROGMAN','PROGMAN') then begin
ShowMessage('ショートカットの制作に失敗しました。');
end else try
{グループの作成}
Temp := '[CreateGroup(' + strGroup + ')]';
DDEClientConv1.ExecuteMacro(PChar(Temp),False);
{グループの表示}
Temp := '[ShowGroup(' + strGroup + ',1)]';
DDEClientConv1.ExecuteMacro(PChar(Temp),False);
{アイテムの作成}
Temp := '[AddItem("' + strExeName + '","' + strPrgName + '")]';
DDEClientConv1.ExecuteMacro(PChar(Temp),False);
ShowMessage('ショートカットを作成しました。');
finally
DDEClientConv1.CloseLink;
end;
end;
参照: [Delphi-ML:21012] <ShellApi> <Windows> <スタートメニュー> <配布>
0028 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
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
です。
参照: [Delphi-ML:20377] <ShellApi> <Windows> <ダイアログ>
0037 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
自作アプリで作ったオブジェクトを他のアプリに貼り付けたい
自作アプリを OLE サーバにして他のアプリに貼り付けられるデータを作成する方法が Inside Windows の、98年4月号「Delphi の神託」に出ているそうです。
参照: [Delphi-ML:18525] <ShellApi> <Windows>
0007 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
Delphi3.0でDLLにバージョン情報が入らない
Delphi3.0で、「新規作成」から DLL を作ると、「バージョン情報を含める」のオプションを指定しても、効果が無い。
これは、.dpr ファイルに {$R*.RES} の一文が入らないために、リソースファイルはできるのに、リンクされないためだ。
uses節の後ろに手動で{$R*.RES} を書いてやればよい。
参照: [Delphi-ML:19012] <アプリケーション> <開発環境> <Windows> <バグ> <DLL>
[新規作成] [最新の情報に更新]
How To
Lounge
KeyWords
Osamu Takeuchi osamu@big.or.jp
Tips
Delphi
Home