トップ回答者
アンマネージdllからレジストリの値が取得できない

質問
-
お世話になります。
既存システムにてアンマネージで作成されたレジストリの値を読み込むhoge.dllがあります。 現在はC#にて開発を行っているので、hoge.dll のメソッドをコールして、レジストリの値を取得しようとしているのですが、うまく取得できません。
hoge.dllは動作実績もあり、アンマネージのテストプロを作成しhoge.dllをコールすると値が取得できるので、マネージプログラムからの呼び出しで何か制限があるのかと思っていますがそれらしい情報が見つかりませんでした。
どなたか、ご存知の方がいましたら教えていただきたいのですが・・・
以下、開発環境&ソースの抜粋です。
WinXP,.NET Framework2.0
Code Snippetpublic class ABC
{
[DllInport("hoge.dll")]
private static extern int GetRegValUnmanage(StringBuilder outVal, int outSize);
public void CallRegVal()
{
StringBuilder outVal = new StringBuilder(128);
int len = GetregValUnmanage(outVal, outVal.Length);
// ↑ lenは0、outValにも何も入っていません
}
}
回答
すべての返信
-
失礼しました。
アンマネージ側は以下のようになっています。
Code Snippet// hoge.h
__declspec(dllexport) int GetRegValUnmanage(LPSTR lpOutVal, int nOutSize);
// hoge.cpp
__declspec(dllexport) int GetRegValUnmanage(LPSTR lpOutVal, int nOutSize)
{
char readVal[128];
// readValにレジストリから値を読み込む
strcpy(lpOutVal, readVal); // レジストリから読み込んだ値をコピー
strcat(lpOutVal, "abc"); // 文字列"abc"を連結
return strlen(lpOutVal);
}
マネージ側から呼び出すと、上記のreadValが何も取得できずに、strcatした”abc”だけが返ってきます。
-
readValにレジストリから値を読み込む
の処理はどこでしょうか?
その処理がうまくいっているのは確認できているのでしょうか?
(DLL側でMessageBoxで表示してみたりして)
呼び出し規約はDLL側で設定していないのでしょうかね?(WINAPIとか__stdcallとか)
デフォルトだと、__cdeclになるんだっけかな?
[DllInport("hoge.dll")]
private static extern int GetRegValUnmanage(StringBuilder outVal, int outSize);
を
Code Snippet[DllImport("hoge.dll",
CharSet=CharSet.Ansi,
CallingConvention=CallingConvention.Cdecl)]
private static extern int GetRegValUnmanage(StringBuilder outVal,
int outSize);
としたらどうなりますか? -
呼び出されたDLLが正常に動作していないということから、
呼び出し規約が一致していない可能性がありそうですね。
CallingConventionを指定しなかった場合はCallingConvention.StdCallになりますが、
VC++でのデフォルトは__cdeclですからDLL側は__cdeclで、C#側でのCallingConventionにCallingConvention.Cdeclを指定する必要があるもしれないです。
ソースとヘッダーの関数宣言に呼び出し規約が書かれていない場合は、
DLLのプロジェクトの呼び出し規約の設定になりますので、念のためそちらも確認してみてください。 -
CallingConventionを指定しなかった場合はCallingConvention.Cdeclになるので、
DllImportAttribute.CallingConvention フィールド
http://msdn2.microsoft.com/ja-jp/library/system.runtime.interopservices.dllimportattribute.callingconvention(VS.80).aspx
より
CallingConvention フィールドの既定値は Winapi です。
とあり、
CallingConvention 列挙体
http://msdn2.microsoft.com/ja-jp/library/system.runtime.interopservices.callingconvention.winapi(VS.80).aspx
より
Winapi
このメンバは実際には呼び出し規約ではありません。代わりに、既定のプラットフォーム呼び出し規約を使用します。たとえば、Windows では StdCall、Windows CE .NET では Cdecl が既定値になります。
とあるのですが、Cdeclになるのでしょうか?
そうすると、WinAPIを使うときには毎回CallingConvention=CallConvention.StdCallが必要になるわけなんですよね?
追記
__stdcall をDLLにつける場合、現在DEFファイルをつかっていないのであれば、使用するか、
C#側でDllImportでEntryPointを指定するか、序数指定にするかどちらかになるでしょう。