Delphi Tips
>> Index
● 01/22 短いファイル名を長いファイル名に変換したい(COM版)。
● 12/31 リンクファイルから参照先のファイル名を得る
● 03/04 フォームの最小化時のアニメーション効果を出す(BCB)
● 11/21 子プロセス(DOS)の標準出力をパイプする
● 07/18 スクリーンセーバーの作り方
● 06/27 Delphi によるレジストリの操作方法
● 06/27 システムアイコンをリフレッシュする
● 06/27 コントロールパネルを作る
● 06/27 全てのウィンドウを最小化する
● 06/25 自己実行形式の動画
● 06/25 ActiveX でショートカットキーが使えない
● 06/25 FindFirst でアイコンを変更したディレクトリを検索できない
● 06/25 FindFirst による4文字以上の拡張子の判別
● 05/17 ActiveX 内部から自身の親ウィンドウのハンドルを得る
● 08/25 ComCtl32.DLL を配布するには
● 12/28 Windows2000の新APIを使った半透明ウィンドウ
● 11/30 スクリーンセーバーの名前を変更する。
● 11/16 INI ファイルを扱うもう1つのクラス
● 10/07 文字列リソースの編集ツール - 文字列テーブルエディタ
● 09/30 アクティブデスクトップを使って壁紙を変更
● 09/27 デスクトップにあるアイコンの数と位置を知りたい。
● 09/27 アップリケーションにサウンドリソースを埋め込んで使いたい。
● 09/27 エクスプローラからファイルをドラッグ&ドロップする
● 09/27 アプリケーションを常駐させてタスクトレイに登録したい
● 09/26 ファイルを削除してゴミ箱に移動させたい。
● 09/24 Windows 特殊フォルダの Class ID List
● 09/23 シェルのデスクトップやマイコンピュータをプログラムから開きたい。
● 09/22 長いファイル名を短いファイル名に変換したい
● 09/20 エクスプローラのように、アプリケーションにブラウザページをつくりたい。
● 09/20 MDI等で二重起動を防止して新しいファイルを開く
● 09/19 二重起動の判定
● 09/19 インターネット エクスプローラを起動したい/その情報を取得したい
● 09/17 起動中のブラウザからURLを取得する/ブラウザにURLをセットする方法
● 09/08 IME に未確定文字列を入力
● 09/08 フォルダのタイムスタンプを変更する
● 09/06 メインフォーム以外のフォームをタスクバーに入れたい。
● 09/06 APPのフォームを最小化して起動したい
● 09/02 Windowsの「ファイルの検索」ダイアログをプログラムから使いたい
● 09/01 フォームの最小化、最大化をアニメーションでやりたい。(DELPHI)
● 08/30 メインフォーム以外のフォームを最小化した時もAPP全体を最小化したい
● 08/26 ダイヤラを呼び出す。(TAPI32.DLLの使用)
● 08/26 他のアプリの起動パスを取得する
● 08/26 セルのテキストをドラッグイメ−ジにしてグリッド(TStringGrid)でドラッグ&ドロップを行う
● 08/23 デスクトップのウィンドウのタイトルとハンドルを取得する
● 08/23 プロセスの実行ファイル名を列挙する
● 08/23 Win95/98で、ウィンドゥハンドルから、実行アプリ名を知る
● 08/23 WinNT でウィンドウハンドルから実行アプリ名を知る
● 08/21 クリップボードのフォーマットを知る
● 08/21 クリップボードが更新された時のイベントを取得する
● 08/19 インターネットエクスプローラのアドレス帳を呼び出す
● 07/28 HTML-Help を作りたい
● 07/07 CapsLock の状態を変更する
● 05/19 独自メッセージとして自由に使える値の範囲
● 05/19 「送る」の 516 文字制限について
● 03/21 アプリケーション間でデータの送受信(WM_COPYDATAを使う)
● 02/11 IME 入力で読み仮名を取得する
● 02/11 カレントユーザのデスクトップディレクトリを得る
● 02/11 IniFile に書き込みを行った後にはバッファのクリアが必要
● 02/11 TFileStream で標準出力に表示
● 02/11 半角カナを確定無しで直接入力させる
● 02/11 CreateProcess を使うときは CloseHandle で後始末
● 02/11 ディスパッチインターフェイスとデュアルインターフェイスについて
● 02/11 マウスがクリックされた正確な時刻が知りたい
● 02/11 エクスプローラで使われるアイコンを取得・変更する
● 02/11 クリップボードにコピーされたファイル・ディレクトリ
● 02/11 リムーバブルドライブの種類を判別する
● 02/11 Bitmap のパレットに使いたい色を追加する
● 02/08 Delphi で DOS のアプリを書く方法
● 02/08 Delphi/CBuilder で作った DLL から VB に文字列を返す
● 02/08 コントロールパネルのスクリーンセーバの設定画面を表示させる
● 02/08 Windows95 のみを再起動する
● 02/08 他プロセスの Window を GUI で選ばせたい
● 02/08 実行終了後、自分自身(実行ファイル)を削除したい
● 02/08 メタファイルを wmf 形式でコピーするときの注意
● 02/08 デスクトップフォルダのパスを得る
● 02/08 CD-DA のデータを Wav ファイルに落としたい
● 02/08 複数プログラムから同一内容のメモリを参照/更新する
● 02/08 プログラムからWindowsのスタートメニューを表示する
● 02/08 SetWindowsExt/SetViewportExtを使うときの注意点
● 02/08 スクリーンセーバーをプログラムから停止する
● 02/08 Delphiアプリをマウスのホイールに対応させたい
● 02/08 ヘルプ作成用のホットスポットエディタ(SHED.EXE)の入手方法
● 02/08 「システムエラー 読み出せません ドライブ X:」ダイアログを回避する
● 02/08 自作コントロールで IME 入力時の変換候補をキャレット位置に表示したい
● 02/08 TDDEClientConvで最初の行しか実行されない?
● 02/08 起動したアプリケーションの終了待ち
● 02/08 NT のタスクマネージャにアプリケーションのアイコンが表示されない
● 02/08 DDeClientConv を使ってスタートメニューにアイコンを登録
● 02/08 スタートメニューを任意の位置にポップアップさせる
● 02/08 Windowsの「ファイルの検索ダイアログ」を表示させる
● 02/08 自作アプリで作ったオブジェクトを他のアプリに貼り付けたい
● 02/08 TrueTypeフォントからベクタ情報を得る
● 02/08 32bitアプリから16bit DLLを呼び出す
● 02/08 Delphi3.0でDLLにバージョン情報が入らない
● 02/08 Delphi 1.0 (16bit)で、物理メモリアドレスに直接アクセスする
● 02/08 NTで他のアプリが開いているファイルを知る
最終更新: 6882 日前
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>
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> <ファイル>
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] <フォーム>
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]
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関連>
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
参照: <バグ> <アイコン>
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関連>
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キーで
『全ウィンドウの最小化』←→『元に戻す-すべて最小化』
を切りかえられます。
参照:
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> <コンポーネント >
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関連> <バグ>
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] <ファイル>
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] <ファイル>
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関連>
0158 D1D2 D3 D4 D5 D6 D7 3.195 98 作成: 1999/02/11 osamu rev 1.2 B1 B3 B4 B5 B6 B7 NT3NT4 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] <配布>
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関連>
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 ですので、この制限は問題にならないでしょう。
参照:
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関連>
0278 D1 D2 D3 D4 D5 D6 D7 3.195 98 作成: 1999/09/30 篠田 rev 1.2 B1 B3 B4 B5 B6 B7 NT3NT4 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] <デスクトップ>
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] <アイコン>
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関連> <開発環境>
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> <ファイル>
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> <フォーム> <コンポーネント >
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> <ファイル>
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] <ファイル>
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]
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] <ファイル>
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> <通信>
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;
便利なプロパティやメソッドがたくさんあります。
参照: <その他Windows関連> <ShellApi>
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> <通信>
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>
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] <ファイル>
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] <タスクバー> <フォーム>
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] <タスクバー> <フォーム>
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> <ダイアログ>
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] <フォーム>
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] <フォーム>
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>
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] <アプリケーション> <ファイル>
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] <コンポーネント > <その他コンポーネント関連>
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] <デスクトップ>
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関連>
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]
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]
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関連>
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] <ヘルプ>
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]
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関連>
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]
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]
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>
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] <ファイル>
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] <アプリケーション> <バグ>
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] <ファイル>
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>
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]
0157 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-ML:30627] [Delphi-ML:30649] [Delphi-ML:30684] <PASCAL>
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関連>
0153 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 編集
エクスプローラで使われるアイコンを取得・変更する
> Windowsでディレクトリなどに使われるアイコンを変更するなどの
> プログラムもあるみたいですが、そういったシステムで使われる
> アイコンを取得したいと思っています。
レジストリの HKEY_LOCAL_MACHINE の下に
Software\Microsoft\Windows\CurrentVersion\explorer\Shell Icons
というキーがあり、ここに番号の文字列を作り、アイコンのファイル名とインデックスを設定することによりアイコンが設定可能です。
参照: [Delphi-ML:26403] <アイコン> <ファイル>
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関連> <ファイル>
0140 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-ML:24577] <ファイル>
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関連> <画像>
0117 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 編集
Delphi で DOS のアプリを書く方法
[A1]
http://www.geocities.com/SiliconValley/Park/4493/
にある 32 ビット DOS エクステンダで Win32 Console 実行ファイルをMS-DOS 実行ファイルに変換できます。
どの API が使用できるのかは未確認ですが・・・・
[A2]
Delphi1の場合、DOS用Turbo Pascalの最終バージョンであるBorland Pascal 7.0付属のライブラリソースを元にしてDOS用ライブラリをでっちあげ、かつコマンドラインコンパイラでオプション-cdをつけてコンパイルすれば、DOS プログラム用のコンパイラとして動かすことができます。
ライブラリの構築にBP7が必要なので、「Delphiだけで」というわけにはいきませんが、一度ライブラリを作ってしまえばOKということです。
ただ、このライブラリでっち上げが「すげー手間」なのでお勧めしません。
昔はCompuServeにライブラリソースの差分が上がってたんですけど、さすがにもう消えているはずです。
現実的には、どうせライブラリ作成過程で必要になるBP7を素直に使うのが正常な判断というものでしょう。
#私?BP7も持ってたから試しましたとも、D1日本語版すら出てない頃に(^^;
参照: [Delphi-ML:22238] [Delphi-ML:22240] <開発環境>
0118 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 編集
Delphi/CBuilder で作った DLL から VB に文字列を返す
> VB(VBA含む)は、ポインタが使えませんので、DLLで文字列を返す方法
> が知りたいです。 だれか、ご存知のかたおしえてください。
一番手軽なのは,SysAllocStringByteLen で文字列を確保して,そのまま返す方法です.
例)
return SysAllocStringByteLen( "Hello", 5 );
内容は ShiftJIS で Ok.
ここで確保したメモリーは VB 側で開放されるそうです.
参照: [builder:6429] <DLL> <メモリ>
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関連>
0121 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 編集
Windows95 のみを再起動する
> Windowsの再起動ってどうやればいいんでしょうか?
> マシンごと再起動ではなく、Windowsのみの再起動を
> したいのですが・・・。
> Windowsの終了->コンピューターを再起動する
> をシフトキーを押しながらしたときの動作がしたいのです。
これ、16BitAPIコードじゃないとできないらしいです。
だからWin95では使えても、NTでは無理なのでは?
と思いますが……どうなんでしょう?
ちょっと裏技として、RUNDLLを利用する手段があります。
RUNDLL.EXE に
user.exe,exitwindowsexec
というオプションをつけて起動させてみてください。
ショートカットでは正常動作したので、多分使えると思います。
プログラムでは95でもNTでも試していませんが……。
できなかったらごめんなさい。
ではまた。
参照: [builder:6513]
0125 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 編集
他プロセスの Window を GUI で選ばせたい
TImage を基本として作ったVCLを紹介します。
当該コントロール上でマウスの左ボタンを押下し、そのまま目的のウィンドウ上までドラッグ、ボタンを離す事によって、ウィンドウハンドルを得ることができます。
ThWndCapture Ver. 1.00
http://w3ma.kcom.ne.jp/~sammy/
レポートお待ちしております。
参照: [Delphi-ML:22176]
0128 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 編集
実行終了後、自分自身(実行ファイル)を削除したい
> 実行終了後、自分自身を削除したいのですが、
> なにか良い方法はありませんか?
こんなのはどうでしょう?
MoveFileEx(lpszExisting,NULL,MOVEFILE_DELAY_UNTIL_REBOOT);
NTではこれで再起動時に削除されます。
Windows95 ではこのAPIはサポートされないので
以下の方法をとるように、MoveFileEx のヘルプで示されています。
Windows 95: The MoveFileEx function is not supported on Windows 95.
To rename or delete a file at reboot on a Windows 95 system, use the following procedure.
・To Rename or Delete a File on Windows 95
Check for the existence of the WININIT.INI file in the Windows directory. If WININIT.INI exists, open it and add new entries to the existing [rename] section. If the file does not exist, create the file and create a [rename] section. Add lines of the following format to the [rename] section:
DestinationFileName=SourceFileName
Both DestinationFileName and SourceFileName must be short filenames. To delete a file, use NUL as the value for DestinationFileName.
The system processes WININIT.INI during system boot. After WININIT.INI has been processed, the system names it WININIT.BAK.
ちなみに、いずれも再起動が必要です。また私自身は、Windows95 で上記の方法は試したことがありませんが、WindowsNTで自分自身を消去するのは確認済みです。
参照: [Delphi-ML:22795]
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関連> <画像>
0052 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 編集
デスクトップフォルダのパスを得る
uses Shellapi, ShlObj, ActiveX, ComObj;
function GetDesktop: string;
var pidl: PItemIDList;
buf : array [0..MAX_PATH] of Char;
m : IMalloc;
const DesktopID = CSIDL_DESKTOPDIRECTORY;
begin
OleCheck(CoGetMalloc(1, m));
OleCheck(SHGetSpecialFolderLocation(0, DesktopID, pidl));
try
Assert(SHGetPathFromIDList(pidl, buf));
Result := buf;
finally
m.Free(pidl);
end;
end;
ネットワークコンピュータ、マイコンピュータは仮想フォルダなので
パスは有りません。マイコンピュータの定義は CSIDL_DRIVES です。
参照: [Delphi-ML:19392]
0060 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 編集
CD-DA のデータを Wav ファイルに落としたい
ここにあるcd2wavが大いに参考になるでしょう。ソース付きです。
http://www2s.biglobe.ne.jp/~elfin/
参照: [builder:4912]
0061 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 編集
複数プログラムから同一内容のメモリを参照/更新する
Win32用に、中村@NECさんが、File Mapping を利用して実現したクラスを [Delphi-ML:19603] で紹介されています。
ただ、添付ファイルは Web からは取れません。
どこか他からダウンロードしないと。。。
参照: [Delphi-ML:19603] <ファイル> <メモリ>
0062 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のスタートメニューを表示する
以下の方法でメニューを出すことができるようです。
HWND taskbar=FindWindow("Shell_TrayWnd","");
if(taskbar) PostMessage(taskbar,WM_USER+260,0,0);
参照: [builder:4947] <メニュー>
0064 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 編集
SetWindowsExt/SetViewportExtを使うときの注意点
TCanvas.Handle に対してこれらの関数を呼んで使う際の注意点。
(1) Font.Height と Font.Size の関係はマッピングモードが MM_TEXT
で有ることを仮定しているので SetMapMode API でマッピングモードを
変えた場合は Font.Height のみを使った方が良いでしょう。
(2) API の効果の寿命はイベントハンドラ毎です。
引き継がれません。
参照: [Delphi-ML:19671] <描画>
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関連>
0078 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 編集
Delphiアプリをマウスのホイールに対応させたい
TMouseWheel コンポーネントってのがあります。
これが、参考になるのではないでしょうか。
以下、readme.txtより抜粋
---------ここから
(概要)
このコンポーネントはフォームに貼り付ける事によってそのフォー
ムに貼り付けてある全てのコントロールに対してホイールによるス
クロールを可能にする事ができます。
---------ここまで
Delphi広場にありました。ファイル名:mwheel.exe
http://www.sakaki.keiaikai.or.jp/
参照: [Delphi-ML:20365]
0080 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 編集
ヘルプ作成用のホットスポットエディタ(SHED.EXE)の入手方法
以下のURLよりダウンロードが可能です。
ftp://ftp.microsoft.com/Softlib/MSLFILES/SHED.EXE
参照: [Delphi-ML:20436] <開発環境> <ヘルプ>
0081 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 編集
「システムエラー 読み出せません ドライブ X:」ダイアログを回避する
Q:
Delphiで、フロッピーのようなリムーバブルメディアがちゃんとセットされているかを、「静かに」知る方法はないものでしょうか。FileExists関数を使っても、フロッピーの入っていないドライブを見に行くと、システムエラーダイアログが表示されてしまいます。
A:
Windows API の SetErrorMode を使用すればいいでしょう。
ここ一年使っているドライブのチェックルーチンはこんな感じです。
# WIN32の部分はまだあまり実績がないですけど...
function IsDriveReady(drive : char) : boolean;
var
oldmode : word;
searchrec : tSearchRec;
begin
drive := upcase(drive);
oldmode := SetErrorMode(SEM_FAILCRITICALERRORS); (* ここと *)
result := DiskSize(ord(drive)-$40) <> -1;
{$IFDEF WIN32}
if result and (GetDriveType(pchar(drive+':\')) in [DRIVE_REMOTE, DRIVE_CDROM]) then begin
{$ELSE}
if result and (GetDriveType(ord(drive)-$41) = DRIVE_REMOTE) then begin
{$ENDIF}
result := FindFirst(drive+':\*.*',$3f, searchrec) = 0;
FindClose(searchrec);
end;
SetErrorMode(oldmode); (* ここね *)
end;
http://slis.flet.mita.keio.ac.jp/~anakata/delphi/myfaq.html#Q12
にも載せてあります。
参照: [Delphi-ML:184] <ダイアログ>
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] <その他Windows関連> <System> <ShellApi> <バグ> <コンポーネント >
0097 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 編集
起動したアプリケーションの終了待ち
WaitForSingleObject という API を使います。
これをキーに過去ログを検索すると、コード例も見つかります。
http://www2.big.or.jp/~osamu/Delphi/search.cgi?key1=WaitForSingleObject
参照:
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] <その他Windows関連> <ShellApi> <スタートメニュー> <配布>
0112 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 編集
スタートメニューを任意の位置にポップアップさせる
スタートメニューのポップアップは、
procedure PopupStartMenu;
var hTaskBar: Integer;
begin
hTaskBar:= FindWindow(PChar('Shell_TrayWnd'), nil);
SetForegroundWindow(hTaskBar);
PostMessage(hTaskBar, WM_USER + $0104, 0, 0);
end;
でOK。
表示されたメニューを MoveWindow で強制的に動かすには、
procedure MoveStartMenu(Point: TPoint);
var hStartMenu: Integer;
OldRect: TRect;
begin
hStartMenu:=FindWindow('#32768',nil);
GetWindowRect(hStartMenu, OldRect);
MoveWindow(hStartMenu,
Point.X, Point.Y,
OldRect.Right-OldRect.Left, OldRect.Bottom-OldRect.Top,
True);
end;
詳しくはスレッドを追って下さい。
参照: [Delphi-ML:21886] <スタートメニュー>
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] <その他Windows関連> <ShellApi> <ダイアログ>
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] <その他Windows関連> <ShellApi>
0048 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 編集
TrueTypeフォントからベクタ情報を得る
中村@NECさんのサンプルコードが[Delphi-ML:6963]にあります。
参照: [Delphi-ML:06963] <その他コンポーネント関連> <コンポーネント >
0010 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 編集
32bitアプリから16bit DLLを呼び出す
英語ですが、
http://www.itecuk.com/delmag/thunk95.htm
に詳しく説明があり、サンプルソースも落としてこれます。
ただし、Delphi Magagine で紹介されている方法を解読するには遙かなる時間がかかるでしょう。まあ、これは参考文献にとどめて置いて、やはり実践的なサンプルコードが必要かと思います。
DSP(http://ring.asahi-net.or.jp/archives/pc/delphi/)の、ThunkDownを使ったサンプル「freres.zip」と「zthunk.zip」や、ひきさんの「TExitWinコンポーネント」(http://www.vector.co.jp/authors/VA009712/take/)が参考になると思います。
また、UserリソースやGDIリソースを得るにはGetFreeSystemResourcesを使うのですが、これは16ビットAPIなため、ThunkDownが必要です。
サンプルまでひきさんが書いてくれました。
#でも Web からは添付文書取れないんだよね。。。(^^;;;
参照: [Delphi-ML:18742] <DLL>
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>
0000 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 編集
Delphi 1.0 (16bit)で、物理メモリアドレスに直接アクセスする
procedure TForm1.Button1Click(Sender: TObject);
var
TestSelector: word; {新しいセレクタ}
P : ^byte; {メモリマップアクセス用ポインタ}
begin
TestSelector := AllocSelector(DSeg); {新しいセレクタを作成}
SetSelectorBase(TestSelector, $C8000);{ベースアドレスを$C8000に設定}
SetSelectorLimit(TestSelector, $2000);{8KB($2000)確保}
P := Ptr(TestSelector, $0100); {$0100 アドレスにポインタセット}
P^ := $00; {$C8000+$0100=$C8100に$00を書込}
FreeSelector(TestSelector); {セレクタの解放}
end;
参照: [Delphi-ML:18551] <メモリ>
0002 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で他のアプリが開いているファイルを知る
WindowsNT上ならば、
http://www.ntinternals.com/
に NTFilemon があります。
ソースが公開されているので、参考になるかもしれません。
参照: [Delphi-ML:18558] <ファイル>
[新規作成] [最新の情報に更新]
How To
Lounge
KeyWords
Osamu Takeuchi osamu@big.or.jp
Tips
Delphi
Home