今だけ人気マンガ100円♪夏の100円レンタル祭り♪

仕事上今まで蓄積されているFortranプログラムを効率よく使いたくDLL,VB,VBAにチャレンジしていますが,
Intel(R) Fortran Compiler9.0で作成したDLLをEXCELのVBAからCALLしたところ 実行時エラー'49' DLLが正しく呼び出せません のエラーが表示されました。 このDLLはVisual Basic .NETで作成したVBからは正しくCALLできています。 色々原因を調べているのですがVBAからDLLの呼び出しとDLL内の計算は正しく行われておりDLLからVBAに戻るときにエラーになっているようです。

テストを行っているFortranとVBAのソースは以下です。VBAでDLLをCALL出来るように解決いたしたくご教授願お願いいたします。

(1)---- Fortran ソース ---------------------------
subroutine DLL1(Q,QQ,QQQ)
! Expose subroutine DLL1 to users of this DLL
!
!DEC$ ATTRIBUTES DLLEXPORT::DLL1
!DEC$ ATTRIBUTES ALIAS:'DLL1'::DLL1
! Variables
! Body of DLL1
real*4 Q,QQ,QQQ
QQ = Q*2
QQQ = Q**3
end subroutine DLL1

(2)----------- VBA ソース --------------------
Private Q As Single
Private QQ As Single
Private QQQ As Single
Declare Sub DLL1 Lib "DLL1.dll" (ByRef Q As Single, ByRef QQ As Single, ByRef QQQ As Single)

Sub Macro1()
ChDrive ActiveWorkbook.Path
ChDir ActiveWorkbook.Path
Q = 2#
Call DLL1(Q, QQ, QQQ)
Cells(5, 2) = Format(Q, "#####.#0")
Cells(6, 2) = Format(QQ, "#####.#0")
Cells(7, 2) = Format(QQQ, "#####.#0")
End Sub

このQ&Aに関連する最新のQ&A

A 回答 (9件)

#3, #4 です。


あまり意図が伝わらなかったようなので、再度。
dllは、作成する時点で、呼び出し規約が確定し
VB.NETは、cdecl 呼び出し規約用に作成されたdllを扱えますが
VBAは、stdcall 呼び出し規約用に作成されたdllしか扱えません。

すなわち、VB.NETで動いたからVBAで動くとは必ずしもいえない
ということです。

そこで、私自身は、Fortranは扱ったことがありませんが、
#4のサイトに従えば、
!DEC$ ATTRIBUTES DLLEXPORT::DLL1
!DEC$ ATTRIBUTES ALIAS:'DLL1'::DLL1

!DEC$ ATTRIBUTES DLLEXPORT,STDCALL::DLL1
!DEC$ ATTRIBUTES ALIAS:'DLL1'::DLL1
にして、dllをリコンパイルすれば、stdcall呼び出し規約用dllとして
コンパイルできるので、使えるだろうということです。

この回答への補足

回答ありがとうございました。
教えていただいたHPアクセスして内容確認したのですが理解不足でした。

新たなご指摘どおりの修正でDLLをCALLすることができました。
ものすごく前進しました。ただ、QQとQQQに結果が返ってきていません。DLLの処理ではQQは4.0、QQQは8.0が戻されるはずですがVBAで呼出し語確認したところ初期設定された値のままです。(両方とも0.0に初期設定しました) 値渡しと参照渡しでまだとり違いがあるのでしょうか。

更なるご指導よろしくお願いいたします。

補足日時:2007/09/06 16:32
    • good
    • 0

#3,4,7 です。



QQ,QQQだけでなく、たぶん、Qもdll内で
もし変更するようにしたら、Qの変更も
VBA側に反映されていないでしょう。

Fortranは、みたこともなく、全然わかりませんが、
googleで検索して
http://www.ae.utexas.edu/lrc/fortran/intel/f_ug1 …
を見る限り、
ByRefで呼ぶ場合は、Fortran側でその旨、指示する必要があり
たぶん
!DEC$ ATTRIBUTES REFERENCE :: Q
!DEC$ ATTRIBUTES REFERENCE :: QQ
!DEC$ ATTRIBUTES REFERENCE :: QQQ
が必要でしょう。
    • good
    • 0
この回答へのお礼

ご指摘ありがとうございます。
kurinkurinさんの前回指摘の後、dsuekichiさんのヒントで皆さんから頂いた情報を立ち戻りDLLが正しく動作いたしました♪

Fortran側で参照渡しのPointerの宣言を行うことで目的を達することができました。(Real, Pointer :: Q,QQ,QQQを挿入しました)
これからは配列の取り扱いにチャレンジいたします。

すっきりしました。ありがとうございました。

