none
native C++で、C++/CLIのDLLを参照する方法 RRS feed

  • 質問

  • 以下の点について教えていただけると助かります。

    1.C++/CLIでOracleにアクセスするDLLの作成方法について

      (1)Oracleへのアクセス方法

        ・SELECT文によるデータの取得方法

        ・INSERT文、UPDATE文、DELETE文の実行方法

    2.native C++と1.で作成したC++/CLIのDLLとのデータ連携について

      (1)native C++からC++/CLIで作成されたDLLを参照するための設定の仕方および参照方法

      (2)native C++とC++/CLIで作成されたDLLとのデータ受け渡し方法

    (環境)

      Visual Studio 2008

      Oracle 11g R2

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


    2013年12月25日 2:17

回答

  • native C++とC++/CLIとのやり取り方法は、native C++同士のやり取りと同じです。

    Oracleは…Oracle社からライブラリが提供されていませんか?

    2013年12月25日 7:46
  • ですから、native C++同士のやり取りと同じです。native C++同士でも敢えてCOMに公開してそれを呼び出すこともできます。
    ですが大抵は通常の関数呼び出し、printf()を呼び出すのと同じ方法でやり取りします。
    2013年12月26日 1:49

すべての返信

  • native C++とC++/CLIとのやり取り方法は、native C++同士のやり取りと同じです。

    Oracleは…Oracle社からライブラリが提供されていませんか?

    2013年12月25日 7:46
  • 佐祐理さん、返信どうもありがとうございます。

    C++/CLIで作成したDLLとのやりとりを行う場合は、COMに公開するかどうかを指定しなければいけないと聞いているのですが

    具体的にどのように指定すれば良いのかわかりません。

    Oracleについては、参照の追加でOracleDataAccessを追加すればよいことがわかりました。

    2013年12月26日 1:35
  • ですから、native C++同士のやり取りと同じです。native C++同士でも敢えてCOMに公開してそれを呼び出すこともできます。
    ですが大抵は通常の関数呼び出し、printf()を呼び出すのと同じ方法でやり取りします。
    2013年12月26日 1:49
  • 佐祐理さん、返信どうもありがとうございます。

    C++/CLIで作成したDLLとのやりとりを行う場合は、COMに公開するかどうかを指定しなければいけないと聞いているのですが

    具体的にどのように指定すれば良いのかわかりません。

    Oracleについては、参照の追加でOracleDataAccessを追加すればよいことがわかりました。

    kotaro_20050623さん

    こんにちは。

    native C++からC++/CLIのDLLを呼び出したいということでしたら、

    A)C++/CLIのDLLを作成する(この手順はわかりますか?)

    B)A)のDLLをnativeC++のexeあるいはdllから静的あるいは動的リンクしてA)を呼びだす

    まずはどこまでわかるか、教えていただけませんか?

    ご質問の内容だと、COMの話はあまり関係ないように思いますので。

    2013年12月26日 5:30
  • にゃにゃおさん

    こんにちは。

    A)の作成手順はわかります。(補足:先々このDLLをC#から呼び出して使用する予定です。)

    B)のリンクして呼び出すところがよくわかりません。

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

    2013年12月26日 6:23
  • そもそもnative C++同士での呼び出し方はわかっているのでしょうか? native C++を扱えないのにC++/CLIを扱うのは非常に困難ですよ。
    2013年12月26日 6:30
  • にゃにゃおさん

    こんにちは。

    A)の作成手順はわかります。(補足:先々このDLLをC#から呼び出して使用する予定です。)

    B)のリンクして呼び出すところがよくわかりません。

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

    kotaro_20050623さん

    こんにちは。

    B)の手順について少しだけ触れますね。

    DLLのリンクには、動的リンクと静的リンクというのがあります。

    前者は”LoadLibrary”APIを使って、必要なタイミングでロードして使います(言い換えるとEXE起動時にはなくてもよい)

    後者はC++/CLIのDLLをコンパイルすると作成されるlibファイルを、乱暴な言い方をするとEXEのコンパイル時に取り込んでしまいます。EXE起動時にDLLが必要になります。

    前者は呼び出し方が多少複雑になるので、今回は後者をおすすめします。

    静的リンクのやり方は、ソース内に

    #pragma comment(lib,"LIBファイル名")

    と記述するか、VisualStudioのプロジェクトの設定で行えます。

    A)はおわかりだということは、

    __declspec(dllexport) unsigned long Foo()←Foo()はkotaroさん作成の関数名にします

    この意味がわかるということでよろしいでしょうか?




    2013年12月26日 7:41
  • そもそもnative C++同士での呼び出し方はわかっているのでしょうか? native C++を扱えないのにC++/CLIを扱うのは非常に困難ですよ。

    佐祐理さん

    現在、native C++同士のことも調べながらC++/CLIとの連携を調査しているため、十分に理解しているとは言い切れません。

    ただ、native C++からC#で作成したDLLを呼び出してOracleにアクセスする方法については調査済みであり、

    この調査結果で、文字列のコード変換が必要なことや構造体配列のデータをパラメータで受け渡しするのが複雑であることはわかっております。

    そのため、他の方法としてC++/CLIでDLLを作成した場合に具体的にどのように連携すればよいか調査しているところです。

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

    2013年12月26日 8:38
  • にゃにゃおさん

    >__declspec(dllexport) unsigned long Foo()←Foo()はkotaroさん作成の関数名にします

    >この意味がわかるということでよろしいでしょうか?

    はい、わかります。

    2013年12月26日 8:45
  • 登場人物が多いようですがきちんと把握できていますか?

    • native C++
    • C++/CLI
    • C#(最初の質問文には含まれておらず後から追加された)
    • Oracle Data Access Components

    とあり、

    • native C++がC++/CLIを呼び出す
    • native C++がC#を呼び出す
    • C#がC++/CLIを呼び出す
    • C++/CLIがOracleを呼び出す
    • C#がOracleを呼び出す

    の話題が書かれていました。ご自身で、本当の目的を把握できていますか? 変に遠回りをして、その遠回りをしている部分に引っかかっていたりしませんか?

    もしnative C++がOracleを呼び出したいだけであれば、C++/CLIもC#も不要ですよ。

    2013年12月26日 22:58
  • 佐祐理さん

    以下の要望事項を受けて調査をしています。

    (要望事項)
    1.Oracle11gをアクセスする処理のクラスを作成しDLL化したい。
    2.現行のnative C++の資産を活かし、Oracleをアクセスするところのみ上記1.に切り替えたい。
    3.新規のプログラムはC#で作成し上記1.で作成した処理を利用したい。
    4.将来は、native C++で作成されたプログラムをC#に置き換えたい。
    5.上記を満たす処理方法の中で、処理速度や開発者のミスの少なさ等を考慮して処理方法を決定したいので
      サンプルプログラムを作成して欲しい。

    上記の要望を踏まえて、次の処理方法について具体的な記述方法などを調査しています。
    (処理方法)
    案1.native C++ ⇒ C#のクラスのDLL ⇒ OracleDataAccess Compornents ⇒ Oracle
    案2.native C++ ⇒ C++/CLIのクラスのDLL ⇒ OracleDataAccess Compornents ⇒ Oracle
    案3.native C++にC++/CLIでOracleにアクセスする処理のクラスを作成し組み込む ⇒ OracleDataAccess Compornents ⇒ Oracle
       ※Oracleにアクセスする処理のクラスを抜き出してDLLを作成し案4の方法で利用する。
    案4.C# ⇒ C++/CLIのクラスのDLL ⇒ OracleDataAccess Compornents ⇒ Oracle

    今回は案2に関する質問になります。

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

    2013年12月27日 2:12
  • kotaro_20050623さん

    こんにちは。

    具体例を書きます。

    <C++/CLI側>

    仮にDLL名を"Oracle_cli.dll"とします。

    1)EXEが#includeするための公開ヘッダファイル(例:oracle_cli_exp.h)

    #ifndef __ORACLE_CLI_EXP_H__
    #define __ORACLE_CLI_EXP_H__

    #ifdef __cplusplus
    extern "C"
    {
    __declspec(dllexport) unsigned long OracleCLI_Select();
    #endif
    #ifdef __cplusplus
    }
    #endif

    #endif

    2)DLLの実装

    __declspec(dllexport) unsigned long OracleCLI_Select()
    {
    oracle_cli::OracleAccessor^ oracle = gcnew oracle_cli::OracleAccessor();
          oracle->ExcecuteSQL(SQL文);

            return 0;

    }    

    <EXE側>

    #include "oracle_cli_exp.h"

    #pragma comment(lib, "oracle_cli.lib")

    int _tmain(int argc, _TCHAR* argv[])
    {
    unsigned long a = OracleCLI_Select();
    }

    これだけでOKです。

    佐祐理さんがいわれるように、純粋にnativeC++(unmanaged)だけの実装と変わりません。

    いかがでしょうか?

    2013年12月27日 4:11
  • そういう背景でしたか。挙げられている要望事項についてコメントしておくと、

    .NETと非.NETとでデータ型を共用・共通化することはできません。つまり、C++/CLIのクラスがデータを返す時、C#向けのデータとnative C++向けのデータとで完全に別物になってしまいます。つまり2.と3.もしくは2.と4.は両立しません。

    ただし、質問者さんが触れられていたように.NETクラスをCOMから操作することで共用することができます。…が、native C++側にそれなりの改造が必要になります。

    1. COMを使わず、native C++からOracleへ直接参照 及び C#からOracleへ直接参照 の2本立て
    2. COMを使い、.NET DLL(C#もしくはC++/CLI)でOracleに参照し、native C++からCOM経由で.NET DLLを参照

    のどちらの方式を選択するかを決定する必要があると思います。

    # 当初、背景もわからず無下にCOM使用を否定して申し訳ありませんでした。

    2013年12月27日 4:15
  • にゃにゃおさん

    具体例どうもありがとうございます。

    これをもとにサンプルプログラムを作成してみようと思いますが
    データの受け渡しについて教えていただけますでしょうか?

    DLL側の処理で、SELECT処理により複数レコードが抽出されることを考えて
    構造体配列に取得した結果を格納しようと思っています。
    この取得した構造体配列のデータをEXE側の処理で直接参照できるのでしょうか?
    それともパラメータでの受け渡しにしなければいけないのでしょうか?
    ※直接参照できるのであれば構造体配列には文字列項目と数値項目を混在させる予定です。

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

    2013年12月27日 5:05
  • 佐祐理さん

    コメント及びご意見どうもありがとうございます。

    こちらからの説明不足で申し訳ありませんでした。

    どの方式にするか検討を進めていこうと思います。

    2013年12月27日 5:20
  • にゃにゃおさん

    具体例どうもありがとうございます。

    これをもとにサンプルプログラムを作成してみようと思いますが
    データの受け渡しについて教えていただけますでしょうか?

    DLL側の処理で、SELECT処理により複数レコードが抽出されることを考えて
    構造体配列に取得した結果を格納しようと思っています。
    この取得した構造体配列のデータをEXE側の処理で直接参照できるのでしょうか?
    それともパラメータでの受け渡しにしなければいけないのでしょうか?
    ※直接参照できるのであれば構造体配列には文字列項目と数値項目を混在させる予定です。

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

    こんにちは。

    データの受け渡しについてですが、全件取得するというのはあまり考えないほうがよいとおもいます。

    (大量データを全件取得しようとするときっとメモリが足りません)

    1. C++/CLIのDLLの中だけで処理する(データ受け渡しせずに、DLLの中で必要な処理をする)
    2. EXEの中で処理する

    のどちらかがよいとおもいます。

    受け渡しのイメージをおもちなら、直接OracleDataAccessを使用する2.がよいです。

    ExecuteReaderの結果も、そのままEXEの中で使うことができますので。

    SELECTの結果をどうされたいでしょうか?

    2013年12月27日 7:36
  • データの受け渡しについてですが、全件取得するというのはあまり考えないほうがよいとおもいます。
    ちょっと脱線しますが…今どき数GB、数十GBぐらいのメモリは積んでますから、データ規模にも依りますが規模相応のコンピュータが使用されると考えると、案外、全件読み込んだ方がいちいちディスクアクセスするよりも早いってことは十分にありますよ。
    2013年12月27日 7:42
  • にゃにゃおさん

    今考えているのは、

    EXE側より必要な情報(ユーザーID、パスワード、接続識別子、抽出条件)をDLL側に渡してデータを取得し、

    その取得結果をもとにEXE側でファイル出力や条件などにより更新処理にデータを渡したりすることです。

    DLL側には、SELECT処理、INSERT処理、UPDATE処理、DELETE処理の各クラスを作成する予定です。

    データ量もかなり多いのでどのようにするか検討する予定です。

    2013年12月27日 8:21
  • 目的とkotaro_20050623さんの考えている手段がよく読み取れないのですが、要は「現在ネイティブC++で作成しているプログラムを、徐々に.NET(C#)化したいので、ネイティブC++と.NET(C#)で作成したプログラムとの連携方法を知りたい」ということでしょうか?

    それでしたら、以下の記事が参考になると思います。

    [連載! とことん VC++] 第 8 回 C++/CLI を利用した相互運用 ~ネイティブ C++ から .NET の利用~ 言語: C++:
    http://code.msdn.microsoft.com/VisualC-ee06b200
    [連載! とことん VC++] 第 9 回 C++/CLI を利用した相互運用 ~.NET からのネイティブ C++ 資産の再利用~ 言語: C#, C++:
    http://code.msdn.microsoft.com/VisualC-a1dc1f1d
    [C++] C++/CLI を用いて、.NET 対応アプリケーションから MFC 対応クラスを使用する 言語: C++:
    http://code.msdn.microsoft.com/windowsdesktop/VisualC-howto-76f9cd9e

    2013年12月27日 16:47
  • にゃにゃおさん

    今考えているのは、

    EXE側より必要な情報(ユーザーID、パスワード、接続識別子、抽出条件)をDLL側に渡してデータを取得し、

    その取得結果をもとにEXE側でファイル出力や条件などにより更新処理にデータを渡したりすることです。

    DLL側には、SELECT処理、INSERT処理、UPDATE処理、DELETE処理の各クラスを作成する予定です。

    データ量もかなり多いのでどのようにするか検討する予定です。

    こんにちは。

    となると、以下の考え方ではいかがでしょうか?

    1. INSERT処理の場合、DLLにSELECT条件を渡して、SELECT→INSERTする
    2. UPDATE処理の場合、DLLにUPDATE条件を渡して、SELECT→UPDATEする
    3. DELETE処理の場合、DLLにDELETE条件を渡して、SELECT→DELETEする

    SELECT結果を画面表示したいというような場合は、DLLに描画先のコントロールを渡して、そのコントロールに対して表示してやればよいとおもいます。

    SELECT結果を全件取得して返す、というのは搭載メモリ量が仮に多い場合でも、私はやらないほうがよいとおもいます。

    メモリ使用量の観点というより、処理がワンステップ増えてしまいますよね。

    本当は、

    SELECT→何かの処理

    ですむのに、

    SELECT→何処かのバッファに格納→何かの処理

    でワンステップ増えちゃいます。

    2013年12月28日 4:13
  • ちちびんたリカさん

    返信が遅くなって申し訳ありません。

    現時点では、ちちびんたリカさんの認識されて通りです。

    紹介していただいた記事を参考にさせていただきます。

    2014年1月6日 2:19
  • にゃにゃおさん

    返信が遅くなって申し訳ありません。

    にゃにゃおさんの考え方もひとつの案として検討を進めていこうと思います。

    2014年1月6日 2:29