Delphi Tips
>> Index
● 02/11 可変長レコードの扱い方
● 02/08 Delphi/CBuilder で作った DLL から VB に文字列を返す
● 02/08 複数プログラムから同一内容のメモリを参照/更新する
● 02/08 DLL のロード・アンロードでメモリリーク?
● 02/08 Delphi1.0でHugeポインタを使う
● 02/08 New/Dispose に Pointer 型のポインタを渡すと。。。
● 02/08 Delphi 1.0 (16bit)で、物理メモリアドレスに直接アクセスする
最終更新: 9415 日前
0149 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 編集
可変長レコードの扱い方
> 今、DirectPlayの送信部分を制作していますが、
>
> HRESULT Send(DPID idFrom, DPID idTo, DWORD dwFlags,
> LPVOID lpData, DWORD dwDataSize);
>
> 上記のようになっていて、送信データ部分を構造体のポインタで渡す
> ようになっています。現在は、
>
> TTextMessage = record
> dwType: DWORD; { dwType は絶対に必要 }
> Msg :array[0..255]of char;
> end;
>
> としてstring型からchar型に変換してから送受信をしていますが、
> 255文字以上送信できませんし、短い場合は無駄が生じるように思います。
> このmsgの部分を可変サイズにする方法はないでしょうか?
必要な量だけヒープから確保するのがよろしいかと思います。
具体的な案としては、以下のような手順が考えられます。
1. 送信用に AllocMem等で 必要量だけ確保
2. 確保した領域を編集しやすいように 予め用意しておいた型をかぶせ、編集
3. 送信
4. 確保領域の開放
例)
const
Giga = (1024*1024*1024);
type
// 編集用の型
PTextMessage = ^TTextMessage;
TTextMessage = record
dwType: DWORD;
Msg: array[0..1*Giga -1] of Char;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
pBuf: Pointer;
pMsg: PTextMessage;
begin
pBuf := AllocMem(Sizeof(pMsg^.dwType) + 4092);
// 型をかぶせて編集
pMsg := pBuf;
with pMsg^ do
begin
dwType := $12345678;
StrCopy(Msg, PChar(StringOfChar('A', 4091)));
end;
... // 送信等
FreeMem(pBuf);
end;
参照: [Delphi-ML:25091] <PASCAL>
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] <Windows> <DLL>
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] <Windows> <ファイル>
0106 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 編集
DLL のロード・アンロードでメモリリーク?
プログラム中でDLLの呼び出し、開放を何度も行っていると、システムモニターの「アロケート済みメモリ」がどんどん増えていきます。
簡単なDLL呼出しプログラムを作って試しましたが、呼出・開放を2018回繰り返すとプログラムがとまります。DLLの内容には関係ありません。
また、NT4/BCB3を使っても同様の現象が発生します。
以下の方法で回避できます。
・インポートライブラリを使ってDLLをリンクする
または
・DLLを作成するときにVCLをリンクしない(DLLでVCLを使っていない場合のみ)
参照: [builder:5705] <バグ> <DLL>
0025 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 編集
Delphi1.0でHugeポインタを使う
Delphi1.0用のHugeポインタルーチンです。
もう過去の遺物かな?
function HpSubOne( pointer:Pointer ):Pointer;
inline(
$58/ { POP AX }
$5A/ { POP DX }
$2d/$01/$00/ { SUB AX,1 }
$73/$03/ { JNB @@ }
$83/$EA/$08 { SUB DX,8 }
); {@@: }
function HpAddOne( pointer:Pointer ):Pointer;
inline(
$58/ { POP AX }
$5A/ { POP DX }
$40/ { INC AX }
$75/$03/ { JNZ @@ }
$83/$C2/$08 { ADD DX,8 }
); {@@: }
function HpAddWord( pointer:Pointer ; offset:Word ):Pointer;
inline(
$59/ { POP CX }
$58/ { POP AX }
$5A/ { POP DX }
$01/$c8/ { ADD AX,CX }
$73/$03/ { JNC @@ }
$83/$C2/$08 { ADD DX,8 }
); {@@: }
function HpSubWord( pointer:Pointer ; offset:Word ):Pointer;
inline(
$59/ { POP CX }
$58/ { POP AX }
$5A/ { POP DX }
$29/$c8/ { SUB AX,CX }
$73/$03/ { JNB @@ }
$83/$EA/$08 { SUB DX,8 }
); {@@: }
function HpAddLong( pointer:Pointer ; offset:LongInt ):Pointer;
inline(
$59/ { POP CX }
$5B/ { POP BX }
$58/ { POP AX }
$5A/ { POP DX }
$01/$c8/ { ADD AX,CX }
$83/$D3/$00/{ ADC BX,0 }
$B1/$03/ { MOV CL,3 }
$D3/$E3/ { SHL BX,CL }
$01/$DA { ADD DX,BX }
);
function HpSubLong( pointer:Pointer ; offset:LongInt ):Pointer;
inline(
$59/ { POP CX }
$5B/ { POP BX }
$58/ { POP AX }
$5A/ { POP DX }
$29/$c8/ { SUB AX,CX }
$83/$D3/$00/{ ADC BX,0 }
$B1/$03/ { MOV CL,3 }
$D3/$E3/ { SHL BX,CL }
$29/$DA { SUB DX,BX }
);
参照: [Delphi-ML:13257]
0006 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 編集
New/Dispose に Pointer 型のポインタを渡すと。。。
New や Dispose は与えられたポインタの型によって、正しく初期化/解放の処理をしますが、これは、Delphi がコンパイル時にポインタの型情報を隠れた引数としてこれらの関数に与えているからです。
従って、差している先のデータがなんであれ、Dispose はポインタの型を信じ込んでデータの解放を試みます。
すると、次のコードはあっという間にメモリを使い果たします。
var pString1:pString;
pUnknown1:pointer;
i:Integer;
begin
for i:=0 to 2000 do begin
New(pString1);
SetLength(pString1^,10000000);
pUnknown1:=pString1;
Dispose(pUnknown1);
end;
end;
ただし、MemGet/MemFree と同様、ポインタの直接差すメモリブロックのサイズに関しては、Dispose が実行時に取得するため、次のコードは、メモリリークを起こしません。
type
TTest = array [0..1000000] of Double;
pTest = ^TTest;
var
pTest1: pTest;
pUnknown1: pointer;
begin
for i:=0 to 2000 do begin
New(pTest1);
pUnknown1:=pTest1;
Dispose(pUnknown1);
end;
end;
参照: [Delphi-ML:18664] <PASCAL>
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] <Windows>
[新規作成] [最新の情報に更新]
How To
Lounge
KeyWords
Osamu Takeuchi osamu@big.or.jp
Tips
Delphi
Home