お礼日時:2007/09/06 17:36

ANo 2です。



> 値渡しと参照渡しでまだとり違いがあるのでしょうか。

ANo.4さんの提示されたページにちゃんと書いてありますよね?

--------------------------------------------------------------
II.サブルーチンのエクスポート
呼出し規約としてSTDCALLを指定した場合,
実数型および整数型の引数は基本的に値渡し
(仮引数は実引数のコピーであり,関数内部で仮引数を変更しても実引数には影響がない.)
となる.
--------------------------------------------------------------
で、対応方法も書いてますよね・・・
    • good
    • 0
この回答へのお礼

ありがとうございました。
ご指摘のとおりです。再度見直してDLL動作いたしました。
すっきりしました♪

お礼日時:2007/09/06 17:40

#5です。



> regsvr32を実行したところ『DllregiSterserverエントリポイントが> 見つかりませんでした』の
> メッセージでDLLが登録されなかったようです。
> (ここでつまづいたので先は未実施です)。
> DLLの作成に問題ありでしょうか?
その可能性が高いのかなぁ・・・
でもVB.NETではCall出来ているというし、、、(←間違いないですよね??)

> 尚、教えていただいた上記VBA構文を実行したところ
> コンパイルエラーとなりましたので元に戻しました。
DLLのレジスト(regsvr32)および参照設定が行えておりませんので、これはコンパイルエラーに
なります。(当初私が想定した理由とは別の理由ですが・・・)
※as New ~ ではなく、CreateObjectする方法もありますが、いずれにせよDLLレジストが必要です。

ちなみに、一番初めにご提示いただいた状態のVBAソースで
  Q = 2#
のところを
  Q = 2!
  QQ = 0!
  QQQ = 0!
としても、「実行時エラー'49' DLLが正しく呼び出せません」のままでしょうか?

この回答への補足

回答ありがとうございます。
>ちなみに、一番初めにご提示いただいた状態のVBAソースで
>  Q = 2#
>のところを
>  Q = 2!
>  QQ = 0!
>  QQQ = 0!
>としても、「実行時エラー'49' DLLが正しく呼び出せません」のままでしょうか?
だめでした........
ちなみに2!がSingle表示で2#がDoubleなんですね。
基本的なことが理解できていませんでした。

Q=2.0と入力すると自動でQ=2#と変換されるのでそんなものかと思っておりましたが式の右辺がDoubleでもQがSingleであれば=Qの式でSingleに変換されて代入されると暗黙に信じておりました。(Fortran知識)

補足日時:2007/09/06 16:16
    • good
    • 0

#1です。


「ロギングしている?」とは「Fortran側関数内で通過確認のログ(時分秒など)を出力しているのかな?」という意味です。

> VBAでエラーになったときデバッグモードでステートメントCALL DLL1(Q,QQ,QQQ) の
> 変数Q、QQ、QQQの上にカーソルを重ねるとそのDLLで計算された数値が表示されました
とは、「Call DLL1(Q, QQ, QQQ)」の行が黄色い時のことですか?
デバッガで行が黄色いのは「これからその行を実行しますよ」という意味なので、まだそのステートメントは(完全には)実行されていません。

ごみが残っている場合なども考えられますので、マウスポインタを重ねた状態で変数に値が入っているから、DLLの実行が完了しているとは言い切れないと思います。


まずは以下を試してみてください。

・(#2さんも言っていますが)Fortran側関数の引数は間違いなくSingle型(なんというのか分かりませんが、Fortranで言うところの単精度浮動少数型)ですか?
・[スタート]-[ファイル名を指定して実行]から「regserv32 C:\aaa\bbb\hogehoge.dll」を実行してください。(Fortranで作成した該当DLLを配置しているフルパスに読み替えてください。)
・VBAの参照設定から、hogehogeをチェックしてOKを押してください。(既にチェックが付いていたり、参照不可になっていたら、一度はずしてOKを押してから、再度参照設定を開いてやり直してください。)
・VBAの書き方を以下のように変更してみてください。(いろいろ怪しい部分があります。。。)
--------------------------
Private Q As Single
Private QQ As Single
Private QQQ As Single

Sub Macro1()
Dim oFortran As New hogehoge.hogehoge 'もしかしたら「As New DLL1」や「As New hogehoge」、「As New hogehoge.DLL1」かも(もしコンパイルが通らない場合は元の記述に戻して結構です。Declareも)

'変数は初期化してから使いましょう(初期化しなくても動作保障されるのは使えるのはVBぐらいです。他言語を呼ぶ以上これはお作法です。)
Q = 2! '#はDouble型の型宣言文字です。←これがいちばん怪しい気がする。。。
QQ = 0!
QQQ = 0!
Call oFortran.DLL1(Q, QQ, QQQ)
Cells(5, 2) = Format(Q, "#####.#0")
Cells(6, 2) = Format(QQ, "#####.#0")
Cells(7, 2) = Format(QQQ, "#####.#0")
End Sub
--------------------------

この回答への補足

回答ありがとうございます。
>デバッガで行が黄色いのは「これからその行を実行しますよ」という意味なので、まだそのステートメントは(完全には)実行されていません。
>ごみが残っている場合なども考えられますので、マウスポインタを重ねた状態で変数に値が入っているから、DLLの実行が完了しているとは言い切れないと思います。
ご指摘どおりですね、QQ=0とQQQ=0を挿入します。

>・(#2さんも言っていますが)Fortran側関数の引数は間違いなくSingle型(なんというのか分かりませんが、Fortranで言うところの単精度浮動少数型)ですか?
Fortran内でReal*4と型宣言していますがこれは4バイトの変数定義ですのでQ,QQ,QQQはそれぞれSingle(4Byteと理解しています)です。

>・[スタート]-[ファイル名を指定して実行]から「regserv32 C:\aaa\bbb\hogehoge.dll」を実行してください。(Fortranで作成した該当DLLを配置しているフルパスに読み替えてください。)
>・VBAの参照設定から、hogehogeをチェックしてOKを押してください。(既にチェックが付いていたり、参照不可になっていたら、一度はずしてOKを押してから、再度参照設定を開いてやり直してください。)
regsvr32を実行したところ『DllregiSterserverエントリポイントが見つかりませんでした』のメッセージでDLLが登録されなかったようです。(ここでつまづいたので先は未実施です)。
DLLの作成に問題ありでしょうか?

ご指摘よろしくお願いいたします。

>Dim oFortran As New hogehoge.hogehoge 'もしかしたら「As New DLL1」や「As New hogehoge」、「As New hogehoge.DLL1」かも(もしコンパイルが通らない場合は元の記述に戻して結構です。Declareも)
尚、教えていただいた上記VBA構文を実行したところコンパイルエラーとなりましたので元に戻しました。

補足日時:2007/09/06 14:00
    • good
    • 0

#3 です。

 すいません。 #3は、間違った指摘ですね。
忘れてください。

やはり、呼び出し規約に問題があると思われ
http://rakasaka.fc2web.com/propath/prodll_export …
が参考になると思います。

この回答への補足

ありがとうございます。
参考にさせていただきます。

補足日時:2007/09/06 13:59
    • good
    • 0

おそらくDll1.dllのパス指定が足りません。


フルパス指定するか、Dll1.dllをExcel.exeと同じフォルダに
置かないといけません。 xlsファイルと同じところにおいても
認識されません。 あくまで実行ファイルはExcel.exeです。
    • good
    • 0

> 実行時エラー'49' DLLが正しく呼び出せません 


は、VBAのヘルプにあるように、主に、

・引数の数が間違っている場合
・引数の型が間違っている場合
・DLLが、StdCall 呼び出し規約に従って作成されていない場合

に発生します。

FortranのDLL作成方法は詳しくありませんが、この辺り大丈夫でしょうか?

また、
> Visual Basic .NETで作成したVBからは正しくCALLできています。
とのことですが、VB.NETでは、どういう宣言を行って、どうやってCallしているのでしょう?
#VB.NETのコードも提示してください。

この回答への補足

回答ありがとうございます。
VB.NETのソースは以下のとおりです。

(3)----------- VB.NET ソース --------------------
Declare Sub DLL1 Lib "DLL1.dll" (ByRef Q As Single, ByRef QQ As Single, ByRef QQQ As Single)
Private Q As Single
Private QQ As Single
Private QQQ As Single

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Q = 2.0
Call DLL1(Q, QQ, QQQ)
TextBox1.Text = Format(QQ, "####.#0")
TextBox2.Text = Format(QQQ, "####.#0")
End Sub



>・引数の数が間違っている場合
>・引数の型が間違っている場合
>・DLLが、StdCall 呼び出し規約に従って作成されていない場合に発生します。
>FortranのDLL作成方法は詳しくありませんが、この辺り大丈夫でしょ
うか?
ご指摘どおり変数の型と個数の確認も行っておりますが間違いがないとは言い切れません。DLLの作成方法も同じです。よりどころはVBで正しく利用できたということです。
StdCallの規約はそのようなものがあることはネットで確認しておりますが内容はまだ理解できておりません(未熟です)。

そのような状況ですみませんがアドバイス頂ければ幸いです。

補足日時:2007/09/06 10:31
    • good
    • 0

> VBAからDLLの呼び出しとDLL内の計算は正しく行われており


間違いなく事実ですか?(根拠は?DLL内でロギングしているとか??)

単純に参照設定されていないとか、regserv32されていないとかではないですか・・・?
(個人的には呼び出しがうまくいっていないんじゃないのかなぁと思うんですが・・・)


#自分はシステム屋で業務でVBAは使うので得意ですが、Fortranは全くの素人です。

この回答への補足

>> VBAからDLLの呼び出しとDLL内の計算は正しく行われており
>間違いなく事実ですか?(根拠は?DLL内でロギングしているとか??)

回答ありがとうございます。
FORTRANのDLL内部で数値の確認を行ったところ値は正しく引き渡されておりその引数を使っての数値計算結果も正しく行われておりました。
その確認とは別にVBAでエラーになったときデバッグモードでステートメントCALL DLL1(Q,QQ,QQQ) の変数Q、QQ、QQQの上にカーソルを重ねるとそのDLLで計算された数値が表示されましたのでDLLでの計算は正しく行われたものと判断しまし、制御がDLLからVBAに戻るときに何かのエラーになっているのではないかと睨んだしだいです。
(別途regserv32とロギングの知識がないので確認してみます)

補足日時:2007/09/06 09:40
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QDLLが正しく呼び出せません (ToT)

こんにちは。よろしくお願いします。

環境は、WindowsXP Access2000/VBA にてプログラミングをしています。
現在、表題の「DLLが正しく呼び出せません」エラーに泣かされています。。。。
どなたかもし心当たりなどありましたらぜひアドバイスを下さい。

VBAにてシステムを作成していますが、その中で、普通に自分で書いた関数を
普通に?呼び出しているだけなのですが、表題のエラーが頻発してしまい困っています。

別に、外部DLLをDeclareしてそれを呼び出した時に出ている、という事ではないです。
普通に自分で書いた関数を呼び出すだけなんですが、ある関数を呼び出すと、
返ってくる時にこのエラーが発生するものがあります。(SubでもFunctionでも)

引数の型や戻り値の型は、呼び出し側と整合が取れています。(確実に一致しています)

まったく原因がわからないので、例えばエラーの出た関数がSubの場合は
一応 Call をつけて呼び出してみたりするとその場はエラーがなくなったりして
でも、またその関数の中を編集したりすると、いつのまにかまた
その関数を呼び出した時に表題のエラーがでたりします。

もちろんコンパイルエラーはありませんし、SetしてNothingを忘れてメモリを壊している
という事などもないつもりです。
(エラーのでる関数ではそもそもSetなどを使っていませんし)

DLLの関数を呼び出すのではなく普通に標準モジュールなどに書いた自前の関数の呼び出しで
表題のエラーがでる原因として、なにか考えられる事はあるのでしょうか。

実際のソースを載せれないので申し訳ないですが、一般的な情報として
「DLLが正しく呼び出せません」エラーの原因となる事をどのような事でもけっこうですので
教えていただければ、と思います。

どうかよろしくお願いいたします。

こんにちは。よろしくお願いします。

環境は、WindowsXP Access2000/VBA にてプログラミングをしています。
現在、表題の「DLLが正しく呼び出せません」エラーに泣かされています。。。。
どなたかもし心当たりなどありましたらぜひアドバイスを下さい。

VBAにてシステムを作成していますが、その中で、普通に自分で書いた関数を
普通に?呼び出しているだけなのですが、表題のエラーが頻発してしまい困っています。

別に、外部DLLをDeclareしてそれを呼び出した時に出ている、という事ではないです。...続きを読む

Aベストアンサー

VB/VBAから呼び出すDLLの関数は、Microsoft C/C++の用語で言うところのSTDCALL呼び出し規約でなければなりません。

呼び出し規約がSTDCALLでない関数(例えばcdecl呼び出し規約の関数)をVB/VBAから呼び出すと、関数の呼び出し自体は行われますが、関数の実行から戻ってきた時点で「DLLが正しく呼び出せません」エラーになります。

また、STDCALL呼び出し規約の関数であっても、呼び出し時に引数の数やサイズを間違えていると、やはり関数の実行から戻ってきた時点で「DLLが正しく呼び出せません」エラーになります。

このほか、呼び出された関数が何らかの理由(通常はプログラムミス=バグ)によりスタックポインタを通常あるべき値とは異なる値にして実行を終了すると、関数の実行から戻ってきた時点で「DLLが正しく呼び出せません」エラーになります。

QExcel2010VBAでエラーが出る相対パス指定

 ExcelVBAで,Excel2007と2013で問題無いのに,
Excel2010ではエラーが出る相対パス指定について,
ご教示を頂けると助かります.

 ExcelVBAにて,
○○.dll ファイルを 以下のように宣言して使っています.

Private Declare Function LoadTT Lib ".\○○.dll" _
() As Integer

 プログラムの中で,
ret = LoadTT()
を実行すると,
Excel 2007では相対パスでの指定で問題無く動作しますが,
Excel 2010では相対パスでの指定ではエラー(ファイルが見つからない)"48"が出ます.
そこで,相対パス指定をやめて絶対パスに変更すると問題無く動作します.

 念のため Excel2013でも試したところ,
2007と同様に,相対パス指定でも問題なく動作しました.

 なお,ExcelVBAのファイル「○.xlsm」と「○○.dll」は同じフォルダーに入れています.
 また,
ChDrive ThisWorkbook.Path
ChDir ThisWorkbook.Path
の実行によるカレントフォルダーの確認も,どのバージョンでも同じに正しく確認出来ています.
 
 因みに,バージョンの違う各Excelは別々のPCでの動作ですが,使用OSは Windows7 Professional 32bit で同じです.

 以上のように
Excel2010だけ動作が異なります.

 とりあえずは絶対パス指定にすれば問題は解消するのですが,
Excel2010で特に何か設定したということは無いので気持ち悪く,
原因と思われることでご存じ方がいらしたらご教示を頂けると助かります.

 どうぞよろしくお願い致します.

==

 ExcelVBAで,Excel2007と2013で問題無いのに,
Excel2010ではエラーが出る相対パス指定について,
ご教示を頂けると助かります.

 ExcelVBAにて,
○○.dll ファイルを 以下のように宣言して使っています.

Private Declare Function LoadTT Lib ".\○○.dll" _
() As Integer

 プログラムの中で,
ret = LoadTT()
を実行すると,
Excel 2007では相対パスでの指定で問題無く動作しますが,
Excel 2010では相対パスでの指定ではエラー(ファイルが見つからない)"48"が出ます.
そこで,相対パス指定をやめて...続きを読む

Aベストアンサー

#2の回答者です。

質問者さんは、もう論理的な対処をしたり、回答者の書いた内容の確認もないようです。そこで、後の人のためにまとめておこうと思い立ちました。

----------------
 [.dll] は、[.ocx]に読み替えても可

(1)一般的な.dll (ダイナミックリンク・ライブラリ)は、一般的には、実行ファイル(.exe)や WindowsのSystem32 フォルダに入れる。
 基本はこの通り
 http://www.forest.impress.co.jp/info/knowledge/2-5-3xp.html

(2).dllは、パスの通った所に置く。
 - Shellコマンド(SET PATH)や外部オブジェクト(FileSystemObjectのBuildPath)で、パスは通せる。

(3).dllを絶対パスにする。

(4) Excel 等のOfficeの場合は、設定で、[オプション]-[保存]-[規定のファイル]
で、Current Folder を決め、そこに置く。 要 Excelの再起動。
(非推奨-ファイルと同じ場所に置くことは、ユーザーによる削除したり移動したりするトラブルが想定されるから。)

(5)相対パスは、基本的にはお勧めできない。

過去には、このような例もある。ただし、質問者のExcel VBAの技術としてはかなり低い。
通常、ユーザーが作成したライブラリであっても、当時はMS Officeのディベロッパのユーティリティや現在でも流通しているフリーのインストーラーを使うのが基本だから、そのような問題は本来は発生しない。単なる手続き上の手抜きによるトラブル。
http://www.vbalab.net/vbaqa/c-board.cgi?cmd=ntr;tree=5215;id=excel

 ChDrive ActiveWorkbook.Path
 ChDir ActiveWorkbook.Path
が可能と書いてあるが、私自身は、Win32 APIのSetCurrentDirectory をお勧めする。
---------------------

と、以上が、32ビットでの一般的な対処法です。他にも、Excelの特殊なツールによって、設定を変える方法はあるかとは思いますが、基本的なことは変わらないと信じます。自作で、Excel用のライブラリを作れるレベルなら、このような質問はしないはずです。いたずらに、長く話を伸ばしてもしかたがないので、これで終わりにします。

#2の回答者です。

質問者さんは、もう論理的な対処をしたり、回答者の書いた内容の確認もないようです。そこで、後の人のためにまとめておこうと思い立ちました。

----------------
 [.dll] は、[.ocx]に読み替えても可

(1)一般的な.dll (ダイナミックリンク・ライブラリ)は、一般的には、実行ファイル(.exe)や WindowsのSystem32 フォルダに入れる。
 基本はこの通り
 http://www.forest.impress.co.jp/info/knowledge/2-5-3xp.html

(2).dllは、パスの通った所に置く。
 - Shellコマンド(SET PATH)や...続きを読む

QC++で作成したDLLにVBAから配列渡し

VC++初心者です。よろしくお願いします。
VC++2008ExpressでWindowsアプリケーションのDLLを作成してみました。
Excel2007VBAにて、そのDLLを呼び出して関数を使用したいのですが
VBAの配列を参照渡しで渡すと、配列のデータをうまく渡せません。
コードは以下の通りです。
配列ではないデータはうまくいきますが。。。
配列の場合はもっと他に必要なことがあるのでしょうか?
よろしくお願いします。

//VC++ DLLコード

#include <windows.h>

int APIENTRY Add(int[] a)
{
   return a[0] + a[1] ;
}

'''VBAのコード

Private Declare Function Add Lib "TEST_DLL.dll" (ByRef a() As Integer) As Integer

Dim a(1) As Integer

Sub test()

a(0) = 1
a(1) = 2

MsgBox (Add(a))

End Sub

メッセージボックスには3が表示されるはずですが
変な数字に化けてしまいます。

どなたか、ご存知の方、よろしくお願いします。

VC++初心者です。よろしくお願いします。
VC++2008ExpressでWindowsアプリケーションのDLLを作成してみました。
Excel2007VBAにて、そのDLLを呼び出して関数を使用したいのですが
VBAの配列を参照渡しで渡すと、配列のデータをうまく渡せません。
コードは以下の通りです。
配列ではないデータはうまくいきますが。。。
配列の場合はもっと他に必要なことがあるのでしょうか?
よろしくお願いします。

//VC++ DLLコード

#include <windows.h>

int APIENTRY Add(int[] a)
{
   return a[0] + a[1] ;
}

'''V...続きを読む

Aベストアンサー

CPPファイルでコンパイルしているなら extern ”C"でCPPの自動命名を抑制したほうがいいと思います

VBAのIntegerは16ビットなので C++側の受けは shortにしないといけません
VBA側をC++に合わせるなら 変数を Longにします

またVBA側のDeclare宣言を
' C++側が intなら
Private Declare Function Add Lib "Test_DLL.dll" ( a as Long ) as Long
' C++側が shortなら
Private Declare Function Add Lib "Test_DLL.dll" ( a as Integer ) as Integer
といった具合にします


呼び出し方法は

MsgBox( Add( a(0) ) )
といった具合に 先頭要素を引数に渡しましょう

Q定数配列の書き方

VB6で定数を定義する場合は次の通りです。

  Const strTest As String = "TEST"

では、定数配列を定義する場合はどのように書けばいいのでしょう?

  Const astrTest() As String = Array("A", "B", "C")      '→NG
  Const astrTest(0 To 2) As String = Array("A", "B", "C")  '→NG

いろいろな書き方を試して見たのですが、上記のような書き方でも文法的にエラーになるようです。

どのように書けばいいのでしょうか?

それとも定数を配列で定義するのは無理なんでしょうか?

Aベストアンサー

残念ですが、VBでご希望のことをすることはできません。

QCOMコンポーネントって何?

よく、COMコンポーネントって聞くんですが、何のことかわかりません。VBやVBAのような言語名ではないことは、なんとなく分かるのですが・・・。できるだけわかりやすく教えてください。

Aベストアンサー

失礼ですが、クラスをご存知ないのであればCOMは多分
全く理解できないでしょうねぇ

クラスについても、ご自分で勉強が必要だとは思いますが
簡単に説明しておきます。
構造体(属性)に、関数(操作)を加え、カプセル化したものです。
従来のプログラミングでは、変数をばらばらに扱わず、
構造体と呼ばれる型に関係ある変数をまとめて、
プログラム中のデータ構造が明確になるようにしておきました。
そこで、この構造体に専属の関数を加えてしまえば、
その構造体は単独で自分の面倒をみることが出来るようになります。
それがクラスです。
その結果、プログラム中のデータや処理が、クラス単位で整理され、
それぞれ部品のように組み替えが可能になりました。

このように、クラス単位にプログラムを分割することで
巨大なプログラムを明瞭にする言語をオブジェクト指向言語といいます。

また、クラスには親と子があり、「継承」という考えを用いて
どんどんバージョンアップや特化を行うことが容易です。

VBで説明すると、
Dim value as A
として変数を宣言した場合、クラスは「A」です。
valueはオブジェクトや、インスタンスと呼ばれます。
valueを使って、Aに含まれる関数を呼び出して、valueを
操作することが出来ます。
value.Init()
等。

ざっくり説明するとこんな感じです。
詳細については、各言語の書籍を参照してください。

このようにして作ったクラスを、
・他の言語から使いたい
・ネットワーク経由で使いたい
などと言った機能を実現する、Microsoft提供の方法の一つが、
COMやDCOMと呼ばれるものです。
COMは、他のプログラムからの使いまわしに強いので、
一度作っておけば、VB、Delphiは勿論、VBScript、JavaScrips、WSHなどから
呼び出しが可能です。
また、COM自体のバージョンが上がっても、それを呼び出してる
プログラム自体には変更の必要がありません。

失礼ですが、クラスをご存知ないのであればCOMは多分
全く理解できないでしょうねぇ

クラスについても、ご自分で勉強が必要だとは思いますが
簡単に説明しておきます。
構造体(属性)に、関数(操作)を加え、カプセル化したものです。
従来のプログラミングでは、変数をばらばらに扱わず、
構造体と呼ばれる型に関係ある変数をまとめて、
プログラム中のデータ構造が明確になるようにしておきました。
そこで、この構造体に専属の関数を加えてしまえば、
その構造体は単独で自分の面倒をみることが出...続きを読む

QCで作成したDLL関数をVBから呼び 引数渡し方法

/**** Cプログラム *****/
int testAP( char* a)
aのポインタにアドレスを返します。

/**** VB プログラム****/
Public Declare Function testAP Lib "test.dll" (ByRef a As String) As Integer


Dim keydata As String * 128

lngRc = testAP(keydata)

上記VBのAPを実行するとアプリケーションエラーになります。
Cプログラムのデバックをすると入口ではaのポインタにはアドレスがセットされていて
、値を設定出来、最後まで正常動作して、VBとのインタフェースで落ちています。
VB6.exeでアプリケーションエラーになっています。

恐らく、VBにはポインタという概念が無いと聞いていてCのAPとの受け渡しに失敗して
そうなのですが、VBでの引き渡し方法が分かりません。
よろしくお願い致します。

Aベストアンサー

>__declspec(dllexport) int testAP(BSTR* cp_KeyData){
>
>→char*からBSTR*に変更しました。

だめです。そんな強引なことをしないでください。
char *でかまいません。
BSTR*にするとメモリ破壊が起きます。
__stdcallはどうしたんですか?
(ごめんなさい、アンダースコア2つですね)

>只、VCのデバックを行うと実行時エラー'49'
>DLLが正しく呼び出せません。が出力される。
>(DLL関数を呼んで処理が終了してVBに戻る所で出力されます。

VBのDeclareステートメントと、Cの処理があっていません。メモリを破壊しているのでしょう。
EXEにして動くのはたまたまでしょう。

Qエクセル関数で日付かどうかの確認?

ワークシート関数でセル内が日付かどうか調べるものはないでしょうか?
VBAのIsDateなら存じておりますが。

Aベストアンサー

日付を表すデータは、セルの値としては、単なる数値なのですが、どういう種類のセルの書式が設定されているかを調べることはできます。
調べたいセルがA1だとして
=cell("format",A1)

"D1"になれば概ね日付だと判別できます。
時刻を含めたものにする場合は、
Dで始まることをチェックすればいいかも。
詳しくは、CELL関数のヘルプを参照してください。

QEXCELファイルのカレントフォルダを取得するには?

EXCELファイルのカレントフォルダを取得するには?

C:\経理\予算.xls

D:\2005年度\予算.xls

EXCEL97ファイルがあります。

VBAで
  カレントフォルダ名
(C:\経理\,D:\2005年度\)
を取得する事は可能でしょうか?

CURDIRでは上手い方法が見つかりませんでした。

Aベストアンサー

こんばんは。
Excel97 でも、同じですね。以下で試してみてください。

Sub test()
'このブックのパス
a = ThisWorkbook.Path
'アクティブブックのパス
b = ActiveWorkbook.Path
'Excelで設定されたデフォルトパス
c = Application.DefaultFilePath
'カレントディレクトリ
d = CurDir
MsgBox "このブックのパス   : " & a & Chr(13) & _
   "アクティブブックのパス: " & b & Chr(13) & _
   "デフォルトパス    : " & c & Chr(13) & _
   "カレントディレクトリ : " & d & Chr(13)
End Sub

QDoEvents関数って何?

こんにちは。

VBAやプログラミングに詳しい皆様に
教えていただきたい質問があります。

cells(1,1)からcells(5000,1)までの値を消去するときに
処理の進行状況を表示するためにuserform上にプログレスバーを表示したいと思います。

そこで下記のようなコードを入力しました。

userform1.show
for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
next i
unload userform1

しかしこれだとuserformの背景が真っ白になってしまい
ラベルの文字も消えてしまいます。
そこで「EXCEL VBA パーフェクトマスター」という本を見たら

for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
DoEvents
next i
unload userform1
と入力すれば解決することがわかりました。

しかし「DoEvents」についてあまり詳しく書いていなかったのでDoEvents関数をヘルプで見ると、
「発生したイベントがオペレーティング システムによって処理されるように、プログラムで占有していた制御をオペレーティング システムに渡すフロー制御関数です。」

と書いてあるのですが正直、書いてあることがよくわかりません。

どなたかDoEvents関数について、
もう少しわかりやすく教えていただけませんか。
それから、最初に書いたコードで実行すると
ユーザーフォームの背景が真っ白になってしまう原因も
教えていただけませんか?

よろしくお願いいたします。

こんにちは。

VBAやプログラミングに詳しい皆様に
教えていただきたい質問があります。

cells(1,1)からcells(5000,1)までの値を消去するときに
処理の進行状況を表示するためにuserform上にプログレスバーを表示したいと思います。

そこで下記のようなコードを入力しました。

userform1.show
for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
next i
unload userform1

しかしこれだとuserformの背景が真っ白になってしまい
ラベルの文字も消えてしまいます。
そ...続きを読む

Aベストアンサー

簡単に言うと、
OS に制御を渡すってことです。(ヘルプそのまんま)
時間が掛かるループ処理などの場合、ループが終わるまで制御は独占されてしまいます。
ですのでループ中は OS や Excel そのものにも再描画をさせる暇さえ与えません。
途中に DoEvents を入れると制御が OS に渡るので、OS は溜まっていた処理をそこで行うことができます。
結果、フォームの再描画などが行われることになります。

注意点ですが、
Private Sub CommandButton1_Click()
  Dim i As Long

  For i = 1 To 50000
    DoEvents
    Cells(i,1) = ""
  Next i
End Sub

Private Sub CommandButton2_Click()
  MsgBox "hoge"
End Sub

っていうフォームのコードがあった場合、
DoEvents を入れることによって、ループ中にユーザーがCommandButton2 を押すことによって CommandButton2 のクリック イベントも動いちゃいます。
CommandButton1 のクリック イベントではループの前に
CommandButton1.Enabled = False
CommandButton2.Enabled = False
を書いてフォーム上の CommandButton を無効にしておき、ループが終わったら
CommandButton1.Enabled = True
CommandButton2.Enabled = True
と書いて CommandButton を有効に戻してください。

これを工夫すれば、CommandButton2 で CommandButton1 のループを途中キャンセルする処理もすることができます。

Private Canceled As Boolean

Private Sub CommandButton1_Click()

  CommandButton2.Enabled = False

  Dim i As Long
  For i = 1 To 50000
    DoEvents

    If Canceled = True Then
      MsgBox "キャンセルしました"
      Exit Sub
    End If

    Cells(i, 1).Value = ""
  Next i
End Sub

Private CommandButton2_Click()
  Canceled = True
End Sub



コードの行頭にあるスペースは見易さのために全角スペースで作成していますので、これをこのままコピペするとエラーになるかもしれません。
コピペするなら行頭の全角スペースを半角スペースに直してください。

簡単に言うと、
OS に制御を渡すってことです。(ヘルプそのまんま)
時間が掛かるループ処理などの場合、ループが終わるまで制御は独占されてしまいます。
ですのでループ中は OS や Excel そのものにも再描画をさせる暇さえ与えません。
途中に DoEvents を入れると制御が OS に渡るので、OS は溜まっていた処理をそこで行うことができます。
結果、フォームの再描画などが行われることになります。

注意点ですが、
Private Sub CommandButton1_Click()
  Dim i As Long

  For i = 1 To 50000
...続きを読む

QEXCEL VBA で現在開いているブックのファイル名を取得する方法

EXCEL2003 VBAで業務を簡素化するために、現在開いているブックのファイル名を取得する方法が分かりません。
作業手順をマクロを使って処理していますが、オリジナルのワークブックをファイル名を変えて保存し、以後、このワークブックを読み込んで使用しています。
このときのVBAは、オリジナルのファイル名を使っているため、ファイル名を変更するとエラーになり、以後の業務に使用できません。
常にファイル名を取得出来るVBAをどなたか、教えて下さい。

Aベストアンサー

>現在開いているブックのファイル名
 ちょっと曖昧な表現かなぁという気もいたしますが、VBAが書いてあるブックのブック名は
ThisWorkbook.Name
で、現在 "アクティブにして" 操作対象になっているブックの名前は
ActiveWorkbook.Name
ですね。

 しかし、
>VBAは、オリジナルのファイル名を使っているため、ファイル名を変更するとエラーになり
というような文脈からすると、
ThisWorkbook.Name
の方ですかね。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング