このブログ「吟遊詩人の戯言」 の記事検索...
1 2

C#&アンマネージDLLマーシャリング 普通の配列の受け取り

関連記事








【追記】

GCHandleを利用した
C#&アンマネージDLL 普通の配列の引渡し

方法を記載しました.参考にどうぞ!



いや,アンマネージな構造体配列の受け取りは,大昔書いていたんだけど
intやら,floatやらの配列は,p/Invokeが良きに計らってくれると思ってたり

 
 
 
 

【C#】ラインドール(Rijn.dll)のP/Invokeラッパー

関連記事




必要に迫られて(汗
ファイルの暗号化なぞ,やってみたり

ここで,お世話になったのが,ラインドール(Rijn.dll)
Rijndael(ラインダール)共通鍵暗号技術を利用したファイル暗号化フリーDLLです

詳細情報/ダウンロードはこちら@Type74 SoftWare

こちらでは,サンプルで,Delphiでの使用方法の記述がありました

昔Delphi屋,今C#屋なんで :mrgreen:

Delphiのコードを読んで,
C#マネージコードから,Rijn.dllを呼び出す,P/Invokeラッパーを書いて,稼動試験しました

問題なく,動きましたです

コードは,こちらに書いておきますです(簡単なんで,書くまでもなさそうですが(汗)

#region DLL-API定義
[DllImport("rijn.dll")]
private static extern int EncryptFile(string SourceFileName, string DestFileName, string key);	//暗号化
[DllImport("rijn.dll")]
private static extern int DecryptFile(string SourceFileName, string DestFileName, string key);	//復号化
#endregion

HANDLEからCDC*の取得

関連記事








C#の各コントロールが持っている,Handleプロパティ

こやつを,VC++で作成したDLLへ,渡した上で
最終的には,CDC*を必要としており

ちょいと探してみましたが
結構簡単,っぽい?

[CPP]
CDC* m_cdc;

extern “C” int WINAPI CDCFromhWnd(HWND hWnd)
{
CWnd* cw = CWnd::FromHandle(hWnd);
m_cdc = cw->GetDC();
}
[/CPP]

このコード,まだ,走らせてませんので
ちゃんと動くかどうか,分からないですわん

とりあえず,実装中の本体に組み込みますです

【追記】
結局,このコードは使わない方向へ(爆
描画は全部C#側でやってしまえぇ~~ 😎

実装作業…

関連記事




       ____
     /      \
   /  _ノ  ヽ、_  \
  /  o゚⌒   ⌒゚o  \  また,VC++で
  |     (__人__)    |  ノンマネージDLLを作成する仕事が始まるお・・・
  \     ` ⌒´     /


ひっさしぶりのVC++だわぁ~
ネイティブDLLこさえて,外向きAPIをいくつか実装して

って,ライブラリが,VC6用しか準備されていない件

VC8@VS2005は,文字コードが,UTFだしなぁ...
VC6用のライブラリ,ANSIだろうし.
衝突し無きゃいいけどなぁ...

とりあえず,やってみよう...

【解決編?】C#のアンマネージDLLマーシャリングで…

関連記事








ブログ側から記事を移動させました…



構造体配列の先頭ポインタを取る方法って,どう書くんだっけ?

の話

かなぁ~り,めんどくさい手段とれば,取れそうな感じ

まずはC++のDLL側ソース(さっきのソース,バグってます(ww)

//ヘッダ側(.h)
#ifndef __FUNC_TESTFUNC_H__
#define __FUNC_TESTFUNC_H__

#ifdef __cplusplus
  extern "C"
  {
#endif

typedef struct {
    float wx;
    float wy;
    float wz;
    int     x;
    int     y;
} POINT_LCTOWL, *PPOINT_LCTOWL;
 
int WINAPI get_PointInfoArray(PPOINT_LCTOWL &aryPtr, int &arySize);  //構造体配列の先頭ポインタと配列長を取得


#ifdef __cplusplus
  }
#endif


#endif	//__FUNC_CARIBXML_H__	

//実装側(.cpp)

#include "StdAfx.h"
#include "TestFunc.h"


POINT_LCTOWL g_PointInfoArray[10];

extern "C" int WINAPI get_PointInfoArray(PPOINT_LCTOWL &aryPtr, int &arySize)                  
{
    g_PointInfoArray[0].wx = 1;
    g_PointInfoArray[0].wy = 2;
    g_PointInfoArray[0].wz = 3;

    g_PointInfoArray[1].wx = 11;
    g_PointInfoArray[1].wy = 12;
    g_PointInfoArray[1].wz = 13;

    g_PointInfoArray[2].wx = 21;
    g_PointInfoArray[2].wy = 22;
    g_PointInfoArray[2].wz = 23;

    aryPtr  = &g_PointInfoArray[0];
    arySize = 10;
 
    return 0;
} 


んで,C#側
これがウルトラ面倒だわ


namespace arrydllTestOya
{
[StructLayout(LayoutKind.Sequential)]
public struct POINT_LCTOWL{
public float wx;
public float wy;
public float wz;
public int x;
public int y;
}

public partial class Form1 : Form
{
[DllImport(“arrayDllTest.dll”)]
public static extern int get_PointInfoArray(out IntPtr ary, out int aryCount);

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
POINT_LCTOWL[] a;
IntPtr b;
int ac;

get_PointInfoArray(out b, out ac);

a = new POINT_LCTOWL[ac];

int size = Marshal.SizeOf(typeof(POINT_LCTOWL));

for (int i = 0; i < ac; i++) {
//ポインタを、sizeずつずらしていく。
IntPtr current = new IntPtr(b.ToInt64() + (size * i));
//ポインタから構造体に変換して配列に格納。
a[i] = (POINT_LCTOWL)Marshal.PtrToStructure(
current, typeof(POINT_LCTOWL));
}


string st;

st = a[0].wx.ToString() + "," + a[0].wy.ToString() + "," + a[0].wz.ToString();
listBox1.Items.Add(st);

st = a[1].wx.ToString() + "," + a[1].wy.ToString() + "," + a[1].wz.ToString();
listBox1.Items.Add(st);

st = a[2].wx.ToString() + "," + a[2].wy.ToString() + "," + a[2].wz.ToString();
listBox1.Items.Add(st);

GC.Collect();
}
}
}
[/csharp]

    1.DLL側から,構造体配列の先頭ポインタをIntPtr型で受取り
    2.構造体配列のインスタンスを生成
    3.各要素ごとにIntPtrの値+構造体サイズのオフセット値を計算して
    4.3で計算した値をMarshal.PtrToStructure()にて,配列要素に叩き込む

って形にしないと,いけないっぽい


んで,問題が…

これ,DLL内で確保したメモリのアドレスを構造体の要素に突っ込んで行ってるけど
GC(ガーベジコレクション)が走ったら,DLL(アンマネージ)内のメモリ,勝手に解放しないか??

ちょいと心配…


    追記
      なんとなく,だけど,Marshal.PtrToStructure()って,ポインタの書き換えとか,やっているんじゃなくて
      IntPtrのメモリ位置から指定サイズ分のブロック切り出して,マーシャリング
      んで,配列の要素に,そのブロック実体をコピーしているような気がしてきた
      これなら,GCの解放動作とか,問題にはならないけど…

      でも毎度毎度,コピーするってのもなんだかなぁ(速度的にナニだし)

      DLL内部のメモリブロック,ポインタから直接参照するって方法,ないものかねぇ~



もう少し突っ込んでテストしてみるけど
基本,これで,DLL内の構造体配列は,参照できた,ということで♥


参考 : WTSEnumerateSessionsとP/Invoke@ぬるり。さんのページ

1 2