メイン

Delphi アーカイブ

2004年08月27日

RaveReportでNDRファイルをプレビュー

RaveレポートでNDRファイルを作成し、そのファイルをTRvSystemでプレビューした場合、なぜかNDRファイルを掴んだままになってしまいます。
プレビュー閉じたら、ファイルハンドル開放しろよな・・・まったく。


で、その回避方法

RvSystem.systemFiler.StreamMode := smFile
RvSystem.SystemOption := RvSystem.SystemOption + [soNoGenerate];

 ※ここではソースで記述していますが、プロパティエディタで設定してもいいですよ。


ちなみにNDRファイルをプレビューするサンプル

RvSystem1.SystemFiler.FileName := 'XXXX.ndr';
RvSystem1.DefaultDest := rdPreview;
RvSystem1.Execute;

なお、現象確認したRaveのバージョンは5.08です。

2004年04月08日

Delphi7はバグだらけぇ

Delphi7はバグだらけぇ

いや、ホントですよ。
6も結構バギーだったけど、7はヒドイ・・・
納期が迫ってきてる時にこれが出るとかなーりぶち切れです。

たとえばプリペアドクエリーの実行時の例
  query.SQL.Text := 'select * from HOGE where AGE = :AGE ';
  query.Prepare;
  try
    for i := 0 to 10000 do begin
      query.ParamByName('AGE').AsInteger := i;
      query.Open;
      while not query.Eof do begin
        query.Next;
      end;
      query.close;
    end;
  finally
    query.UnPrepare;
  end;

