質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.72%

[VBA]C#で作成したDLLの戻り値DbDataReaderの受け取り方がわかりません。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,865

siritaidake

score 6

前提・実現したいこと

下記サイトを参考に、VBAでしようできるDLLをC#で作成しました。

C#でVBA向けの.NETライブラリ(COMコンポーネント)を作成するには?

DLLは、C#で別のアプリケーションから使用できることは検証済みです。
VBA(Excel 2013) でも使用できることは確認済みです。

ただ、ある関数が返してくる戻り値が受け取れなくて困っています。
ある戻り値は C#では DbDataReader なのですが、VBAではどうしたら受け取れるのでしょうか?
それらしきものを探したのですが、見つけられませんでした。

DLLの方でLIST型にして返すという手も考えてはいますが、
まずはVBAでそのまま DbDataReader を受け取れないのかどうか教えてほしいです。

発生している問題・エラーメッセージ

if res.HasRows then の行で[オブジェクトが必要です]とエラーがでる

該当のソースコード

Dim obj as new Test.Access
call obj.Open
dim res as Variant
set res = obj.ExcuteReader("select * from hoge")
if res.HasRows then
省略
end if
call obj.Close

※Test.AccessはC#で作った自作のDLLを参照して使えるようにしました

試したこと

  1. 受け取る方を変えてみた
    dim res as Object 
    set res = obj.ExcuteReader("select * hoge")
    上記の行で[オブジェクトが必要です]とエラーがでてしまう。

  2. Select文実行するだけにしてみた
    Dim obj as new Test.Access
    call obj.Open
    obj.ExcuteReader("select * hoge")
    call obj.Close

補足情報(言語/FW/ツール等のバージョンなど)

Test.Accessで使用できる関数は下記の通りです。

public void Open()
public void Close()
public DbDataReader ExcuteReader(string sql)
public int ExcuteNonQuery(string sql)
public DataTable Select(string sql)
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • lain

    2016/11/22 14:50

    そのif文のところで resの内容ってnullになってませんか?

    キャンセル

  • siritaidake

    2016/11/22 14:58

    ウォッチ式でみたのですが、宣言した際にはEmptyと値は表示されています。ExcuteReader実行後は何も表示されなくなります。でも型にはVariant/OracleDataReaderという型になるので、返ってきているのだと思います。

    キャンセル

  • siritaidake

    2016/11/22 15:00

    OracleDataReaderは、C#でOracleのNuget Packageを使って使用できるようにしたやつです。OracleDataReaderは、SQLDataReaderと同じつくりをしていて、DbDataReaderを継承しています。

    キャンセル

回答 3

check解決した方法

0

C#のDLL内で、DbDataReaderを保持し、そのデータにアクセスできるインターフェースを実装し、VBAからも使えるようにしました。

/* C#の方 元のDbDataReaderを使うのと同じように使えるようにしました */
 void bool Read();
 void string GetValue(int colindex);
'VBA
Private Sub CommandButton2_Click()
    'クラスのインスタンスを生成
    Dim o As New TestOracle.DbAccess
    '接続
    o.Open
    'カーソルを開く(SELECT文の実行)
    o.ExcuteReader ("SELECT * FROM testtable where rownum <= 10")
    'データがなくなるまで繰り返す
    Do While o.Read
        debug.print o.GetValue(0)
        debug.print o.GetValue(1)
    Loop

    'カーソルを閉じる
    Call o.CloseCursor
    '接続を切断する
    Call o.Close
End Sub

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

fromがないだけだったり?

"select * from hoge"

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/22 14:43

    ごめんなさい、実際にはあります。記入ミスです、修正します。

    キャンセル

0

DbDataReaderクラス(SQLDataReaderも含む)にはSQLクエリを引数とするコンストラクタがありません。
SqlCommandクラスを経由して下のコード(VBAの事は考えてません)のように使用してみてください。

SqlConnection con = new SqlConnection("SQL接続文字列");
SqlCommand command = new SqlCommand("select * from hoge", con);
con.Open();
SqlDataReader reader = command.ExecuteReader();
if(reader.HasRows)
{
    処理...
}
con.Close();
con.Dispose();

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/22 15:48

    やはり、C#で作ったDLL側の関数内で、VBAで受け取れるように別の形で返しなさいということですか?

    キャンセル

  • 2016/11/22 16:12 編集

    補足します。

    C#で下記のように書いています。(省略したるところや、別のクラスも登場しているので説明しずらいですが。)これをDLLにしました。そして、5つのメソッドを通して使おうとしています。
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    /////////////////////////////////////////////////////
    //DLLにする為
    using System.Net;
    using System.Runtime.InteropServices;
    /////////////////////////////////////////////////////
    //SQLServerとOracle使うため
    using System.Data;
    using System.Data.Common;
    using System.Data.SqlClient;
    using Oracle.ManagedDataAccess.Client;
    /////////////////////////////////////////////////////

    namespace TestOracle
    {
    [Guid (DbAccess.ClassId)]
    public class DbAccess
    {
    public const string ClassId = "1F9B0653-A03E-453D-8D9F-E1D3B965F18E";

    protected DbConnection connection = null;

    private ConnectionString xml = null;

    public void Open(string xmlFilePath)
    {
    ReadXml(xmlFilePath);

    if (null == connection)
    {
    connection = new OracleConnection();
    }

    connection.ConnectionString =
    string.Format(@"Data Source=({0}) ;User ID={1}; Password={2}; "
    , xml.XmlDataSource, xml.XmlUserId, xml.XmlPassword);

    this.Open();
    }

    protected void Open()
    {
    if (null != connection)
    {
    connection.Open();
    }
    }

    public void Close()
    {
    if (null != connection)
    {
    connection.Close();
    connection = null;
    }
    }

    public DbDataReader ExcuteReader(string sql)
    {
    DbCommand command = connection.CreateCommand();
    command.CommandText = sql;
    return command.ExecuteReader();
    }

    public int ExcuteNonQuery(string sql)
    {
    DbCommand command = connection.CreateCommand();
    command.CommandText = sql;
    return command.ExecuteNonQuery();
    }

    public DataTable Select(string sql)
    {
    DataTable resultData = new DataTable();

    DbDataAdapter dbAdapter = null;

    if (1 == GetDbType())
    {
    dbAdapter = new OracleDataAdapter();
    }
    else
    {
    dbAdapter = new SqlDataAdapter();
    }

    DbCommand command = connection.CreateCommand();
    command.CommandText = sql;
    dbAdapter.SelectCommand = command;
    dbAdapter.Fill(resultData);

    return resultData;
    }

    protected int GetDbType ()
    {
    int ret = 0;

    if (null != connection)
    {
    if (null != connection)
    {
    if (0 <= connection.GetType().ToString().ToUpper().IndexOf("ORACLE"))
    {
    ret = 1;
    }
    }
    }

    return ret;
    }

    protected void ReadXml(string strFilepath)
    {
    System.Xml.Serialization.XmlSerializer xmlSerial =
    new System.Xml.Serialization.XmlSerializer(typeof(ConnectionString));

    System.IO.FileStream fsR =
    new System.IO.FileStream(strFilepath, System.IO.FileMode.Open);

    xml = (ConnectionString)xmlSerial.Deserialize(fsR);

    fsR.Close();
    }
    }//class
    }

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.72%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる