喫茶XRAYトップページ

[スレッド全体
]

[12032] Re:PAnsiCharをStrPCopy関数で使用返信 削除
2018/7/11 (水) 11:58:59 Mr.XRAY
> AnsiStrings を追加して明示的に AnsiStrings を

Move 関数を使ってしまう手もあります.
Move 関数を使用する場合は uses に AnsiStrings は不要です.

※ Length(Ansi文字変数) はバイト数を返します.

procedure TForm1.Button3Click(Sender: TObject);
var
  LAnsiString : AnsiString;
  LPAnsiChar  : PAnsiChar;
begin
  LAnsiString := '日本語 ABC 文字列';
  LPAnsiChar  := AllocMem(Length(LAnsiString) + 1);
  try
    Move(LAnsiString[1], LPAnsiChar^, Length(LAnsiString));
    Memo1.Lines.Add(string(LPAnsiChar));
  finally
    FreeMem(LPAnsiChar);
  end;
end;


[12036] Move関数の引数返信 削除
2018/7/12 (木) 06:22:50 Mr.XRAY
Move 関数には引数が 3 つあります.
第 2 の引数はコピー先です.
したがって,変数名を使用する必要があります.
以下の動作確認は Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32 です.

[System.Move - RAD Studio API Documentation]
http://docwiki.embarcadero.com/Libraries/XE5/ja/System.Move


//=============================================================================
//  Move関数
//  第1引数 コピー元
//  第2引数 コピー先
//  第3引数 コピーするバイト数
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
 LAnsiString  : AnsiString;
 LAnsiCharArr : array [0..25] of AnsiChar;
