かなりローテクですが、よく使うものを初心者向けとして書いています。
みなさんのお役に立てるかどうか(^^;;)
もっともっとも〜〜っと高等な技術をお求めの方は、Delphi Acid Floorへどうぞ(^^;;)
ExtractFileDirを使います。
例
Var DirName:String;
Begin
DirName := ExtractFileDir('d:\temp\test\test.txt');
End;
とするとDirNameには、d:\temp\test\が入ります。
ExtractFilePathもありますが、ExtractFileDirはマルチバイト文字にも対応しているので
日本語を使ったディレクトリを扱う場合などは、こちらの方が良いでしょう。
USE節にshellapiを追加します。
private宣言の中に以下を追加します。
procedure WMDropFiles(var Msg:TWMDropFiles);message WM_dropfiles;
その後
implementation
{$R *.DFM}
などの後に以下の文を追加します。
procedure tform1.WMDropFiles(var Msg:TWMDropFiles);
var fname:array[0..255]of char;
myfilename:string;
begin
dragQueryfile(msg.drop,0,fname,256);//fnameにファイル名を入れる
dragfinish(msg.drop);
myfilename:=strpas(fname); //string型の変数へ代入
end;
あとフォームのonshowイベントの中などに
dragacceptfiles(handle,true);
も忘れずに追加しましょう。
何かのプログラムを実行するときに付けて、そのプログラムの動作を変えるものです。
例えばスクリーンセーバーなどでは、/Aはパスワードの変更、/Pはプレビュー、/Cは設定ダイアログの表示
などとなります。
DelphiではParamcountでコマンドラインパラメータの数を、
Paramstr()で、()内の数字番目のパラーメーターを文字で得られます。
ちなみに0番目はプログラム自身の名前が入っています。
これも結局は上記のコマンドラインオプションと同じものです。
ドラッグアンドドロップといっても、見かけ上はアイコンにアイコンを落としているようには見えますが、
実際での動作はms-dos時代のプログラムの実行方法と同じことをやっています。
これをMS-DOSプロンプト上で同様の操作をするとこうなります。
c:¥>なんとか.exe c:¥test.txt c:¥abc.dat
のようにプログラム本体がなんとか.exeで、それにD&Dされたのが、c:¥test.txtとc:¥abc.datです。
「送る」でプログラムを実行した場合も同様です。
この時のコマンドライン引数は、
0番・・・なんとか.exe(プログラム自身の名前)
1番・・・c:¥test.txt
2番・・・c:¥abc.dat
となります。
実際の使い方です。
フォームにmemoコンポを置き、下の文をFormのOnShowイベントのプロシージャ内に書いてください。
コンパイル後そのプログラムにD&Dしてみてください。
if paramcount >=1 then //何か引数があるか確認
begin
for i:=1 to paramcount do //その数だけの
memo1.lines.add(paramstr(i));
end;
ファイルサイズを取得して、結果を文字で返す関数です。
filesizeという関数もあるのですが、ヘルプを見ると。。。
function FileSize(var F): Integer;
説明
FileSize を呼び出すと,ファイルのサイズがわかります。
FileSizeを使うには,ファイルを開いておかなくてはなりません。
ファイルが空の場合,FileSize(F) は 0 を返します。F はファイル変数です。
注意
FileSize はテキストファイルに対しては使えません。
などなど面倒なので、findfirst関数を利用してファイルサイズを取得します。
Fnameにはフルパスでファイル名を指定します。
function GetfileSize(Fname:string):Cardinal;
var sr:tsearchrec;
begin
if findfirst(Fname,faanyfile,sr)=0 then
begin
result := sr.size;
findclose(sr);
end else result:=0;
end;
上からの続きです。
iにはファイルサイズが入っているとします。
FsizeはString型とします。
そしてiをKbyteまたはMbyteで割り、結果が実数になるのでFormatFloatを使います。
Fsize := FormatFloat( '#,##0.00MB',i/1048576)//
メガバイト単位
Fsize := FormatFloat( '#,##kB',i/1024); // キロバイト単位
Fsize := FormatFloat( '#,##byte',i); // バイト単位
ドラッグアンドドロップで受けたファイル名を取得でも使っていますが、
StrPas関数を使います。
Var S:string;
Begin
s := strpas(charの配列変数);
End;
Win32APIの関数へ文字列を渡す場合は、C言語ベースなので互換性は無く、
DelphiにあるString型の文字変数を直接渡すことはできません。
そこでPchar(string型の変数)と書いて文字列へのポインターを渡します。
またWin32api関数内で、' 'で囲んで直接文字を渡してもOKです。
他にもchrの配列を渡すことも可能です。
ただし文字の長さは255文字までです。
これらのことは、Unlha32.dllなどのDLLへ文字を渡すときも同様です。
DLLを使うときには静的リンクと動的リンクの方法があります。
静的リンク
これは使いたいDLLが絶対存在すると仮定した使い方です。
DLL の手続きや関数を使うには,external 宣言を使って手続きや関数をインポートします。
Unlha32.dllを使った例をあげます。Unlha32.dllのバージョン情報を取得する関数です。
Unlha32.dll付属のAPI.TXTには
WORD WINAPI UnlhaGetVersion(VOID)とあります。
UnlhaGetVersion関数は、引数無し(VOID)で戻り値はWord型(0〜255)の数値です。
external 宣言は Unlha32.dll という
DLLから UnlhaGetVersion という関数を読み込みます。
ここで気をつけなければならないのはname以降の関数名は1字一句間違えてはいけません。
大文字と小文字も区別されます
例
新規フォームをにボタンをひとつ貼り付けて、そのイベントハンドラに記述します。
赤い部分を自前で書きます。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes,Graphics, Controls,
Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
function GetVersion: Word;
stdcall; external 'Unlha32.dll' name 'UnlhaGetVersion';
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
showmessage(floattostr(GetVersion/100));
end;
end.
これをそのまま書いて実行すると、Unlha32.dllのバージョンが表示されます。
ただしUnlha32.dllが存在し、かつパスの通った位置にあればの話ですが。。。
もしどちらかがかけていると、エラーが出てどっかーん!!です(^^;;)
この方法は簡便ですが、お勧めできません。
面倒でも次の動的リンクを使って書きましょう。
動的リンク
これはいったんLoadLibrary関数を使ってDLLがあるかないか確認してから使います。
LoadLibraryが0以外の有効なハンドルを返したなら、目的のDLLは存在し
メモリーに読み込まれます。
その後GetProcAddress関数を使い、DLL内の目的の関数のアドレスを取得し、
それを使って関数を実行します。
例
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes,Graphics, Controls,
Forms, Dialogs,
StdCtrls;
type
TGerVersion= function : word;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
GerVersion : TGerVersion;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var DLLHandle:THandle;
Version : string;
begin
DLLHandle := LoadLibrary('Unlha32.dll'); //DLLをロードしてハンドルを取得
if DLLHandle <> 0 then
begin
@GerVersion := GetProcAddress(DLLHandle, 'UnlhaGetVersion'); //DLLのハンドルを使って
if @GerVersion <> nil then //関数のアドレスを取得
begin
Version := floattostr(GerVersion / 100);
end else Version :='関数アドレスの取得に失敗しました';
FreeLibrary(DLLHandle); //使ったら必ずDLLを開放する
end else Version :='DLLがありません';
showmessage(Version);
end;
end.
どうでしょうか?
ちょっと面倒ですが、こちらの使い方のほうが安全なので
普通はこちらを使うほうがよいでしょう。
通常Windowsでは、拡張子を見てファイルの判断をしますが、これが当てにならない場合が多々あります。
こんな時は直接ファイルを読み込んで、そのファイルヘッダから何のファイルか判断します。
といってもそれぞれファイルフォーマットが違うので、それなりに調べなければなりませんが
よくあるもので
Bitmap 先頭の2バイトがBMになっている
EXE 〃 がMZ
ZIP 〃 がPK
などがあります。
興味のある方は、The Programmer's File Format Collectionへ行ってみてください。
大抵の資料は揃っています。
例文
Procedure CheckHeader(Const FileName:string);
Var TF:TfileStream;
Buf:array[0..2]of char;
begin
TF:=TFileStream.create(FileName,fmOpenRead);
TF.Position := 0;
TF.Read(Buf,2);
If (buf[0]='B')and(buf[1]='M')
then showmessage('Bitmap');
If (buf[0]='M')and(buf[1]='Z')
then showmessage('Exe');
If (buf[0]='P')and(buf[1]='K')
then showmessage('Zip');
TF.Free;
end;
いやいや、最近これにはまってネット上のいろいろな資料を漁りました。
しかしながらDelphi関連は少なくVC++ばかりで、少しCも読めるようになりました(^^;;)
IMEを制御するときのミソというか、直接IMEのハンドルを取得してそれに対して
メッセージを投げるか、APIを実行するのかと思ったら違うんですね〜。
IMEは「文字入力可能なコントロールに対して個別にハンドルを割り当てる」らしいです。
ということで、ここから書くサンプルでは、TWinControlから派生したコンポのハンドルを
使用するものとして書いていきます。
自分が試したときはTeditを使いました。
またUSE節には、IMMを追加しておきます。
IME ウィンドウ(ツールバー)の表示・非表示
procedure ShowIme(const winctr :TWinControl;const valeu:boolean);
var Imc:HIMC;
begin
winctr.SetFocus; //対象のコントロールにフォーカスを当てる
Imc := ImmGetDefaultIMEWnd(winctr.Handle); //winctrに対するIMEのハンドルを取得
if valeu then SendMessage(Imc,
WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0)
else SendMessage(Imc, WM_IME_CONTROL,
IMC_CLOSESTATUSWINDOW, 0);
//SendMessage()で表示、非表示を切り替える
end;
valeuにはtrue(表示)false(非表示)を渡します。
しかしながら、WinXPのIME2002では非表示にならず、表示サイズが小さくなるだけでした。
その他のバージョンのIMEやAtokでは効くみたいです。
IMEのOn Off
procedure ImeOnOff(const winctr :TWinControl; const status:boolean);
var Imc:HIMC;
begin
winctr.SetFocus;
if status then Win32NLSEnableIME(winctr.Handle,true)
else Win32NLSEnableIME(winctr.Handle,false);
// MS-IMEでは上記のようにします。win98以降のもの?
Imc := ImmGetContext(winctr.Handle);
if status then ImmSetOpenStatus(imc,true)
else ImmSetOpenStatus(imc,false);
ImmReleaseContext(winctr.Handle, Imc);
//その他のIME(Atokなど)では、上の3行でOKみたいです。
end;
statusにはtrue(On)false(Off)を渡します。
入力文字種の切り替え
Type
TImeCharMode = (ZenHiragana,ZenKatakana,ZenEisu,HanKatakana,HanEisu,Kigou);
//事前に定義しておきます。
procedure SetInputCharMode(const winctr :TWinControl;const
ImeCharMode:TImeCharMode);
var
Imc
: HIMC;
dwConversion : DWORD;
dwSentence : DWORD;
begin
winctr.SetFocus;
Imc := ImmGetContext(winctr.Handle);
ImmGetConversionStatus(Imc,dwConversion,dwSentence);
If (dwConversion And IME_CMODE_ROMAN)
= IME_CMODE_ROMAN Then
dwConversion := IME_CMODE_ROMAN else
dwConversion := 0;
case ImeCharMode of
ZenHiragana: dwConversion :=
dwConversion or
IME_CMODE_JAPANESE or
//日本語
IME_CMODE_FULLSHAPE; //全角
ZenKatakana: dwConversion :=
dwConversion or
IME_CMODE_JAPANESE or
//日本語
IME_CMODE_FULLSHAPE or //全角
IME_CMODE_KATAKANA; //カタカナ
ZenEisu: dwConversion := dwConversion or
IME_CMODE_FULLSHAPE; //全角英数字
HanKatakana: dwConversion := dwConversion or
IME_CMODE_JAPANESE or
//日本語
IME_CMODE_KATAKANA; //カタカナ
HanEisu: dwConversion := dwConversion or
IME_CMODE_ALPHANUMERIC; //英数字
Kigou : dwConversion := dwConversion
or
IME_CMODE_CHARCODE; //
記号 = &H20
end;
ImmSetConversionStatus(Imc,dwConversion,dwSentence);
ImmReleaseContext(winctr.Handle, Imc);
end;
現在の入力文字種判定
Type
TImeCharMode = (ZenHiragana,ZenKatakana,ZenEisu,HanKatakana,HanEisu,Kigou);
//事前に定義しておきます。
Function GetInputCharMode(const winctr :TWinControl):TImeCharMode;
var Imc:HIMC;
dwConversion : DWORD;
dwSentence : DWORD;
begin
winctr.SetFocus;
Imc := ImmGetContext(winctr.Handle);
ImmGetConversionStatus(Imc,dwConversion,dwSentence);
case dwConversion of
IME_CMODE_JAPANESE or IME_CMODE_FULLSHAPE:result:=
ZenHiragana;
IME_CMODE_JAPANESE or IME_CMODE_FULLSHAPE
or IME_CMODE_KATAKANA:result:= ZenKatakana;
IME_CMODE_FULLSHAPE:result:= ZenEisu;
IME_CMODE_JAPANESE or IME_CMODE_KATAKANA
:result:= HanKatakana;
IME_CMODE_ALPHANUMERIC:result:= HanEisu;
IME_CMODE_CHARCODE:result:= Kigou;
end;
ImmReleaseContext(winctr.Handle, Imc);
end;
現在の入力モードの判定(ローマ字・かな入力)
type
TImeInputMode = (ROMAN,HIRA);
//事前に定義しておきます。
Function GetInputMode(const winctr :TWinControl):TImeInputMode;
var Imc:HIMC;
dwConversion : DWORD;
dwSentence : DWORD;
begin
winctr.SetFocus;
Imc := ImmGetContext(winctr.Handle);
ImmGetConversionStatus(Imc,dwConversion,dwSentence);
If (dwConversion And IME_CMODE_ROMAN)
= IME_CMODE_ROMAN Then result:=ROMAN
else result:=HIRA;
ImmReleaseContext(winctr.Handle, Imc);
end;
すでにIMEがオープンしているか
Function IsImeOpened(const winctr :TWinControl):boolean;
var Imc:HIMC;
begin
winctr.SetFocus;
Imc := ImmGetContext(winctr.Handle);
result:= ImmGetOpenStatus(imc);
ImmReleaseContext(winctr.Handle, Imc);
end;
現在のIMEの名前を取得
Function GetImeName(const winctr :TWinControl):string;
var kl:HKL;
Imc:HIMC;
imename:array[0..255]of char;
begin
winctr.SetFocus;
Imc := ImmGetContext(winctr.Handle);
if not ImmGetOpenStatus(Imc)then
ImmSetOpenStatus(Imc, TRUE);
Kl := GetKeyboardLayout(0);
if not ImmIsIME(Kl)then
result:='' else
ImmGetDescription(Kl,imename, sizeof(imename));
result:= strpas(imename);
ImmReleaseContext(winctr.Handle, Imc);
end;
使用可能な全てのIMEの名前を取得してComboBoxへ入れる
これは手抜きで、Delphiの関数を使ってます(^^;;)
procedure Tform1.Button1Click(Sender: TObject);
begin
ComboBox1.Items.AddStrings(screen.Imes);
end;
上記で取得した複数のIMEを切り替える。
対象はForm上にあるEdit1とします。
procedure Tctrl_f.ComboBox1Click(Sender: TObject);
begin
edit1.ImeName:= ComboBox1.Items.Strings[ComboBox1.itemindex];
end;
|