フリーソフト

« 2005年12月 | トップページ | 2006年2月 »

[BCB] BCB6.0のIndyをバージョンアップ

BCB6.0には最初からIndyがインストールされていますが、それをIndy9にバージョンアップする方法です。

最初にインストールを試みたときは、「プロシージャエントリポイント Idresourcestrings@_RSBindingAnyがダイナミックリンクライブラリIndy60.bplから見つかりませんでした。」というエラーがでてパッケージがインストールできず苦労しましたが、下記のとおりの順番でやり直したところうまくいきました。


前準備(BCBのアップデート)

(1) ボーランドのページからBorland C++Builder 6 アップデートパック #4をダウンロード。すでにインストール済みの場合はスキップ。

(2) アップデートパックをインストールする。

古いIndyのアンインストール

(3) コントロールパネルから「プログラムの追加と削除」を起動。

(4) その中から「Borland C++Builder 6」を選択して「変更」をクリック。インストールCDROMを求められた場合はCDROMを挿入。

(5) 表示された機能一覧の中から「Indy」を探して、「インストールしない」にして「次へ、次へ」。

(6) 残っているゴミの削除。以下はIndyのサイトに書いてあった情報。
 (6-1) $(BCB)フォルダ以下から「IDPAS32.obj」というファイルを検索していったん、デスクトップなどに移動する。BCB6.0なら $(BCB)\Source\vcl内に見つかると思います。
 (6-2) $(BCB)フォルダ以下から「dclindy*.bpl, dclindy.*, dclindy*.bpl, indy*.lib, id*.pas, id*.hpp, id*.obj, id*.dcu」を検索して削除。Indy関連ではないファイルを間違えて削除しないように注意。検索するときは「」内の文字列をそのままWindowsの検索画面の「ファイル名のすべてまたは一部」の欄に入力して検索すればOK。
 (6-2) C:\Windows\System32以下の「indy*.bpl」を検索して削除。
 (6-3) $(BCB)\Help以下から「indy.*」を検索して削除。
 (6-4) 6-1で移動しておいたIDPAS32.objを元の場所に戻す。

新しいIndyのダウンロードとインストール

(7) Indyのページからソースをダウンロード。WindowsはZipで配布されている。

(8) ダウンロードしてきたファイルを展開。展開して出てきたフォルダを、適当なフォルダを新規に作ってその中に移動する。

(9) 展開したフォルダの中にある「Fullc6.bat」を実行。DOSの画面が消えるまで待つ。実行が終わるとひとつ上のフォルダに「C6」というフォルダができている。

(10) 「C6」フォルダの中身を「$(BCB)\Source\Indy」にまるごとコピー。

(11) 「C6」フォルダの「dclIndy60.bpl」を「$(BCB)\bin」にコピー。

(12) 「C6」フォルダの「hpp」という拡張子のファイルを全部「$(BCB)\Include」にコピー。

(13) BCBを起動する。

(14) 「ツール」-「環境オプション」で表示されるダイアログで、「ライブラリ」タブを選択。「ライブラリパス」に「$(BCB)\Source\Indy」を追加して「OK」でダイアログを閉じる。

(15) 「コンポーネント」-「パッケージのインストール」。「追加」ボタンを押して「$(BCB)\bin\dclIndy60.bpl」を選択。チェックがついていることを確認して「OK」を押すとパレットに新しいIndyコンポーネントが追加される。

Indyヘルプファイルの更新

(16) Indyのページから新しいヘルプファイルをダウンロード。何種類が形式が用意されているが、元のと同じWinHelp形式を選択。

(17) ダウンロードしたファイルを展開。

(18) 展開したフォルダの中にあるファイルを丸ごと「$(BCB)\Help」にコピー。

インストールはこれで完了。

もともと古いバージョンのIndyを使っていたプロジェクトをコンパイルする場合は、そのままだとエラーが出る。プロジェクトファイル(例:Project1.bpr)をメモ帳などで開き、「Indy.lib」と「Indy.bpi」という文字列を検索して削除してから改めてコンパイルしなおすとうまくいく。

[BCB] 電光掲示板のようにスクロールするラベル

電光掲示板の文字のようにスクロールするラベルです。 Form上にLabelとTimerをひとつずつ置きます。

スクロールさせたい文字列はCaptionStringという内部変数に入れておきます。TimerのIntervalは200くらいにしておきます。

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
 static int x=Label1->Width;
 RECT r;
 int w;

 r.left=0;
 r.top =0;
 r.right=Label1->Width;
 r.bottom=Label1->Height;

 w=Label1->Canvas->TextWidth(CaptionString);
 if (w+x<0) X=Label1->Width;

 Label1->Canvas->Brush->Color=Label1->Color;
 Label1->Canvas->Brush->Style=bsSolid;
 Label1->Canvas->FillRect(r);
 Label1->Canvas->TextRect(r,X,1,CaptionString);
 Label1->Update();
 x=x-10;//移動量
}

[BCB] タスクバーに表示されないアプリを作る

プロジェクトのソースファイルを以下のように書き換えます。ソースファイルは「プロジェクト」-「ソース表示」で表示できます。

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
  try
  {
    Application->Initialize();
    //タスクバーからアイコンを消す
    ShowWindow(Application->Handle, SW_HIDE);
    SetWindowLong(Application->Handle, GWL_EXSTYLE,
      GetWindowLong(Application->Handle, GWL_EXSTYLE) | WS_EX_TOOLWINDOW);
    Application->CreateForm(__classid(TForm1), &Form1);
    Application->Run();
  }
  catch (Exception &exception)
  {
    Application->ShowException(&exception);
  }
       :

[BCB] StringGridを列を指定してソートする(バブルソート)

以下はStringGridで列を指定してソートする手続きです。1つ目の引数にはソートするStringGridを、2つ目の引数には何列目でソートするかを指定します。なお、以下の例ではデータを文字列としてソートしていますが、データを比較するif文を書き換えれば数値としてソートすることも可能です。その場合は、比較する2つデータをStrToIntなどで整数に直してから比較することになります。

void __fastcall TForm1::StringGridSort(TStringGrid *Grid, int SortCol)
{
 for (int i=Grid->FixedRows;iRowCount-1;i++) {
  for (int j=Grid->RowCount-1;j>i;j--) {
   if (Grid->Cells[SortCol][j-1]>Grid->Cells[SortCol][j]) {//データを比較
    //2つの行を入れ替える
    AnsiString TmpStr=Grid->Rows[j-1]->CommaText;
    Grid->Rows[j-1]->CommaText=Grid->Rows[j]->CommaText;
    Grid->Rows[j]->CommaText=TmpStr;
   }
  }
 }
}

この手続きはバブルソートという方法を使っています。時間のかかるソート法ですので行数が多くなると固まったようになるかもしれません。

[BCB] StringGridでクリックされた場所のRowとColを取得

StringGridで、一番上の行につくったFixedRowがクリックされたときに、クリックされた列をキーにしてデータをソートしたいということがあります。マウスクリックされた場所が、何行、何列のセルなのかは以下のようにして取得することができます。

void __fastcall TSentenceSimForm::StringGrid1MouseUp(TObject *Sender,
   TMouseButton Button, TShiftState Shift, int X, int Y)
{
 int ARow,ACol;
 StringGrid1->MouseToCell(X,Y,ACol,ARow);

 //AColに列、ARowに行番号が格納される
 
 if (ARow!=0) return; //クリックされたのが一番上の行じゃなかったらreturn
 else StringGridSort(ACol); //ACol列でソート
}

上の例のStringGridSortは自分で定義する必要があります。

[BCB] フォルダを削除する

RemoveDirectoryを使います。

[BCB] バイナリデータをBase64エンコードする

入力されたバイナリデータをBase64エンコードする関数です。引数Bufには入力データ列を、Lengthにはその長さを指定します。エンコードの結果はAnsiString型の文字列で返されます。

AnsiString __fastcall Encode64(Byte *Buf,int Length)
{
 char *Codes64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 int Byte3=0;
 AnsiString Result="";

 for (int i=0;i<Length;i++) {
  Byte3=(Byte3<<8)+(int)Buf[i];
  if ((i+1)%3==0) {
   Result=Result+Codes64[(Byte3>>18)&0x3F];
   Result=Result+Codes64[(Byte3>>12)&0x3F];
   Result=Result+Codes64[(Byte3>>6 )&0x3F];
   Result=Result+Codes64[(Byte3  )&0x3F];

   Byte3=0;
  }
 }

 int Rest=Length%3;
 switch (Rest) {
 case 1:
  Byte3=Byte3<<4;
  Result=Result+Codes64[(Byte3>>6 )&0x3F];
  Result=Result+Codes64[(Byte3  )&0x3F];
  Result=Result+"==";
  break;
 case 2:
  Byte3=Byte3<<2;
  Result=Result+Codes64[(Byte3>>12)&0x3F];
  Result=Result+Codes64[(Byte3>>6 )&0x3F];
  Result=Result+Codes64[(Byte3  )&0x3F];
  Result=Result+"=";
  break;
 }
 return Result;
}

[BCB] フォームが最大化(最小化)されているか調べる

フォームの状態を調べるにはWindowStateプロパティを使用します。

{
 switch (Form1->WindowState) {
 case wsMaximized:
  //最大化されている
  break;
 case wsMinimized:
  //最小化されている
  break;
 case wsNormal:
  //どちらでもない
  break;
 }
}

[Delphi] 電源(バッテリ)の状態を取得する

GetSystemPowerStatus関数を使います。この関数はWindows NTでは使用できません。

procedure TForm1.Button1Click(Sender: TObject);
var
 SystemPowerStatus: TSystemPowerStatus;
begin
 GetSystemPowerStatus(SystemPowerStatus);
end;

関数を実行するとTSystemPowerStatus構造体に結果が格納されます。構造体のメンバは以下のとおりです。

ACLineStatusAC電源の状態
BatteryFlagバッテリの充電状態
BatteryLifePercentバッテリの残り(%)
Reserved1未使用(常に0)
BatteryLifeTimeバッテリの残り時間(秒)
BatteryFullLifeTimeフル充電状態での残り時間(秒)

値の意味は以下のとおりです。

ACLineStatus

0オフライン
1オンライン
255不明

BatteryFlag

1残り66%以上
2残り33%以下
4残り5%以下
8充電中
128バッテリはない
255不明

[BCB] OSの名前を取得する(簡易版)

ヘッダ

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Windows.hpp>

class TSysOSVersionInfo
{
private:
 AnsiString FProductID;
 AnsiString FProductName;
 DWORD FServicePackVersion;
 DWORD FVersionMajor;
 DWORD FVersionMinor;
 DWORD FVersionBuild;
 AnsiString FCSDVersion;

 bool FIsWinNT;
public:
 __fastcall TSysOSVersionInfo(void);
 __fastcall ~TSysOSVersionInfo(void);

 __property AnsiString ProductID={read=FProductID};
 __property AnsiString ProductName={read=FProductName};
 __property AnsiString ProductType={read=FProductType};
 __property DWORD ServicePackVersion={read=FServicePackVersion};
 __property DWORD VersionMajor={read=FVersionMajor};
 __property DWORD VersionMinor={read=FVersionMinor};
 __property DWORD VersionBuild={read=FVersionBuild};
 __property AnsiString CSDVersion={read=FCSDVersion};
};


#endif

ソース

//---------------------------------------------------------------------------


#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#include <windows.h>
#include <Registry.hpp>

//---------------------------------------------------------------------------
__fastcall TSysOSVersionInfo::TSysOSVersionInfo(void)
{
 TSystemInfo SystemInfo;

 memset(&SystemInfo, 0x00, sizeof(SystemInfo));
 GetSystemInfo(&SystemInfo);

 FIsWinNT = (Win32Platform == VER_PLATFORM_WIN32_NT);

 //ProductID,ProductName
 TRegistry *Reg=new TRegistry(KEY_READ);
 try {
  bool Res;
  Reg->RootKey=HKEY_LOCAL_MACHINE;
  if (FIsWinNT) Res=Reg->OpenKeyReadOnly("Software\\Microsoft\\Windows NT\\CurrentVersion");
  else Res=Reg->OpenKeyReadOnly("Software\\Microsoft\\Windows\\CurrentVersion");

  if (Res) {
   FProductID=Reg->ReadString("ProductID");
   FProductName=Reg->ReadString("ProductName");
  }

  Reg->CloseKey();
 } __finally {
  delete Reg;
 }
 FVersionMajor=Win32MajorVersion;
 FVersionMinor=Win32MinorVersion;
 FVersionBuild=Win32BuildNumber;
 FCSDVersion=Win32CSDVersion;
}
//---------------------------------------------------------------------------
__fastcall TSysOSVersionInfo::~TSysOSVersionInfo(void)
{

}
//---------------------------------------------------------------------------

[BCB] 世界協定時刻(UTC)をローカルタイムに変換

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 TSystemTime STime,LTime;
 TIME_ZONE_INFORMATION TzInfo;

 //タイムゾーン情報を取得
 GetTimeZoneInformation( &TzInfo );
 //現在のシステム時刻(UTC)を取得
 GetSystemTime(&STime);

 //タイムゾーン情報を使ってローカルタイムに変換
 SystemTimeToTzSpecificLocalTime(&TzInfo,&STime,&LTime);

 //結果を表示
 AnsiString Str;
 Str.printf("%02d:%02d:%02d",LTime.wHour,LTime.wMinute,LTime.wSecond);
 Label1->Caption=Str;
}

[BCB] 文字が数字かどうか調べる

bool __fastcall IsNumeric(char c)
{
 return ((c>='0') && (c<='9'));
}

[BCB] TSystemTime(_SYSTEMTIME)とTDateTimeの変換

TSystemTimeをTDateTime型に変換

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 TDateTime DateTime;
 TSystemTime SystemTime;

 GetLocalTime(&SystemTime);
 //変換
 DateTime=SystemTimeToDateTime(SystemTime);
}

TDateTimeをTSystemTimeに変換

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 TDateTime DateTime;
 TSystemTime SystemTime;

 DateTime=Now();
 //変換
 DateTimeToSystemTime(DateTime,&SystemTime);
}

[Delphi] 実数を整数部分と小数部分に分ける

Frac関数、およびInt関数を使用します。

uses System,Math;

var
 J:Extended;
 I:Integer;
 S:Extended;
begin
 J:=1.23;

 I:=Int(J); //整数部分 1
 S:=Frac(J); //小数部分 0.23
end;

[BCB] 世界協定時刻(UTC)を取得する

GetSystemTimeを使用します。引数にはTSystemTime構造体へのポインタを指定します。

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 TSystemTime Stime;
 GetSystemTime(&Stime);

 AnsiString Str;
 Str.printf("%d/%d/%d",Stime.wYear,Stime.wMonth,Stime.wDay);
 Lable1->Caption=Str;
}

TSystemTime構造体には次の値が格納されます。

wYear
wMonth
wDayOfWeek曜日(日:0、月:1、..、土:6)
wDay
wHour
wMinute
wSecond
wMillisecondsミリ秒

なお、ローカル時間はGetLocalTimeで取得することができます。

[BCB] TColorをRGB値に変換する

TColorをR,G,Bの値に分解する関数です。

void TColor2RGB(TColor Color, Byte &R, Byte &G, Byte &B)
{
 int RGB=ColorToRGB(Color);

 R=RGB&0xFF;
 G=(RGB>>8)&0xFF;
 B=(RGB>>16)&0xFF;
}

