[delphi-users:2232] DelphiからC++のAPI呼び出し(EmEditorPlugin)

140 views
Skip to first unread message

Delフサギコ

unread,
Oct 2, 2011, 6:46:47 PM10/2/11
to delphi...@freeml.com
こんにちは。
連投失礼します。

以前にもお聞きした事がありますが、
EmEditorのPluginをDelphiで書いています。
C++との接続の部分でやはりわからない所があり、
メモリ違反のエラーになり落ちてしまいます。

お詳しい方おられましたら教えてください。


EmEditorのレジストリorIniファイル設定を読み取るEmEditorのAPIがあります。

EmEditorのPlugin.hからDelphiソースに移植しています。

コメントアウトしてるのがC++ソース
番号は行番号になります。

環境はDelphiXEです。(LPCWSTR=PWideCharなどが定義済みのようです)

インターフェース部

//plugin.h
//624:typedef struct _REG_QUERY_VALUE_INFO {
//625: size_t cbSize;
//626: DWORD dwKey;
//627: LPCWSTR pszConfig;
//628: LPCWSTR pszValue;
//629: DWORD dwType;
//630: BYTE* lpData;
//631: DWORD* lpcbData;
//632: DWORD dwFlags;
//633:} REG_QUERY_VALUE_INFO;

type _REG_QUERY_VALUE_INFO = record
cbSize: LongWord;
dwKey: DWORD;
pszConfig: PWideChar;
pszValue: PWideChar;
dwType: DWORD;
lpData: PByte;
lpcbData: PDWORD;
dwFlags: DWORD;
end; //REG_QUERY_VALUE_INFO;

REG_QUERY_VALUE_INFO = _REG_QUERY_VALUE_INFO;
TRegQueryValueInfo = _REG_QUERY_VALUE_INFO;
PRegQueryValueInfo = ^TRegQueryValueInfo;

//plugin.h
//374:// v7
//375:#define EEREG_COMMON (0x7fffff00)
//376:#define EEREG_REGIST (0x7fffff01)
//377:#define EEREG_MACROS (0x7fffff02)
//378:#define EEREG_PLUGINS (0x7fffff03)
//379:#define EEREG_RECENT_FILE_LIST (0x7fffff04)
//380:#define EEREG_RECENT_FOLDER_LIST (0x7fffff05)
//381:#define EEREG_RECENT_FONT_LIST (0x7fffff06)
//382:#define EEREG_RECENT_INSERT_LIST (0x7fffff07)
//383:#define EEREG_AUTOSAVE (0x7fffff08)
//384:#define EEREG_LM_COMMON (0x7fffff11)
//385:#define EEREG_LM_REGIST (0x7fffff12)
//386:#define EEREG_CONFIG (0x7fffff20)
//387:#define EEREG_EMEDITORPLUGIN (0x7fffff30)
//388:#define EEREG_EMEDITORUSERS (0x7fffff31)

const EEREG_COMMON = $7fffff00;
const EEREG_REGIST = $7fffff01;
const EEREG_MACROS = $7fffff02;
const EEREG_PLUGINS = $7fffff03;
const EEREG_RECENT_FILE_LIST = $7fffff04;
const EEREG_RECENT_FOLDER_LIST = $7fffff05;
const EEREG_RECENT_FONT_LIST = $7fffff06;
const EEREG_RECENT_INSERT_LIST = $7fffff07;
const EEREG_AUTOSAVE = $7fffff08;
const EEREG_LM_COMMON = $7fffff11;
const EEREG_LM_REGIST = $7fffff12;
const EEREG_CONFIG = $7fffff20;
const EEREG_EMEDITORPLUGIN = $7fffff30;
const EEREG_EMEDITORUSERS = $7fffff31;

function Editor_RegQueryValue(hwnd: THandle; dwKey: DWORD;
pszConfig: LPCWSTR; pszValue: LPCWSTR;
dwType: DWORD; lpData: PByte; lpcbData: PDWORD; dwFlags: DWORD): Boolean;

-----
実装部

