DLL 関数の作成No.08058
ひろ さん 01/03/18 20:51
 
 皆さん今日は、ひろです。
 秀丸マクロ用の DLL を作成しようと思っているのですが、同じソースファ
イルから作成しているにも関わらず、gcc で作成した場合、DLL の読み込み
つまり loaddll の時点でエラーにり、Borland C++ freecompiler の場合、
loaddll 自体は成功するものの、dllfunc による呼び出し時点で、「dllfunc
関数で指定された呼び出し先が見つからない」となってしまいます。

 後者については私の作成時報じたいが悪ののかもしれませんが、ひょっと
して DLL 関数の作成は処理系は VC でなければならないなど、制約がある
のでしょうか?

[ ]
RE:08058 DLL 関数の作成No.08059
える さん 01/03/18 22:42
 
> ひょっとして DLL 関数の作成は処理系は VC でなければならないなど、
> 制約があるのでしょうか?

そーいう変な制約はないようですよ。

[ ]
RE:08059 DLL 関数の作成No.08060
でるもんた さん 01/03/19 00:06
 
> > ひょっとして DLL 関数の作成は処理系は VC でなければならないなど、
> > 制約があるのでしょうか?
>
> そーいう変な制約はないようですよ。

ただ、VC と BC とでは関数呼び出しのときの規約が微妙に異なるので相互の
呼び出しができないことがある、ということを聞いたことがあります。

たしか、BC では呼び出された関数の中で EBX レジスタの内容を破壊しても
いいんだけど、VC では EBX が保存されることを期待しているので、BC で作った
DLL を VC から呼ぶと、帰ってきたときには EBX が腐っているということになる
が、VC で作った DLL を BC で呼ぶのは問題ない(もしかしたら VC と BC が
逆だったかも)とのことです。

[ ]
RE:08058 DLL 関数の作成No.08061
杉浦 まさき さん 01/03/19 00:41
 
ひろさん、こんばんは。
杉浦 まさき です。

> 秀丸マクロ用の DLL を作成しようと思っているのですが、同じソースファ
>イルから作成しているにも関わらず、gcc で作成した場合、DLL の読み込み
>つまり loaddll の時点でエラーにり、Borland C++ freecompiler の場合、
>loaddll 自体は成功するものの、dllfunc による呼び出し時点で、「dllfunc
>関数で指定された呼び出し先が見つからない」となってしまいます。

後者はわからないですが、前者は cygwin gcc で
以下のようにしたらできました。

