SmtpMailクラスとアンマネージDLL

解決


MM  2004-12-08 01:28:17  No: 118069

VB.NETでメールを送信するプログラムを作成しています。
http://dobon.net/vb/dotnet/internet/smtpmail.html
の様にSystem.Web.Mail.SmtpMailクラスを使うとメール送信できたの
ですが、「Win98系だとエラーになる」
「不定期にエラーになる(XPのSP2をあてたのが原因か?)」
等の理由から、フリーのDLLを使わせていただく事にしました。

そこで、Declareステートメントや
http://dobon.net/vb/dotnet/links/extractarchive.html
にあるようにDllImportを使ってアンマネージDLLを呼び出そうとしているのですがうまくいきません。
マーシャリング等が関係していたりするのでしょうか?

本DLLのFAQ
http://www.bea.hi-ho.ne.jp/cgi-bin/user/byoko/bnews
にも同じような現象で苦しんでいる方がいらっしゃったのですが、
COM使用で断念したようです。。

下記にソースを載せます。
また実際、System.Web.Mail.SmtpMailクラスはWin98系だと失敗するのでしょうか?(そのような記述は見つからなかったのですが。。)
アンマネージDLLの呼び出しが始めてなので、
本当はSystem.Web.Mail.SmtpMailクラスを使いたいのですが。。

初歩的な間違いをしているのかもしれませんが、
どこを勘違いしてるのかわかりません。。

宜しくお願いします。


MM  2004-12-08 01:29:00  No: 118070

○Declareステートメントを使用した場合○

#宣言
Private Declare Function SendMail Lib "bsmtp" _
(ByVal szServer As String, ByVal szTo As String, ByVal szFrom As String, _
ByVal szSubject As String, ByVal szBody As String, ByVal szFile As String) As String

宣言文が「名前空間のステートメントが無効です」というエラーになっています。

・DLL 関数を保持するクラスを作成した場合

#宣言
Imports System.Runtime.InteropServices

Public Class BSMTP
    Declare Function SendMail Lib "BSMTP.dll" _
    (ByVal szServer As String, ByVal szTo As String, ByVal szFrom As String, _
    ByVal szSubject As String, ByVal szBody As String, ByVal szFile As String) As String
End Class

#使用時
strRet = BSMTP.SendMail(strSmtp, strTo, strFrom, strSubject, strBody, Nothing)

「実行時例外がスローされました : System.NullReferenceException -
オブジェクト参照がオブジェクト インスタンスに設定されていません。」
というエラーになります。

○DllImport属性を使用した場合○

#宣言
Imports System.Runtime.InteropServices

<DllImport("bsmtp")> _
Private Shared Function SendMail(ByVal szServer As String, ByVal szTo As String, ByVal szFrom As String, _
ByVal szSubject As String, ByVal szBody As String, ByVal szFile As String) As String
End Function

宣言文が「名前空間のステートメントが無効です」というエラーになっています。

・DLL 関数を保持するクラスを作成した場合

#宣言
Public Class BSMTP
    <DllImport("bsmtp.dll", CharSet:=CharSet.Auto)> _
   Public Shared Function SendMail(ByVal szServer As String, ByVal szTo As String, _
   ByVal szFrom As String, ByVal szSubject As String, ByVal szBody As String, _
   ByVal szFile As String) As String
    End Function
End Class

#使用時
strRet = BSMTP.SendMail(strSmtp, strTo, strFrom, strSubject, strBody, Nothing)

「実行時例外がスローされました : System.NullReferenceException -
オブジェクト参照がオブジェクト インスタンスに設定されていません。」
というエラーになります。


魔界の仮面弁士  2004-12-08 03:38:07  No: 118071

> 宣言文が「名前空間のステートメントが無効です」というエラーになっています。
その宣言は、「どこに」記載していますか?
        Module〜End Module
        Class〜End Class
        Structure〜End Structure
などの中に書かないと、そのようなエラーになりますよ。

> 「実行時例外がスローされました : System.NullReferenceException -
API宣言が間違っています。各引数を ByRef As String にしてください。


魔界の仮面弁士  2004-12-08 03:41:51  No: 118072

> また実際、System.Web.Mail.SmtpMailクラスはWin98系だと失敗するのでしょうか?(そのような記述は見つからなかったのですが。。)

http://www.microsoft.com/japan/msdn/library/ja/cpref/html/frlrfsystemwebmailsmtpmailclasstopic.asp

》 プラットフォーム: Windows 2000, Windows XP Professional, Windows Server 2003 ファミリ


MM  2004-12-08 05:47:24  No: 118073

魔界の仮面弁士さん、ありがとうございました!

>その宣言は、「どこに」記載していますか?

Imports〜 の直ぐ下に記載していました。。

該当のものはModule〜End Moduleの中に記載し、
各引数はByRefに変えたら全てうまくいきました!
(CharSetは削除)
本当にありがとうございました。

ところで、引数について私の参考書にはByValで宣言されているものもあったのですが、
なぜ今回ByValではNGでByRefに変更したらうまくいったのでしょうか?
(呼び出すDLL側の仕様でしょうかね。。?)

#MSDNにSystem.Web.Mail.SmtpMail対象OSについてしっかり記載されていましたね。。
#すみません、ありがとうございました!


魔界の仮面弁士  2004-12-08 07:40:10  No: 118074

> ところで、引数について私の参考書にはByValで宣言されているものもあったのですが、
> なぜ今回ByValではNGでByRefに変更したらうまくいったのでしょうか?
う〜ん。
簡潔に説明できる自身が無いので、細かい説明はパスさせて下さい。

# C形式の文字列云々とか、OLEのBSTR文字列の説明とかを
# 始めてしまうと、キリが無いし…。

> (呼び出すDLL側の仕様でしょうかね。。?)
まぁ、そういう事です。

http://www.hi-ho.ne.jp/babaq/bsmtp.html のページでは、VB6/VBA向けの
コードで記述されていますので、よく見ないと、ByRef で宣言する仕様に
なっている事に気づき難いかも知れませんね。

ほとんどの文字列系DLLは、Stringの受け渡しを、ByVal As String で
行う事になります。ByRefで渡すタイプはごく稀です。

たとえば、よく使われる USER32 とか GDI32 とか KERNEL32 などのDLLでは、
文字列は基本的に ByVal As String で渡す仕様になってます。
(Unicode文字列形式を要求するタイプは、ByRef As Byteなどになりますが)

OLE/COMベースの処理を行うDLLの中には、今回のように、ByRefで
文字列を渡す仕様の物もありますが、そういう DLL は、
さほど多くありません。
そもそも、OLE/COM系DLLの場合、参照設定して使うタイプが多いですしね。(^^;)


魔界の仮面弁士  2004-12-08 07:44:49  No: 118075

一箇所補足。m(_ _)m

> たとえば、よく使われる USER32 とか GDI32 とか KERNEL32 などのDLLでは、
> 文字列は基本的に ByVal As String で渡す仕様になってます。
> (Unicode文字列形式を要求するタイプは、ByRef As Byteなどになりますが)

上記の「ByRef As Byte」の一文は、VB6 や VBA の場合です。

VB.NETの場合は、宣言時に ANSIモード/Unicocdモードを指定できるように
拡張されていますので、Unicode文字列を扱うDLLの場合も ByVal As String が使えます。


MM  2004-12-08 19:19:58  No: 118076

ByRefで渡すタイプはまれだからサンプルもByValで渡すものばかりだったんですね。。

魔界の仮面弁士さん、
丁寧に解説頂き、本当にありがとうございまいました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加