//plugin.h
//2007:#define EE_REG_QUERY_VALUE (EE_FIRST+86)
//2008: // (REG_QUERY_VALUE_INFO*)lParam = pRegQueryValueInfo;
//2009:
//2010:inline LONG Editor_RegQueryValue( HWND hwnd, DWORD dwKey,
LPCWSTR pszConfig, LPCWSTR pszValue, DWORD dwType, BYTE* lpData,
DWORD* lpcbData, DWORD dwFlags )
//2011:{
//2012: _ASSERT( hwnd && IsWindow( hwnd ) );
//2013: REG_QUERY_VALUE_INFO info = { 0 };
//2014: info.cbSize = sizeof( info );
//2015: info.dwKey = dwKey;
//2016: info.pszConfig = pszConfig;
//2017: info.pszValue = pszValue;
//2018: info.dwType = dwType;
//2019: info.lpData = lpData;
//2020: info.lpcbData = lpcbData;
//2021: info.dwFlags = dwFlags;
//2022: return (LONG)SNDMSG( (hwnd), EE_REG_QUERY_VALUE, 0, (LPARAM)&info );
//2023:}

const EE_REG_QUERY_VALUE = (EE_FIRST+86);

function Editor_RegQueryValue(hwnd: THandle; dwKey: DWORD;
pszConfig: LPCWSTR; pszValue: LPCWSTR;
dwType: DWORD; lpData: PByte; lpcbData: PDWORD; dwFlags: DWORD): Boolean;
var
info: TRegQueryValueInfo;
begin
info.cbSize := SizeOf( info );
info.dwKey := dwKey;
info.pszConfig := pszConfig;
info.pszValue := pszValue;
info.dwType := dwType;
info.lpData := lpData;
info.lpcbData := lpcbData;
info.dwFlags := dwFlags;
Result := BOOL( SendMessage(hwnd, EE_REG_QUERY_VALUE, 0, LPARAM(@info) ) );
end;

-----
呼び出し

function RegReadPluginFolderPath(hwnd: HWND): WideString;
var
Size: Integer;
PBuffer: PByte;
begin
SetLength(Result, 100);
PBuffer := @Result;
Editor_RegQueryValue(hwnd, EEREG_COMMON, '', 'PlugInsFolder',
REG_SZ, PBuffer, @Size, 0);
Result := WideString(PBuffer);
end;


DelphiXEなので、WideStringを使わなくてもいいのですが
なんとなく、以前のバージョンからの移植が済んでいないので
このように書いていますが、

これがメモリアクセス違反になってしまいます。

PBufferや@Sizeの指定のどこかが何か間違っているのですが
どの様に指定すればよいのかがわかりません。

該当のEmEditorのヘルプは次のURLです。
http://jp.emeditor.com/help/plugin/structure/reg_query_value_info.htm


どこか間違っているか、おわかりになる方
教えていただけると幸いです。

長いソースですいません。
どのあたりの段階で間違っているのか不明だったので掲載させてもらいました。

よろしくお願いします。


--
Delフサギコ ミ・д・彡 <delfu...@gmail.com>


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
メールだけでみんなを招待できる便利機能♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=huCKu
-----------------------------------------------------[freeml by GMO]--

auemura

unread,
Oct 3, 2011, 12:45:05 AM10/3/11
to delphi...@freeml.com
> -----
> 呼び出し
>
> function RegReadPluginFolderPath(hwnd: HWND): WideString;
> var
> Size: Integer;
> PBuffer: PByte;
> begin
> SetLength(Result, 100);
> PBuffer := @Result;
> Editor_RegQueryValue(hwnd, EEREG_COMMON, '''', ''PlugInsFolder'',
> REG_SZ, PBuffer, @Size, 0);
> Result := WideString(PBuffer);
> end;

上村です。
定義の方は問題なさそうに見えますが、PBufferがまずんじゃないかと。

function RegReadPluginFolderPath(hwnd: HWND): WideString;
var
Size: Integer;

Buffer: TBytes;
begin
SetLength(Buffer, 100);


Editor_RegQueryValue(hwnd, EEREG_COMMON, '''', ''PlugInsFolder'',

REG_SZ, Buffer[0], @Size, 0);
Result := TEncoding.UNICODE.GetString(Buffer);
end;

こんな感じでどうでしょう?

MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
クーポンサイトを選んで検索♪一番おトクなクーポンをGET!
http://ad.freeml.com/cgi-bin/sa.cgi?id=huIf3

Fukushi

unread,
Oct 4, 2011, 1:49:39 AM10/4/11
to delphi...@freeml.com
Delフサギコさん、こんにちは。福士です。