gcc -Wall -mwindows -shared -o foo.dll foo.c
          ^^^^^^^
        これがミソらしい(^^;

foo.c:
#include <w32api/windows.h>
#include <stdlib.h>
/* DLL エントリポイント(WINAPI == __stdcall 修飾子が必須) */
int WINAPI DllMain(HINSTANCE hInst, DWORD ul, LPVOID ptr)
{ return TRUE; }
/* export する関数 */
__declspec(dllexport) int foo(const char* str)
{ return atoi(str); }

#cygwin dll の関数をDLL内で使う場合についての注意等は
 http://cygwin.com/faq/ を参照してください。


[ ]
RE:08060 DLL 関数の作成No.08062
える さん 01/03/19 11:03
 
>が、VC で作った DLL を BC で呼ぶのは問題ない(もしかしたら VC と BC が
>逆だったかも)とのことです。

逆ですね。

Visual C/C++ では EBX レジスタは関数ローカルになっていて、
Borland 系では関数ローカルになっていません。

このため、Borland 系のコンパイラが作成した関数は関数プロロー
グで EBX を退避し、エピローグで EBX レジスタの値を復旧します。

これに対して Visual C/C++ は関数の呼び出し側が EBX を退避し
関数を呼び出し、関数からの呼び出しが完了したのちに EBX を復
旧するため、Visual C/C++ の生成した関数は呼び出し元の EBX
レジスタを破壊します。

ということで、Borland 系の実装から、Visual C/C++ の cdecl の
関数を呼び出すと、EBX 問題が発生します。
ただ、これが発現して問題になるのは、.o (.obj) ファイルを直接
リンクした場合だけです。
DLL を介した呼び出しではこの問題は発生しません。

[ ]
RE:08058 DLL 関数の作成No.08063
える さん 01/03/19 11:07
 
>loaddll 自体は成功するものの、dllfunc による呼び出し時点で、「dllfunc
>関数で指定された呼び出し先が見つからない」となってしまいます。

とりあえず、DLL から export された関数の名前が間違っているの
ではないですか?

秀丸のマクロ用の DLL の場合、

extern "C" /* C 言語名称 */
int /* int か char * */
WINAPIV /* 呼び出し規約 (WINAPI ではない) */
func(...);

という形式にしてある必要があります。
.def ファイルを作らないと _ が名前についているかも。

[ ]
RE:08061 DLL 関数の作成No.08064
ENCODINGSHIFTJIS さん 01/03/19 12:05
 
どちらかで動くと思います、

// testdll2.mac
// >gcc -Wall -mno-cygwin -mwindows -shared -o test.dll testdll.c

loaddll "TEST.dll";// hidemarudir  ファイル名は大文字小文字区別ナシ
if(!result){message "load error";endmacro}
menu str(dllfunc("foo","989898"));//   関数名は大文字小文字区別ある
                                 // VBはない JavaScriptはある
freedll

// ------------- BCC の場合
//
// >BCC32 -WD -P- -etest.dll testdll.c

// foo.c:
// #include <windows.h>
// #include <stdlib.h>
// /* export する関数 */
//  int WINAPI __declspec(dllexport) foo(const char* str)
// { return atoi(str); }

//  WinMain DllFunc はお世話してくれている、のかな ?


[ ]
RE:08064 DLL 関数の作成No.08065
える さん 01/03/19 13:13
 
>// /* export する関数 */
>//  int WINAPI __declspec(dllexport) foo(const char* str)

これはコメント? 実際のコード?

秀丸は CDECL を期待しているので WINAPI で宣言しては
ダメです、WINAPIV で宣言しましょう。

WINAPI で宣言していると stack under flow で秀丸ごと飛びます。

[ ]
RE:08062 DLL 関数の作成No.08066
ひろ さん 01/03/19 13:14
 
 えるさん、でるもんたさん、杉浦さん、ENCODINGSHIFTJIS さん今日は、ひろです。
 色々有り難うございます。
 BCC に関しては、WINAPI の宣言が抜けていました(^^;。

 また gcc については、Cygnus Solutions が開発している GNU-Win32 の
簡易版であるMingw32 を利用しているのですが、
> gcc -Wall -mwindows -shared -o foo.dll foo.c
このオプションは無いようです(;_;)。やはり簡易版だからかあ〜。

[ ]
RE:08065 DLL 関数の作成No.08068
ENCODINGSHIFTJIS さん 01/03/19 18:27
 
>WINAPI で宣言していると stack under flow で秀丸ごと飛びます。

C・C++を使わないので私はわかりません、2変数の引数でもうまくいっていますし。
WINAPI を付けないとexportしてくれないようだ?
 freeのBCCでは(去年のダウンロード)

マクロ展開の内容、コンパイラオプション、DLLの初期部、リンカーの動作
どれも解説できません。困ったもんだ  m(・τ・)m ??

[ ]
RE:08065 DLL 関数の作成No.08070
杉浦 まさき さん 01/03/20 00:45
 
えるさん、こんばんは。
杉浦 まさき です。

>秀丸は CDECL を期待しているので WINAPI で宣言しては
>ダメです、WINAPIV で宣言しましょう。

DllMain 「だけ」は WINAPI で…ということを強調したつもり
だったんですが、ちょっと誤解を招く書き方になってしまった
ようですね。誤解した方、ごめんなさいm(_ _)m。

#WINAPIV …こんなマクロがあるなんて昨日初めて知りました(^^;。


[ ]
RE:08066 DLL 関数の作成No.08071
ひろ さん 01/03/20 00:58
 
 みなさん今日は、ひろです。自己レスです。
>  また gcc については、Cygnus Solutions が開発している GNU-Win32 の
> 簡易版であるMingw32 を利用しているのですが、
> > gcc -Wall -mwindows -shared -o foo.dll foo.c
> このオプションは無いようです(;_;)。やはり簡易版だからかあ〜。
 これは間違いでは有りませんが、この −share に当たる機能がありまし
た。具体的には DLL 作成時に通常使う dlltool.exe を使わず dllwrap.exe
を使うということだけでした。

 未だに「fuufunc で指定された...。」のエラーはでますが...。

[ ]
RE:08068 DLL 関数の作成No.08084
える さん 01/03/20 21:10
 
>C・C++を使わないので私はわかりません、2変数の引数でもうまくいっていますし。

何がうまくいってるんでしょう?
stack の確認をして問題は発生していない、ということでしょうか?

stack の操作ミスは関数の呼び出し直後に何かが目に見えて発生するわけではないの
で、「うまくいっている」ことを確認するのは相当面倒なはずです。

>WINAPI を付けないとexportしてくれないようだ?

WINAPI の一般的な宣言では、そういった症状が発生することはないでしょう、WINAP
I をつけたことで export を行うか行わないかは変更されません。

export される関数は WINAPI があってもなくても export されますし、export され
ない関数は WINAPI があってもなくても export されません。

> freeのBCCでは(去年のダウンロード)

BCC では...? 続きがないので何か書くつもりでかかれてないのだと
思いますが、BCC では export の on/off は declspec を用います。
単純な関数の例だと、

--foo.c--
#include <windows.h>
int __declspec(dllexport) WINAPIV foo(int n)
{
  return n;
}

--foo.def--
LIBRARY FOO.DLL
EXPORTS
  FOO

--commandline--
bcc32 -c -d -u- -5 -O foo.c
ilink32 -x c0d32.obj foo.obj,foo.dll,,cw32mti.lib import32.lib,foo.def

--macro--
loaddll "foo.dll";
if (!result) endmacro;

#a = dllfunc("foo", 3);
message str(#a);
freedll;

という感じでしょう。(bcc インストールしてないのでテストしてない)

[ ]
RE:08071 DLL 関数の作成No.08085
杉浦 まさき さん 01/03/20 23:26
 
ひろさん、こんばんは。
杉浦 まさき です。

> 未だに「fuufunc で指定された...。」のエラーはでますが...。

えるさんも指摘されておられましたが、C++ で書いた関数なら
以下のように extern "C" が必要ですけど、
そういう問題ではないのかも??

// foo.cpp

// こっちは dllfunc("foo") では呼び出せない(はず)
__declspec(dllexport) int __cdecl foo();
// こっちは dllfunc("foo") でOK
extern "C" __declspec(dllexport) int __cdecl foo();


[ ]
RE:08084 DLL 関数の作成No.08086
ENCODINGSHIFTJIS さん 01/03/21 11:26
 
>--commandline--
>bcc32 -c -d -u- -5 -O foo.c
>ilink32 -x c0d32.obj foo.obj,foo.dll,,cw32mti.lib import32.lib,foo.def

ilink32 -Tpd -x c0d32.obj foo.obj,foo.dll,,cw32.lib import32.lib,foo.def
でうまくゆきました、+出力タイプの指定
ソース、コンパイルオプション、リンカーオプション、モジュール定義など
関係よくわからないです。 BCC32 -WD foo.c のような簡易指定で済んで
しまうこともあるし。call stack の引数積み上げ、巻き戻し動作は??




[ ]
RE:08085 DLL 関数の作成No.08087
える さん 01/03/21 11:30
 
>// こっちは dllfunc("foo") でOK
>extern "C" __declspec(dllexport) int __cdecl foo();

8063 でも書きましたけど、C-DECL の修飾規則では、パブリックシンボルには _ を
付与するので、dllfunc("_foo") になったりしません?
だから、.def ファイルを作成して実行イメージの内部名と DLL のインターフェスに
公開される外部名の対応をとってあげないとダメなんじゃないかと。

8084 の例では BCC のコンパイルオプション -u- で _ の付与を禁止してみました。
これでも大丈夫のはず。

[ ]
RE:08085 DLL 関数の作成No.08088
ひろ さん 01/03/21 11:53
 
 杉浦 まさきさん今日は、ひろです。
> えるさんも指摘されておられましたが、C++ で書いた関数なら
> 以下のように extern "C" が必要ですけど、
> そういう問題ではないのかも??
 わざわざ有り難うございます。extern "C" は付けてあったのですが、リ
ンク時 (だと思う) に *.def を指定していないのが原因でした(^^;。コン
パイラのヘルプにはでてこないので、見落としていました。

[ ]
RE:08086 DLL 関数の作成No.08090
ENCODINGSHIFTJIS さん 01/03/21 13:29
 
今回では、自動処理に頼った最小の形は
>BCC32 -WD -u- foo.c
でした。 FOO.DEF は不要
>IMPDEF foo.def foo.dll
dll から  def  を作る BCC util では できてました
LIBRARY     FOO.DLL
EXPORTS
    ___CPPdebugHook                @2   ; ___CPPdebugHook
    foo                            @1   ; foo

[ ]
RE:08087 DLL 関数の作成No.08096
杉浦 まさき さん 01/03/22 00:00
 
えるさん、こんばんは。
杉浦 まさき です。

>8063 でも書きましたけど、C-DECL の修飾規則では、
>パブリックシンボルには _ を付与するので、
>dllfunc("_foo") になったりしません?
>だから、.def ファイルを作成して実行イメージの内部名と
> DLL のインターフェスに公開される外部名の対応を
>とってあげないとダメなんじゃないかと。

また(^^;やってしまった…と思ってテストしてみましたが、
cygwin gcc の環境で作成したものは __cdecl をつけても
そのまま dllfunc("test") で呼び出せました。
クイックビューアで export テーブルを見ても、
ちゃんと "test" で export されています。

また、*.def は手では作っていませんが、
多分リンカ内部で処理されているのではないでしょうか。
#そのための -shared オプション…なのかな??
#どうでもいいですが、このオプション、gcc --help では
 でてこない?ですね(僕は cygwin の FAQ ページで見ました)。


[ ]
RE:08096 DLL 関数の作成No.08097
杉浦 まさき さん 01/03/22 00:36
 
ども、再び杉浦です。

突っ込まれる前に(^^;…

> また、*.def は手では作っていませんが、
> 多分リンカ内部で処理されているのではないでしょうか。
   ^^^^^^
コンパイラとリンカ、ですね、多分(^^;。
#__declspec(dllexport) を解釈するのは
 コンパイラしかいないですから。

蛇足ですが、VC++ でも __declspec(dllexport) をつけておけば、
*.def を手で作る必要はないようです。<一般的な話かも??

>#そのための -shared オプション…なのかな??

これは単に DLL を作るためのおまじない、です。
#他にも -mdll というオプションがあるんですが、
 こっちもヘルプを見ると DLL を作るためのオプションらしい…
 ですが、これだと(*.def なしで) export テーブルに
 名前が登録されなかったし、使い方がイマイチ分からないです。
 (*.def ありの場合は試してません)


[ ]
RE:08096 DLL 関数の作成No.08099
ひろ さん 01/03/22 12:30
 
 杉浦今日は、ひろです。
 私の発言が元で分岐したこちらのスレッドは、完全にマクロから離れてしまっている
ようですね(^^;。
> #そのための -shared オプション…なのかな??
> #どうでもいいですが、このオプション、gcc --help では
 GUN の作品は --help オプションの表示は、実際の物と比べると送れる傾
向がありますね。man ページも遅れるので、info ファイルを見るのが確実
のようです。ただ cygwin に含まれているのかしら???

> #他にも -mdll というオプションがあるんですが、
>  こっちもヘルプを見ると DLL を作るためのオプションらしい…
>  ですが、これだと(*.def なしで) export テーブルに
 私か使っているツールはこの −mdll オプションを使っているために、
__declspec(dllexport) を付けても登録されなかったようです。→これでスッ
キリした(^^)。

[ ]