begin
  LAnsiString := '日本語 ABC 文字列';

  FillChar(LAnsiCharArr, Length(LAnsiCharArr), #0);
  Move(LAnsiString[1], LAnsiCharArr, Length(LAnsiString));

  Memo1.Lines.Add(LAnsiCharArr);
end;



[12044] 変数の初期化とメモリ領域の確保返信 削除
2018/7/13 (金) 06:17:50 Mr.XRAY
>   FillChar(LAnsiCharArr, Length(LAnsiCharArr), #0);
>   Move(LAnsiString[1], LAnsiCharArr, Length(LAnsiString));


Move 関数によるコピーでは,コピー先が Char(AnsiChar) 型の静的配列の場合,
FilllChar で #0 (つまり Null 文字) で初期化しないと,
文字列の後ろに文字化けしたような「ゴミ」が付きます.

# 静的配列というのは,変数の定義の時に文字数やバイト数分のメモリ領域を
# 確保する配列のことです.
# 動的配列では SetLength でメモリを確保できます.
# PChar(PAnsiChar) の変数は AllocMem や StrAlloc でメモリ領域を確保します.
# コピー先のメモリ領域が確保されていない状態で Move 関数や StrPCopy 関数を
# 実行すると例外が発生します.

↑ 既に提示したコードで確認してください.


[12045] Re:Move関数の引数返信 削除
2018/7/13 (金) 11:23:57 Mr.XRAY
> したがって,変数名を使用する必要があります.

そうしないと

E2197 変数パラメータに定数オブジェクトを渡すことはできません

というエラーが発生します.以下のコードで実際の現象を確認できます.
簡単なコードです.実際にコーディングして確かめてみることをお勧めします.
記事をみて納得するだけでなく,実際に経験することには大きな意味があります.
「百閧ヘ一見にしかず.百見は一触にしかず」です.


procedure HogeHoge(var Arg1: string);
begin
  ShowMessage(Arg1);
  Arg1 := '日本語';
end;

//=============================================================================
//  E2197 変数パラメータに定数オブジェクトを渡すことはできません
//  のエラーが発生するコード
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  HogeHoge('XYZ');
end;
//=============================================================================
//  E2197 変数パラメータに定数オブジェクトを渡すことはできません
//  のエラーが発生しないコード
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
 LText : string;
begin
  LText := 'XYZ';
  HogeHoge(LText);
  ShowMessage(LText);
end;


[12049] 関数の引数には変数を使用する返信 削除
2018/7/14 (土) 06:49:42 Mr.XRAY
> E2197 変数パラメータに定数オブジェクトを渡すことはできません

StrPCopy や Move 関数は「変数」が指す (アドレスの) メモリ上のデータを
コピーします.したがって,引数には「変数」を使用します.
一般に関数の引数には変数を使用します.
具体的な文字列を渡して,エラーが発生しなくても期待通りの動作とならない
ことがあります.

特に今回の場合,AnsiString あるいは PAnsiChar, AnsiChar であることを
明確にしなければならないのですから尚更です.
具体的な文字列を直接引数に使用できるのは特別な場合と思ってください.


# 最初のレスで終わると思ったのですが (^^;
# う〜む,想定外 ?

# 提示したコードを実際に動作させてみることをお勧めします.
# 見て理解するのと,実際に体験するのとでは脳への記録のされ方が違います.
# どれもフォームに TButton と TMome だけを配置した簡単なプロジェクトです.


[12037] 末尾がWの関数と末尾がAの関数返信 削除
2018/7/12 (木) 06:23:17 Mr.XRAY
Windows API の関数の中には名前が同じで,末尾が W と A のものがあること
があります.
末尾が W の関数は Unicode 版で A は Ansi 版です.
Delphi 2007 以前の非ユニコード版 (Ansi 版) の Delphi で末尾に W も A もない
関数を使用すると自動的に末尾が A の関数が実行されます.
Delphi 2009 以降のユニード版の Delphi で末尾 W も A もない関数を使用すると
自動的に末尾が W の関数が実行されます.

Delphi 2009 以降の Delphi で,引数の型が PChar (PWideChar) に PAnsiChar の
変数を渡すと,

「E2010 'PWideChar' と 'PAnsiChar' には互換性がありません」

というエラーになります.その逆も同じです.
以下はこのことを確認するコードです.
動作確認は Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32 です.

[02-01_使用する Windows API の関数名を決める]
http://mrxray.on.coocan.jp/Delphi/plSamples/480_GetFullExePath.htm#02-01


function HogeHoge(Arg1: PWideChar): Boolean;
begin
  Form1.Memo1.Lines.Add(Arg1);
  Result := True;
end;

//=============================================================================
//  E2010 'PWideChar' と 'PAnsiChar' には互換性がありません
//  のエラーが発生する例
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
 LPAnsiChar : PAnsiChar;
begin
  Form1.Memo1.Lines.Clear;
  LPAnsiChar := '日本語 ABC 文字列';
  HogeHoge(LPAnsiChar);
end;

//=============================================================================
//  こういうキャストは無効
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
 LPAnsiChar : PAnsiChar;
begin
  Form1.Memo1.Lines.Clear;
  LPAnsiChar := '日本語 ABC 文字列';

  HogeHoge(PWideChar(LPAnsiChar));
  HogeHoge(PChar(LPAnsiChar));
end;

//=============================================================================
//  一度String型でキャストすればPCharでキャスト可能
//  Windows API の関数では実際には末尾が W または A の関数を使用する
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
 LPAnsiChar : PAnsiChar;
begin
  Form1.Memo1.Lines.Clear;
  LPAnsiChar := '日本語 ABC 文字列';

  HogeHoge(PWideChar(string(LPAnsiChar)));
end;



[12043] Re:末尾がWの関数と末尾がAの関数返信 削除
2018/7/13 (金) 06:14:51 Mr.XRAY
> 「E2010 'PWideChar' と 'PAnsiChar' には互換性がありません」
>
> というエラーになります.その逆も同じです.


したがって,Delhi 2009 以降で Ansi 文字列を扱う場合は,
引数の型が PAnsiChar である関数を使用します.
引数の型が PAnsiChar である関数とは,関数名の末尾が A の関数のことです.

Ansi 文字列とは,Delphi 2007 以前の文字列のことです.
PChar, string が相当します.
Delphi 2009 以降の PChar, string は Ansi の文字列ではありません.
Unicode の文字列といいます.


[12048] 末尾がAの関数を実行する例返信 削除
2018/7/13 (金) 21:01:58 Mr.XRAY
> したがって,Delhi 2009 以降で Ansi 文字列を扱う場合は,
> 引数の型が PAnsiChar である関数を使用します.


例えば Shellexecute 関数でメモ帳を起動する時,
起動するメモ帳のパス名を PAnsiChar 型の文字列で指定するには以下のようにします.
動作確認は Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32 です.
uses に ShellAPI が必要です.

procedure TForm1.Button1Click(Sender: TObject);
var
  LExePath : AnsiString;
begin
  LExePath := 'notepad.exe';
  ShellExecuteA(0, '', PAnsiChar(LExePath), nil, nil, SW_SHOWNORMAL);
end;


[12059] 末尾がWの関数を実行する例返信 削除
2018/7/17 (火) 06:35:46 Mr.XRAY
ものはついでと言いますから,
逆に末尾が W の関数を使用する例です.
Ansi 版の Delphi で末尾が W の ShellExecute 関数を使用する例です.
動作確認は Windows 7 U32(SP1) + Delphi 6(UP2) Pro です.
uses に ShellAPI が必要です.

implementation

uses
  ShellAPI;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  LExePath : WideString;
begin
  LExePath := 'notepad.exe';
  ShellExecuteW(0, '', PWideChar(LExePath), nil, nil, SW_SHOWNORMAL);
end;

# わずか数行のプログラムですが,変数の型や型キャストをいろいろ変えてテスト
# するといろいろなことが分かります.

こんなところも参考にしてください.
[各種文字列の実際]
https://ht-deko.com/tech018.html


[12047] Ansi->Unicode->Ansi変換返信 削除
2018/7/13 (金) 20:26:03 Mr.XRAY
> //=============================================================================
> //  一度String型でキャストすればPCharでキャスト可能
> //  Windows API の関数では実際には末尾が W または A の関数を使用する
> //=============================================================================
> procedure TForm1.Button3Click(Sender: TObject);
> var
>  LPAnsiChar : PAnsiChar;
> begin
>   Form1.Memo1.Lines.Clear;
>   LPAnsiChar := '日本語 ABC 文字列';
>
>   HogeHoge(PWideChar(string(LPAnsiChar)));
> end;



ただし,以下のことも考慮する必要があります.

[Ansi->Unicode->Ansi変換をやっちゃ駄目ってどういう事?]
https://ht-deko.com/tech013.html#tech039_20


[12038] RS-232Cコンポーネント返信 削除
2018/7/12 (木) 06:23:43 Mr.XRAY
Delphi 6 から Delphi 10 に移行中で,RS-232C 用の CommX を Delphi 10 で
使用可能にするために「苦戦」(失礼 !) されているんですね.

私は RS-232C (COM ポート) の制御はやったことがないのですが,
unicode 版の Delphi で利用可能なコンポーネント類があったと思います.

あったとして,それを使用することになっても,苦戦した内容は今後役に立つと
思ってくださいませ (笑).

例えば
[ [Blog] Delphi / C++Builder RS232cコンポーネント MITライセンス配布版[JAPAN]]
https://ht-deko.com/delphiforum/?vasthtmlaction=viewtopic&t=1865.0

他にも探せばあると思いますが,私は調べていません.あしからず.
検討をお祈りしています.
時間があったら喫茶XRAY にもお立ち寄りくださいませ.
飲み物は自分持ちとなっております (^^)


[12039] Re:RS-232Cコンポーネント返信 削除
2018/7/12 (木) 06:53:37 Mr.XRAY
> 私は RS-232C (COM ポート) の制御はやったことがないのですが,

PC-9801 の時代ならやったことあります (笑)


[12040] Re:RS-232Cコンポーネント返信 削除
2018/7/12 (木) 08:03:17 SO
▼ Mr.XRAYさん

最近、某掲示板にてタイプライブラリのインポートで、
sapi.dllが見つからない??と書かれていたので、
確認のためにStarterインストールしたSOです。

Windows APIのAとWを自動的に切り替えているということは、
プロジェクトの設定にそこらへんの設定があるのではないでしょうか?
ぃゃまぁ、Starterインストールしたから、お家で見てみれば分かるんでしょうけど、
気になってしまいました。。。

# COM通信をするアプリでUnicodeが必要な場面がぱっと思い浮かびません(^^;A

[12041] Re2:RS-232Cコンポーネント返信 削除
2018/7/12 (木) 10:12:17 Mr.XRAY
> 最近、某掲示板にてタイプライブラリのインポートで、
> sapi.dllが見つからない??と書かれていたので、


あの方の場合,単にタイプライブラリの本体が dll ということを知らないだけですね.
インストールの画面の見方も知らないようです (というか知ろうとしていない).
当サイトの記事を見てやってみたということですが,記事通りにやっていないことも
明白ですし.
メールでの質問でも結構この手の質問あります.
「記事の説明通りにやったのにうまくいきません」
というやつです.実際は記事通りにやっていなんですよね.
で訊くと「〇〇は XX したんですが関係ありますか ?」
そういう問題ではないのですね.記事通りというから私は悩んでしまうのですよ.
質問してきた方がどんなコードを実行しているかなんて分かりません.
インターネットの向こう側は見えないのですよ.

> 確認のためにStarterインストールしたSOです。

この姿勢が大切だと思っています.コミュニティの場を質問の場ではなく,
情報源として利用するというか,
私もよくやっていました.
最近あまりやらなくなりました.だんだん気力が (笑)

> Windows APIのAとWを自動的に切り替えているということは、
> プロジェクトの設定にそこらへんの設定があるのではないでしょうか?


私の書き込みは正確ではないです.
そうなるように記述してあるだけですね.Windows.pas でしたっけ.
Delphi で提供していない DLL の関数を使用する時もそうすればいいのでしょうけど
当サイトの記事ではそうはしていないので,明示的に W が必要です.
(ほとんど全てのサンプルが Delphi XE 以降ですので A は不要 !!)
 
> # COM通信をするアプリでUnicodeが必要な場面がぱっと思い浮かびません(^^;A

COM 通信で Unicode が必要というわけではなく,Unicode 版の Delphi で
使用可能にするということではないでしょうか.
CommX は Ansi 版の Delphi で開発されていますから.
ん ? Unicode が必要な場合ってあるのかな ?


[12042] 管理者として実行返信 削除
2018/7/12 (木) 10:28:30 Mr.XRAY
> そういう問題ではないのですね.記事通りというから私は悩んでしまうのですよ.

これで一番印象というか記憶にあるのは今回もありましたが,
Delphi 6, 7 を Windows 7, Windows 10 にインストールするやつです.
「管理者権限」を理解してもらうのに苦労しました.
記憶に残っているのは二人です.
かなりのメールのやりとりで理解して頂き,無事インストールできたということです.
後の方々は分かりせん.
とにかく「自分は管理者権限」で実行していると主張する方がほとんどてした.


[▼次のスレッド]
INCM/CMT
Cyclamen v3.82