tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
[ツリー表示へ]  [ワード検索]  [Home]

タイトル Re^7: Com Surrogate
投稿日: 2020/05/15(Fri) 21:41
投稿者魔界の仮面弁士
> >タスクからの実行なので、VB6 のプロジェクトのプロパティでは
> 「対話型インターフェイスの抑制」オプションも有効にしておきましょう
> このオプション付けたら発生しなくなりました\(^o^)/

良かったですね!

「対話型インターフェイスの抑制」を有効にしておいた場合、
実行時エラーが発生した場合や、うっかり MsgBox を出力した場合も、
それらの出力が抑制され、メッセージの内容がイベントログに出力されます。
サーバーでバッチ処理するような場合に便利ですよ。

ただしこのオプションでは、一切のユーザーインターフェイスが禁止されるので、
Form や ActiveX コントロールが利用できなくなるという制限がつきます。



> 関数渡しの場合はどうすればよいのでしょうか
実引数のことでしょうか、それとも仮引数のことでしょうか。
また、ByVal と ByRef の違いは把握されていますか?



> (1)private function Func(adors as object)
> (1)private function Func(adors as adodb.recordset)

どちらも(1)なのが気になりますが、それはさておき。
参照渡しの場合、実引数のデータ型と仮引数のデータ型を完全に一致させるようにします)
(ここで比較するのは、引数の変数に実際に入っている値ではなく、変数の型そのものです)


たとえば「ByRef x As Long」な仮引数に、「Dim y As Integer」な変数を実引数として渡すと、
「ByRef 引数の型が一致しません」というエラーが発生することになるでしょう。
オブジェクトを Set した Variant 型を ByRef x As Object に渡す場合も同様です。


Private Sub Main()
 Dim y AS Integer
 'Test y  'エラー「ByRef 引数の型が一致しません」

 Dim a As Variant
 Set a = CreateObject("ADODB.Recordset")
 'Example1 a  'エラー「ByRef 引数の型が一致しません」
 'Example2 a  'エラー「ByRef 引数の型が一致しません」
 Example3 a
 Example4 a
 Example5 a
End Sub

Private Sub Test(x As Long)
 x = -1&
End Sub

Private Sub Example1(x As Object)
End Sub
Private Sub Example2(ByRef x As Object)
End Sub
Private Sub Example3(ByRef x As Variant)
End Sub
Private Sub Example4(ByVal x As Object)
End Sub
Private Sub Example5(ByRef x As Variant)
End Sub


しかし As Recordset と As Object などのように、インターフェイスに互換性がある場合は、
異なった型であっても、ByRef で受け渡しを行うことができます。


なお、ADODB には複数のバージョンがあるため、そのプロシージャーが別プロジェクトからも
再利用可能なメソッドとして公開されるような場合は、それぞれのバイナリ互換性を維持するために、
意図的に古いインターフェイス名で宣言することが求められるケースがあります。
(たとえば As Recordset15 / As Recordset21 など)
Private スコープの場合は気にする必要は無いですけれどね。
https://j.mp/2LwMLVW
https://j.mp/2Wx27je



> のどちらがよいのでしょうか

結論から言えばどちらも駄目かな…。


そもそも、戻り値を使わないのであれば、Function ではなく Sub にすべきです。
そして Function を使うなら、必ず戻り値の「As 型」を明記することが求められます。

ご存知の通り、戻り値の型を省略した場合には『既定のデータ型』とみなされますが、
それには頼らず、必ず As を記述するべきです。
(初期設定では、Variant 型が『既定のデータ型』に割り当てられています)



また、今回の質問文からは、その引数が「入力用」なのか「出力用」なのかが曖昧です。

呼び出し側で Recordset インスタンスを生成しておき、
それを Func に渡して処理させたいのでしょうか?(入力用)

それとも、Func 側で Recordset インスタンスを生成して、
それを呼び出し側に結果として返したいのでしょうか? (出力用)


前者(入力用)だとすれば、引数は ByVal であるべきです。
この場合、インスタンスの生成は、呼び出す側で面倒をみることになります。
Close も同様に、呼び出す側で面倒を見ることが多いですが、
終了処理を依頼するようなプロシージャーでは、呼ばれた側で Close することもあります。
Open 処理を呼び出す側と呼ばれる側のどちらで行うかは、ケースバイケースです。

 Private Sub Main()
  Dim rs As ADODB.Recordset
  Set rs = New ADODB.Recordset '呼び出し元でインスタンスを作って
   :
  Func rs 'それを ByVal な引数で渡す
   :
  MsgBox rs.GetString(NullExpr:="(null)"), vbInformation
  rs.Close
 End Sub

 Private Sub Func(ByVal rs As ADODB.Recordset)
   'rs のインタンスは生成済みなので、ここでは New しない
 End Sub


一方、後者(出力用)だとすれば、ByRef 引数ではなく戻り値を使うことが推奨されます。
この場合、呼び出された側でインスタンスが生成され、それを呼び出し側で受け取ることになります。
Close 処理は呼び出す側で受け持つことになるでしょう。
Open メソッドについては、こちらもケースバイケースです。

たとえば、インスタンス生成のみを受け持つプロシージャーとする場合は、
開かずに返却して、呼び出し側で Open することがあります。
たとえば、インタンス生成後の初期化処理までも受け持つようなプロシージャーの場合は
開いた状態で返却するために、呼び出された側で Open しておくことがあります。


 Private Sub Main()
  Dim rs As ADODB.Recordset
  Set rs = Func()
  MsgBox rs.GetString(NullExpr:="(null)"), vbInformation
  rs.Close
  With Func()
   MsgBox .GetString(NullExpr:="(null)"), vbInformation
   .Close
  End With
 End Sub

 Private Function Func() As ADODB.Recordset
  Dim rs As ADODB.Recordset
  Set rs = New ADODB.Recordset
   :
  Set Func = rs
 End Sub



しかし提示されたコードでは、引数の前に ByVal や ByRef といったキーワードが省略されていました。
(VB6 でこれらを省略した場合、ByRef 渡しであることを意味します)

自作したプロシージャーの引数で、オブジェクトを ByRef で渡す必要があるのは、それが
入出力両方のパターンで扱われる場合だけですので、本当に入出力両方が必要なケースなのか確認しておきましょう。

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。