[Delphi] TColorにRGB値を代入する

var
 Color : TColor;
begin
 //RGBの引数はR,G,Bの順番
 Color:=RGB(255,0,0);
end;

[BCB] システムの音を鳴らす

MessageBeepを使うと、コントロールパネルの[サウンド]で設定された音を鳴らすことができます。引数には音の種類を指定します。

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 MessageBeep(MB_ICONASTERISK);
}

指定できる音の種類

0xFFFFFFFF標準のビープ音
MB_ICONASTERISKシステム 情報
MB_ICONEXCLAMATIONシステム 警告
MB_ICONHANDシステム エラー
MB_ICONQUESTIONシステム 問い合わせ
MB_OKデフォルトの警告音

[BCB] システムのアイコンを取得する

LoadIconを使用すると、システムで使用されるアイコン(MessageDialogなどに表示されるエラーや警告のアイコンなど)を取得できます。

void __fastcall TForm1::FormCreate(TObject *Sender)
{
 //Image1にエラーのアイコンを表示
 Image1->Picture->Icon->Handle = LoadIcon(0, IDI_HAND);
}

他にも以下のような値を指定できます。

IDI_APPLICATION
IDI_HAND
IDI_QUESTION
IDI_EXCLAMATION
IDI_ASTERISK
IDI_WINLOGO

[Delphi] Memoでキャレット位置に文字列を挿入する

Memo1.SelText:='挿入する文字列';

[BCB] ファイル名の拡張子を変更する

ファイル名の拡張子を変更するにはChangeFileExt関数を使います。

#include <SysUtils.hpp>

//拡張子を取得
Filename="C:\\tmp\\test.ini";
Result=ChangeFileExt(Filename,".htm");

引数には元のファイル名と拡張子を「.」を含めた形で指定します。上の例の場合、Resultは「C:\tmp\test.htm」となります。

ChangeFileExt(Filename,"");
のようにすると拡張子を取り除くこともできます。

[BCB] ファイルの拡張子を取得する

ファイルの拡張子を取得するにはExtractFileExt関数を使います。

#include <SysUtils.hpp>

//拡張子を取得
Filename="C:\\tmp\\test.ini";
FileExt=ExtractFileExt(Filename);

関数を実行すると変数FileExtには、拡張子が「.」を含めた形で格納されます。上の例の場合はFileExtの内容は「.ini」となります。

拡張子がない場合は空の文字列が返されます。

[BCB] ダイアログを動的に作成する

ダイアログを動的に作成する方法です。以下はTSaveDialogの例です。

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 TSaveDialog *Dlg;

 Dlg=new TSaveDialog(this);
 //フィルタを設定
 Dlg->Filter="テキストファイル(*.txt)|*.txt|HTMLファイル(*.htm)|*.htm|すべてのファイル|*.*";
 //オプションを設定
 Dlg->Options=Dlg->Options<<ofOverwritePrompt<<ofPathMustExist;
 Dlg->FileName="list.txt";

 if (Dlg->Execute()) {
  //処理をする
 }
 
 delete Dlg;
}

[Delphi] 画面のサイズを取得する

画面のサイズを取得するにはTScreenのプロパティを使います。

W:=Screen.Width; //画面の幅
H:=Screen.Height; //画面の高

[BCB] Delphiのwith文に対応するものは?

Delphiにはwith文を使って、長いコードを省略することができます。例えば以下のようです。

with Form1.Image1.Picture.Bitmap.Canvas do begin
 MoveTo(0,0);
 LineTo(1,1);
end;

BCBでも使いたいところですが残念ながらBCBにはwith文はありません。その代わりに次のようにして書くことができます。

TCanvas *Canvas=Form1->Image1->Picture->Bitmap->Canvas;
Canvas->MoveTo(0,0);
Canvas->LineTo(1,1);

[BCB] 3桁ごとに数字をカンマで区切る

FormatFloat('#,##0', Value);

これだけでOK。

« 2005年12月 | トップページ | 2006年2月 »