> EmEditorのPluginをDelphiで書いています。
> C++との接続の部分でやはりわからない所があり、
> メモリ違反のエラーになり落ちてしまいます。

全く詳しくないのですが、

> function RegReadPluginFolderPath(hwnd: HWND): WideString;
> var
> Size: Integer;
> PBuffer: PByte;
> begin
> SetLength(Result, 100);
> PBuffer := @Result;
> Editor_RegQueryValue(hwnd, EEREG_COMMON, '', 'PlugInsFolder',
> REG_SZ, PBuffer, @Size, 0);
> Result := WideString(PBuffer);
> end;

でSizeにはPBufferの指す領域のバイト数200(もしくは文字数100)を
格納する必要があるのではないかという気がします。あとは関数の
定義の呼び出し規約が一致しているかどうかも確認してみては
いかがでしょう。呼び出し規約が正しく指定されていないと関数の
呼び出しから戻れないとか、関数の呼び出しから戻った直後に
アクセスバイオレーションでエラーになるとか、そういう状況に
なります。

---
東洋テクニカルシステム株式会社 システム開発部 福士 光
Hikaru Fukushi (Toyo Technical System Inc.)
mailto:fuk...@tts-inc.co.jp


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
クーポンサイトを選んで検索♪一番おトクなクーポンをGET!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hvaXQ

Delフサギコ

unread,
Oct 13, 2011, 9:37:08 AM10/13/11
to delphi...@freeml.com
すさまじく遅いお返事になってしまいました。

こちらのコードですとエラーになってしまいました。

function RegReadPluginFolderPath(hwnd: HWND): WideString;
var
Size: Integer;
Buffer: TBytes;
begin
SetLength(Buffer, 100);
Editor_RegQueryValue(hwnd, EEREG_COMMON, '', 'PlugInsFolder',
REG_SZ, Buffer[0], @Size, 0);

Result := TEncoding.UNICODE.GetString(Buffer);
end;

[DCC エラー] : E2010 'PByte' と 'Byte' には互換性がありません
Buffer[0]がポインタにならないようですね。

定義が、
TBytes - SysUtils.TArray<System.Byte>
TArray<T> = array of T;
このようになっていました。

Editor_RegQueryValue(hwnd, EEREG_COMMON, '', 'PlugInsFolder',

REG_SZ, PByte(Buffer), @Size, 0);

このように変えてもエラーはなくなりましたが、
動かしてみると
Editor_RegQueryValueの内部で行っている
Result := BOOL(SendMessage…
の戻り値もFalseになってきます。

念のため、こちらも載せておきます。
const EE_REG_QUERY_VALUE = (EE_FIRST+86);

function Editor_RegQueryValue(hwnd: THandle; dwKey: DWORD;
pszConfig: LPCWSTR; pszValue: LPCWSTR;
dwType: DWORD; lpData: PByte; lpcbData: PDWORD; dwFlags: DWORD): Boolean;
var
info: TRegQueryValueInfo;
begin
info.cbSize := SizeOf( info );
info.dwKey := dwKey;
info.pszConfig := pszConfig;
info.pszValue := pszValue;
info.dwType := dwType;
info.lpData := lpData;
info.lpcbData := lpcbData;
info.dwFlags := dwFlags;
Result := BOOL( SendMessage(hwnd, EE_REG_QUERY_VALUE, 0, LPARAM(@info) ) );
end;

ちょっとした間違いのような気がするのですが
こういう実装になるととたんに難しく感じます。

よろしければおわかりになる方、よろしくお願いします。


--
Delフサギコ ミ・д・彡 <delfu...@gmail.com>


> 送信者 auemura <delphi...@freeml.com>
> 宛先 delphi...@freeml.com
> 日時 2011/10/03 13:45:07
> 件名 [delphi-users:2234] Re:DelphiからC++のAPI呼び出し(EmEditorPlugin)
> ----


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
使い方はいろいろ♪一部のメンバーだけにMLメールを送ろう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hx97Z

auemura

unread,
Oct 13, 2011, 7:03:58 PM10/13/11
to delphi...@freeml.com
>
> function RegReadPluginFolderPath(hwnd: HWND): WideString;
> var
> Size: Integer;
> Buffer: TBytes;
> begin
> SetLength(Buffer, 100);
> Editor_RegQueryValue(hwnd, EEREG_COMMON, '''', ''PlugInsFolder'',
> REG_SZ, Buffer[0], @Size, 0);
> Result := TEncoding.UNICODE.GetString(Buffer);
> end;
>
すいません。@が抜けてましたね。

Editor_RegQueryValue(hwnd, EEREG_COMMON, '''', ''PlugInsFolder'',

REG_SZ, @Buffer[0], @Size, 0);

でどうでしょう?。
福士さんが言われてるように、バッファのサイズを渡す部分がないのが気になるっちゃ気になりますが。リンク先のヘルプを見ても渡す変数はなさそうですしね。

MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
クーポンサイトを選んで検索♪一番おトクなクーポンをGET!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hxCLC

Delフサギコ

unread,
Oct 14, 2011, 12:13:35 AM10/14/11
to delphi...@freeml.com
上村さん、ありがとうございます。

うーん、シングルクウォートを修正して
このようにしましたが、


Editor_RegQueryValue(hwnd, EEREG_COMMON, '', 'PlugInsFolder',
REG_SZ, @Buffer[0], @Size, 0);

コンパイルは通りますが
#0#0#0#0の連続が取得されるだけで何も得られないです。

何が悪いんだろうか。

ちょっとした事なのに、全然解決しない現象は
途方に暮れますわ…


--
Delフサギコ ミ・д・彡 <delfu...@gmail.com>


> 送信者 auemura <delphi...@freeml.com>
> 宛先 delphi...@freeml.com

> 日時 2011/10/14 8:04:00
> 件名 [delphi-users:2262] Re: DelphiからC++のAPI呼び出し(EmEditorPlugin)
> ----


> >
> > function RegReadPluginFolderPath(hwnd: HWND): WideString;
> > var
> > Size: Integer;
> > Buffer: TBytes;
> > begin
> > SetLength(Buffer, 100);
> > Editor_RegQueryValue(hwnd, EEREG_COMMON, '''', ''PlugInsFolder'',
> > REG_SZ, Buffer[0], @Size, 0);
> > Result := TEncoding.UNICODE.GetString(Buffer);
> > end;
> >
> すいません。@が抜けてましたね。
>
> Editor_RegQueryValue(hwnd, EEREG_COMMON, '''', ''PlugInsFolder'',
> REG_SZ, @Buffer[0], @Size, 0);
>
> でどうでしょう?。
> 福士さんが言われてるように、バッファのサイズを渡す部分がないのが気になるっちゃ気になりますが。リンク先のヘルプを見ても渡す変数はなさそうですしね。
>


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
友達の服をこっそり借りちゃお!「おしゃれ泥棒」
http://ad.freeml.com/cgi-bin/sa.cgi?id=hxHHT

umez

unread,
Oct 14, 2011, 12:34:19 AM10/14/11
to delphi...@freeml.com
こんにちは、梅澤@プロキャストです。

ふと思っただけなので、たぶん外してますが...

Editor_RegQueryValue() を呼び出す前に、Size を バッファサイズで
初期化しておく必要があるのではないでしょうか。

Editor_RegQueryValue呼び出し前のSize: 渡すバッファのサイズ

Editor_RegQueryValue呼び出し後のSize: バッファに書かれたサイズ


Delフサギコ <delphi...@freeml.com> さんは書きました。<2011/10/14>


----------
Tomomi Umezawa um...@procast.co.jp


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
戦国時代の武将達とともに天下統一を目指そう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hxIcl

Fukushi

unread,
Oct 14, 2011, 12:36:01 AM10/14/11
to delphi...@freeml.com
Delフサギコさん、こんにちは。福士です。

EmEditor プラグイン リファレンス: REG_QUERY_VALUE_INFO
http://jp.emeditor.com/help/plugin/structure/reg_query_value_info.htm

によると、lpcbDataは

> lpData パラメータで指定されたバッファのサイズをバイト数で
> 指定する変数へのポインタです。関数から戻ると、この変数には
> lpData に保存されたデータのサイズを保存します。

とありますので、

function RegReadPluginFolderPath(hwnd: HWND): WideString;
var

Size: DWORD;
begin
Size := 100;
SetLength(Result, Size div SizeOf(WideChar));
Editor_RegQueryValue(hwnd, EEREG_COMMON, nil, 'PlugInsFolder',
REG_SZ, @PWideChar(Result)^, @Size, 0);
SetLength(Result, Size div SizeOf(WideChar));
end;

でどうでしょう?

---
東洋テクニカルシステム株式会社 システム開発部 福士 光
Hikaru Fukushi (Toyo Technical System Inc.)
mailto:fuk...@tts-inc.co.jp


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
「アルテイル」オンラインカードゲームで暇つぶし!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hxIdT

Delフサギコ

unread,
Oct 14, 2011, 11:41:04 AM10/14/11
to delphi...@freeml.com
ありがとうございます。

上村さんの方法でも、福士さんの方法でも取得できました。
梅澤さんのおっしゃる通りですね。
呼び出しの作法がよくわかっていませんでした。
すごく、ありがとうございます。

デイリービルドは君の友達 - The Joel on Software Translation Project
http://local.joelonsoftware.com/wiki/デイリービルドは君の友達
に載っている、Turbo Pascalで飛躍的に生産性のあがるような
事とは真逆に、

ソースコード書いていただき
それを私が動かしているという、Edit-Compile-Testループが異様に遅い中、
力を貸していただいて、
動かせないのにソースの細かい所まで見ていただき
ほんと助かります。

動作コードは、下記のコードになります。

戻り値に#0を含む文字が入ってくるのでサイズ指定ではなく
WideString(PWideChar(戻り値の文字))
という実装にしました。

function RegReadPluginFolderPath(hwnd: HWND): WideString;
var

Size: Integer;
Buffer: TBytes;
begin
Size := 100;
SetLength(Buffer, Size);


Editor_RegQueryValue(hwnd, EEREG_COMMON, '', 'PlugInsFolder',
REG_SZ, @Buffer[0], @Size, 0);

Result := WideString(PWideChar(TEncoding.UNICODE.GetString(Buffer)));
end;

function RegReadPluginFolderPath(hwnd: HWND): WideString;
var
Size: DWORD;
begin
Size := 100;
SetLength(Result, Size div SizeOf(WideChar));
Editor_RegQueryValue(hwnd, EEREG_COMMON, nil, 'PlugInsFolder',
REG_SZ, @PWideChar(Result)^, @Size, 0);

// SetLength(Result, Size div SizeOf(WideChar));
Result := WideString(PWideChar(Result));
end;

1点、疑問が残りますが
福士さんの指定していただいているResultのサイズでは
SizeOf(WideChar)は、2バイトなので2になり
100/2の50が指定されることになりますが
これはこれでいいものなのでしょうか?

ファイルパスのサイズなので
適度な長さがあれば実際には全く問題にはならないのですが
ちょっと気になりました。
理由があれば教えてください。
理解力が乏しくてすいませんです。

よろしくお願いします。

--
Delフサギコ ミ・д・彡 <delfu...@gmail.com>


> 送信者 Fukushi <delphi...@freeml.com>
> 宛先 delphi...@freeml.com
> 日時 2011/10/14 13:36:03
> 件名 [delphi-users:2265] Re: DelphiからC++のAPI呼び出し(EmEditorPlugin)
> ----


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
練習や試合の予定調整は「とっとと決め太郎」におまかせ!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hxUxc

Fukushi

unread,
Oct 16, 2011, 9:37:30 PM10/16/11
to delphi...@freeml.com
Delフサギコさん、こんにちは。福士です。

> 1点、疑問が残りますが
> 福士さんの指定していただいているResultのサイズでは
> SizeOf(WideChar)は、2バイトなので2になり
> 100/2の50が指定されることになりますが
> これはこれでいいものなのでしょうか?

最初のソースが100バイト(50文字)となっていたから、だけなの
ですが、パス名であれば

Size := MAX_PATH * 2;

とするのがいいと思います。ただしこれは本来何らかの方法で
バッファサイズを取得できるようになっているべきでしょう
(EmEditorの仕様なのでここで文句をいっても仕方がありませんが)。

# 普通Win32APIではバッファアドレス=NULL、バッファサイズ=0を
# 指定するとバッファサイズに必要サイズが入って戻ってくる、
# というようになっていますよね?

---
東洋テクニカルシステム株式会社 システム開発部 福士 光
Hikaru Fukushi (Toyo Technical System Inc.)
mailto:fuk...@tts-inc.co.jp


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
練習や試合の予定調整は「とっとと決め太郎」におまかせ!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hy03l

Reply all
Reply to author
Forward
0 new messages