こんな普通のコードを実行するとあっという間に使用メモリがガンガン上がり、 「この操作に必要なメモリがありません。」とかエラーになります。
今までこんな事は無かったんですけど、このバグは痛い・・・
毎回プリペア&アンプリペアすれば回避できるんですけど、意味無いし(^^;
ちなみにOracle9i+BDE5.2+delphi7entで確認しました。
※そりゃOracle9iはBDEの対応DBに入ってないですけどね・・・

2004年03月10日

WM_COPYDATAを使ったプロセス間通信

WM_COPYDATAを使ったプロセス間通信 プロセス間通信のサンプルです。
通信用データにはクラスのストリーミング機能をつかってみました。

フォームのクラス名を"TCommunication"
フォーム上に memSend:TMemo と memRecv: TMemo を作成しておきます。
送信用のボタンも1つ作成します。
またキャプションを'プロセス間通信'としておきます。
//interface部
------ここから--------
type
  //フォームの定義。参考までに
  TCommunication = class(TForm)
    memSend: TMemo;
    memRecv: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    //WM_COPYDATAの受信メソッド
    procedure WMCopyData(var msg: TWMCopyData);message WM_COPYDATA;
  public
  end;


  //送受信用データ定義
  TCommunicateData = class(TComponent)
  private
    FstringData1:String;
    FintegerData1:integer;
  published
    //ストリーミングの為publishedであることが重要。
    property stringData1 :String read FstringData1 write FstringData1;
    property integerData1 :integer read FintegerData1 write FintegerData1;

  end;
------ここまで--------
TCommunicateDataというクラスをつかって通信します。
publishedなプロパティであればストリーミング機能が使える為
文字の最大長等をあまり気にせず受け渡しが可能です。
※delphiのバージョンが違うものでコンパイルしたEXE同士では正しく通信できない可能性があります。

//implementation部
------ここから--------

//送信処理 ボタンのクリックイベント
procedure TCommunication.Button1Click(Sender: TObject);
var
  buf: PChar;
  i: Integer;
  copydata: TCopyDataStruct;
  targetHnd:HWND;
  mem:TMemoryStream;
  data:TCommunicateData;
begin
  //ハンドルをクラス名とフォームキャプションで検索するために
  //自分自身のキャプションを変更しておきます。
  Caption := 'プロセス間通信 -- 送信中';

  //送信先のハンドルを取得
  targetHnd := FindWindow('TCommunication','プロセス間通信');

  if targetHnd = 0 then raise Exception.Create('送信対象が見つかりませんでした。');

  mem := TMemoryStream.Create;
  try

    //送受信用データを作成
    data := TCommunicateData.Create(self);
    try
      data.stringData1 := memSend.Text;
      data.integerData1 := 1;

      //送信用データをメモリストリームに書き込む
      mem.WriteComponent(data);

      //TCopyDataStruct構造体の設定
      copydata.dwData := 5963; //メッセージのID なんでもよい
      copydata.cbData := mem.Size;
      copydata.lpData := mem.Memory;

      //送信
      SendMessage(targetHnd, WM_COPYDATA, WPARAM(Handle), LPARAM(@copydata));

    finally
      data.Free();
    end;

  finally
    mem.Free;
  end;

  Caption := 'プロセス間通信';

end;

//受信処理
procedure TCommunication.WMCopyData(var msg: TWMCopyData);
var
  i: Integer;
  buf: PChar;
  mem:TMemoryStream;
  data:TCommunicateData;
begin
  //決められたIDのものだけ処理する
  if msg.CopyDataStruct.dwData=5963 then begin

    mem := TMemoryStream.Create;
    try
      //メモリストリームにTWMCopyDataから受信したデータを書き込む
      mem.Write(Msg.CopyDataStruct^.lpData^,Msg.CopyDataStruct^.cbData);
      mem.Seek(0, soFromBeginning);

      //送受信クラスをインスタンス化しておき
      data := TCommunicateData.Create(self);
      try
        //メモリストリームからプロパティ値を読み出す
        mem.ReadComponent(data);


        memRecv.Text := data.FstringData1;

      finally
        data.Free;
      end;

    finally
      mem.Free;
    end;


  end
  else
    inherited;

end;

------ここまで--------
コンパイルして出来たEXEを2つ起動し、片方でmemSendに適当な内容を記入してボタンをクリックしてみてください。
もう片方のmemRecvに受信した内容が出力されるはずです。

2003年11月11日

スクロールバーを消す

フォームやツリービューなどのスクロールバーを消す方法です。
procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowScrollBar(
                  S3TreeList1.Handle  //消したいウィンドウのハンドル
                , SB_VERT                 //縦のスクロールバー
                , False);                   //消す指定 
end;

2003年10月30日

デスクトップの作業領域を取得する

rWorkAreaに作業領域の座標が設定されます
var
  rWorkArea : TRect;
begin
  SystemParametersInfo(SPI_GETWORKAREA, 0, @rWorkArea, 0);

2003年09月18日

特定のキーが押されているかチェックする

下記のようなメソッドを使えばいつでも特定のキーが押されているか チェックできます。
function CheckKeyDown(const strKey : Char):Boolean;overload;
function CheckKeyDown(const intVKey : Integer):Boolean;overload;

//文字で判断
function CheckKeyDown(const strKey : Char):Boolean;
var
  strWk : String;
begin
   strWk := strKey;
   strWk := UpperCase(sWk);
   Result := CheckKeyDown(Integer(strWk[1]));
end;

//仮想文字コードで判断
function CheckKeyDown(const intVKey : Integer):Boolean;
begin
  result := not((GetAsyncKeyState(intVKey) and $8000) = 0);
end;


-使用例-

  if CheckKeyDown('A') then begin
     showmessage('Aが押されてます');
  end;

  if CheckKeyDown(VK_SHIFT) then begin
     showmessage('SHIFTが押されてます');
  end;

2003年09月14日

TRichEditをキャレット位置までスクロールする

こんな感じです。

richedit1.perform(EM_SCROLLCARET,0,0);

2003年09月13日

protectedなメソッド、プロパティにアクセス

通常protectedなメソッドにアクセスするためにはそのクラスを継承したクラスを作成すべきなのでしょうけど、
ちょっとしたことでわざわざクラス作るのってめんどくさいですよねぇ。

そこでこれです。

type
TGridCracker = class(TStringGrid);

などとダミーのクラスを宣言しておきますと次のようにアクセスできるようになります。

TGridCracker(StringGrid1).InplaceEditor

結構便利です。

2003年09月12日

IMEが入力中であるか調べる

次の例ではLabel1のキャプションに入力中かどうかを設定しています。 でも、本当はもっと直接的に状態を取得したいなぁ。。
[インターフェース部]

  public
    FSaveWndProc:TWndMethod;
    procedure SubclassProc(var Msg:TMessage);


[実現部]

procedure TForm1.FormCreate(Sender: TObject);
begin
  //対象となるコントロールをサブクラス化します。
  FSaveWndProc := Memo1.WindowProc;
  Memo1.WindowProc := SubclassProc;

  Label1.Caption := '入力されてません';
end;

procedure TForm1.SubclassProc(var Msg: TMessage);
begin
  case Msg.Msg of
    WM_IME_ENDCOMPOSITION:
        Label1.Caption := '入力されてません';
    WM_IME_COMPOSITION:
        Label1.Caption := '入力中~';
  end;

  //元のWindowプロシージャを実行
  FSaveWndProc(Msg);
end;

2003年09月11日

BDEがインストールされているか確認する

下記のような方法で調べることが可能です。

function TForm1.CheckBdeExist: boolean;
var
  ses:TSession;
begin
  //TSessionをCreateしただけだとBDEがインストールされていなくてもエラーは発生しない。
  //フォームに貼り付けてもそれは同じ、なにかBDEに対してアクションした場合にエラーが発生する。
  try
    ses := TSession.Create(self);
    try
      ses.AutoSessionName := true;
      ses.IsAlias('AAA'); //何でもいいです。
      result := true;
    finally
      ses.Free;
    end;
  except
    result := false;
  end;
end;	

2003年09月10日

ADOでCSVファイルを操作

次の接続文字列を使うとCSVファイルをテーブルの様に使えます。
クエリも実行できちゃいますよ

//この例ではドライブEの直下にあるファイルに対しての接続となります。
Driver={Microsoft Text Driver (*.txt; *.csv)}; DefaultDir=e:\