C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[13]: C++/CLRのpin_ptrについて


(過去ログ 48 を表示中)

[トピック内 14 記事 (1 - 14 表示)]  << 0 >>

■26510 / inTopicNo.1)  C++/CLRのpin_ptrについて
  
□投稿者/ tom (1回)-(2008/10/12(Sun) 18:51:15)

分類:[C++/CLI] 

初めまして。
C/CLIにて解決出来ない問題があり質問させて頂きます。

現在、メモリを管理するC言語APIを
C#のフォームから操作できるようにするものを構築しています。

具体的には
C言語APIは初期化時にメインメモリを渡し操作する関数群です。
それをCLRでラップし、C#から参照して操作したいと考えています。

その為、CLRクラスの中にC言語APIに渡すメモリを確保して保持したいので
pin_ptrを使おうと考えたのですが適切な使用方法が分かりません。
(どのサイトを見てもローカル変数としてしか使用していない)

下記のように

★ C言語
void  Initialize( void* pAddress, u32 uiSize )
{
}

があり、

★ CLR
ref struct STATE
{
  UInt32  state;
  UInt32  size;
};
// ----------------------------------------------------------------

// ----------------------------------------------------------------
ref struct MEM_INFO
{
  array<BYTE>^  Address;
  array<STATE>^ State; // エラー:トップレベルの '^' なしに、この型をここに使用することはできません。
  UInt32        StateCount;
};
// ----------------------------------------------------------------

// ----------------------------------------------------------------
public ref class MemoryManager
{
  public:
     MemoryManager();
    ~MemoryManager();
    !MemoryManager();
     
  public:
     Xu32   Initialize( UInt32 size );
     Xvoid  Finalize();
     
  public:
     ・
     ・
     ・
     
  private:
    pin_ptr<MEM_INFO>^	pMemoryInfo_; // エラー:pin_ptr の無効なターゲット型です。
//  MEM_INFO*  pMemoryInfo_;
};

といった感じでラップしようと考えたのですが

STATE、MEM_INFO、pin_ptr<MEM_INFO>^でエラーとなってしまいます。



C#のフォーム起動時に
MemoryMan_ = new MemoryManager();
MemoryMan_.Initialize( 1024 * 1024 * 64 ); // 指定された分のメモリを確保してCのAPIを呼び出す。

MemoryMan_を操作して色々とメモリ内を書き換えて

フォーム終了時に
MemoryMan_.Finalize();

したいだけなのですが・・・。


引用返信 編集キー/
■26511 / inTopicNo.2)  Re[1]: C++/CLRのpin_ptrについて
□投稿者/ tom (2回)-(2008/10/12(Sun) 18:53:29)
No26510 (tom さん) に返信
> 初めまして。
> C/CLIにて解決出来ない問題があり質問させて頂きます。
>
> 現在、メモリを管理するC言語APIを
> C#のフォームから操作できるようにするものを構築しています。
>
> 具体的には
> C言語APIは初期化時にメインメモリを渡し操作する関数群です。
> それをCLRでラップし、C#から参照して操作したいと考えています。
>
> その為、CLRクラスの中にC言語APIに渡すメモリを確保して保持したいので
> pin_ptrを使おうと考えたのですが適切な使用方法が分かりません。
> (どのサイトを見てもローカル変数としてしか使用していない)
>
> 下記のように
>
> ★ C言語
> void Initialize( void* pAddress, u32 uiSize )
> {
> }
>
> があり、
>
> ★ CLR
> ref struct STATE
> {
> UInt32 state;
> UInt32 size;
> };
> // ----------------------------------------------------------------
>
> // ----------------------------------------------------------------
> ref struct MEM_INFO
> {
> array<BYTE>^ Address;
> array<STATE>^ State; // エラー:トップレベルの '^' なしに、この型をここに使用することはできません。
> UInt32 StateCount;
> };
> // ----------------------------------------------------------------
>
> // ----------------------------------------------------------------
> public ref class MemoryManager
> {
> public:
> MemoryManager();
> ~MemoryManager();
> !MemoryManager();
>
> public:
> Xu32 Initialize( UInt32 size );
> Xvoid Finalize();
>
> public:
> ・
> ・
> ・
>
> private:
> pin_ptr<MEM_INFO>^ pMemoryInfo_; // エラー:pin_ptr の無効なターゲット型です。
> // MEM_INFO* pMemoryInfo_;
> };
>
> といった感じでラップしようと考えたのですが
>
> STATE、MEM_INFO、pin_ptr<MEM_INFO>^でエラーとなってしまいます。
>
>
>
> C#のフォーム起動時に
> MemoryMan_ = new MemoryManager();
> MemoryMan_.Initialize( 1024 * 1024 * 64 ); // 指定された分のメモリを確保してCのAPIを呼び出す。
>
> MemoryMan_を操作して色々とメモリ内を書き換えて
>
> フォーム終了時に
> MemoryMan_.Finalize();
>
> したいだけなのですが・・・。
>
>
引用返信 編集キー/
■26513 / inTopicNo.3)  Re[2]: C++/CLRのpin_ptrについて
□投稿者/ tom (4回)-(2008/10/12(Sun) 18:58:58)
間違いが御座いました。
お手数ですが削除をお願い出来ますでしょうか・・・。

引用返信 編集キー/
■26519 / inTopicNo.4)  Re[3]: C++/CLRのpin_ptrについて
□投稿者/ Azulean (206回)-(2008/10/13(Mon) 12:33:23)
1点目
ref struct と書いた場合、参照型の構造体になります。(これはC#からはクラスに見えます)
よって、array<STATE>^ ではなく、 array<STATE^>^ です。

2点目
pin_ptr に ^ はつけられません。
pin_ptr<MEM_INFO^> pMemInfo; が正しい形となります。

3点目
pin_ptr はマネージクラスのメンバーとして持たせることはできません。


何をやりたいのかにもよりますが、少なくとも pin_ptr ではできないかと思います。
GCHandle が近いのかなぁ。

とりあえず、C++/CLIと切り離して、C言語ではどう書くのか、どのように使うのかを明示できませんか。
引用返信 編集キー/
■26521 / inTopicNo.5)  Re[4]: C++/CLRのpin_ptrについて
□投稿者/ tom (5回)-(2008/10/13(Mon) 18:02:55)
Azuleanさん、ご返答有難う御座います。

> とりあえず、C++/CLIと切り離して、C言語ではどう書くのか、どのように使うのかを明示できませんか。


もし、Cで書かれたAPIをC++から使用する場合は

u32	MemoryManager::Initialize( u32 size )
{
	pMemoryInfo_->Address = new u8[ size ];
	
	InitializeMem( pMemoryInfo_->Address, size)	// CLIから呼び出したいC言語のAPI
}

void Finalize();
{
	delete[] pMemoryInfo_->Address;
}

と言った感じで使用します。

引用返信 編集キー/
■26522 / inTopicNo.6)  Re[5]: C++/CLRのpin_ptrについて
□投稿者/ tom (6回)-(2008/10/13(Mon) 18:16:22)
現状は以下のようにやっています。

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
u32 MemoryManager::Initialize( u32 size )
{
// このアドレスをFinalizeが呼ばれるまで保持し、
// ガーベージコレクションによるメモリ移動を許さない。
// ( C言語で組まれたAPIがメモリアドレス固定が前提な為 )
MemoryInfo_.Address = gcnew array<Byte>( size + 256 );

pin_ptr<Byte> p = &(MemoryInfo_.Address[ 0 ]);
Xvoid* pNative = p;

MemoryInfo_.CorrectAddress = (Xu32)pNative & ~(256-1);
MemoryInfo_.StubCount = 0;
MemoryInfo_.Stubs = nullptr;

::xMemoryInitialize( (void*)MemoryInfo_.CorrectAddress, size );

return MemoryInfo_.CorrectAddress;
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void MemoryManager::Finalize()
{
}


このCLIプロジェクトはC言語のAPIのテストドライバー(GUIを使用した)である為、
現状はC言語のAPIプログラムをCLIプロジェクトに登録して使っています。
これは問題でしょうか・・・?



引用返信 編集キー/
■26523 / inTopicNo.7)  Re[6]: C++/CLRのpin_ptrについて
□投稿者/ Azulean (207回)-(2008/10/13(Mon) 18:48:49)
>   // ( C言語で組まれたAPIがメモリアドレス固定が前提な為 )
>   MemoryInfo_.Address = gcnew array<Byte>( size + 256 );
そのAddressの中身をC#側で知る必要があるのでしょうか?

もし、C言語の関数を通す部分をC#に見せずに済むのであれば、ネイティブの構造体を隠蔽するクラスとして実装した方が楽かなと。
ちなみに、C++/CLIでもアンマネージなメモリ領域(GCの管轄外)を確保することができます。
(gcnewではなくnewで確保する等)

例
// ネイティブ構造体の一例
struct NativeStruct
{
	unsigned char* pAddr;
	int nCount;
};

// ネイティブ構造体を隠蔽するマネージクラス
public ref class ManagedClass
{
private:
	NativeStruct* m_pNativeStruct;

	void FreeNativeMemory()
	{
		if (m_pNativeStruct != nullptr)
		{
			if (m_pNativeStruct->pAddr != nullptr)
			{
				delete[] m_pNativeStruct->pAddr;
				m_pNativeStruct->pAddr = nullptr;
			}
			delete m_pNativeStruct;
			m_pNativeStruct = nullptr;
		}
	}

public:
	ManagedClass()
	{
		m_pNativeStruct = new NativeStruct;
		m_pNativeStruct->nCount = 256;
		m_pNativeStruct->pAddr = new unsigned char[256];
	}
	~ManagedClass()
	{
		FreeNativeMemory();
	}
	!ManagedClass()
	{
		FreeNativeMemory();
	}
};

※メンバー変数にポインタとしてネイティブの型を持つ。

ところで、
>   MemoryInfo_.CorrectAddress  = (Xu32)pNative & ~(256-1);
アドレスにそんなマスクかけても大丈夫なんですか?

引用返信 編集キー/
■26524 / inTopicNo.8)  Re[7]: C++/CLRのpin_ptrについて
□投稿者/ tom (7回)-(2008/10/13(Mon) 19:19:30)
Azuleanさん、大変親切なご返答有難う御座います。


C#側では確保したメモリを知る必要はありません。
C言語のAPIを初期化したラッパークラスが管理しています。
C#側で取得したいのはラッパークラスの持つ
State構造体とStateCountだけです。

>ところで、
>> MemoryInfo_.CorrectAddress = (u32)pNative & ~(256-1);
>アドレスにそんなマスクかけても大丈夫なんですか?

CLIでは駄目ですかね?(^^;
C++ではアドレスのアライメントの為にやります。


CLIの知識が無さ過ぎで申し訳御座いません。
CLIではgcnewではなくnewでもOKなんですか?

当初、CをラップしたCLIで

u32 MemoryManager::Initialize( u32 size )
{
MemoryInfo_.Address = new Byte[] ( size + 256 );
MemoryInfo_.CorrectAddress = (u32)MemoryInfo_.Address & ~(256-1);
MemoryInfo_.StubCount = 0;
MemoryInfo_.Stubs = NULL;

::xMemoryInitialize( (void*)MemoryInfo_.CorrectAddress, size );

return MemoryInfo_.CorrectAddress;
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void MemoryManager::Finalize()
{
delete[] MemoryInfo_.Address;
}

としていたのですが3回に1度は『delete[] MemoryInfo_.Address;』
でメモリ保護違反で終了してしまうのでgcnewにしないと駄目なのかな〜?
と思いまして・・・。

引用返信 編集キー/
■26525 / inTopicNo.9)  Re[8]: C++/CLRのpin_ptrについて
□投稿者/ Azulean (208回)-(2008/10/13(Mon) 19:38:05)
> >ところで、
> >> MemoryInfo_.CorrectAddress = (u32)pNative & ~(256-1);
> >アドレスにそんなマスクかけても大丈夫なんですか?
>
> CLIでは駄目ですかね?(^^;
> C++ではアドレスのアライメントの為にやります。
C++でも基本的にNGじゃないですか?
例えば、newで0x12345678というアドレスが帰ってきたとき、そのマスクをかけた(& 0xFFFFFF00)結果は0x12345600ですよね?
そこは何があるか分からないのでは?

> CLIの知識が無さ過ぎで申し訳御座いません。
> CLIではgcnewではなくnewでもOKなんですか?
gcnewとnewでは意味が異なります。
何でもかんでもOKではないので、そのあたりはMSDNや書籍を読んで確認して下さい。

> としていたのですが3回に1度は『delete[] MemoryInfo_.Address;』
> でメモリ保護違反で終了してしまうのでgcnewにしないと駄目なのかな〜?
> と思いまして・・・。
それとgcnewは無関係でしょう。
先にも書きましたが、変なメモリアドレスに書き込んでいて、メモリ破壊を起こしているのでdelete[]の際のチェックに引っかかっているだけでは?
引用返信 編集キー/
■26526 / inTopicNo.10)  Re[9]: C++/CLRのpin_ptrについて
□投稿者/ tom (9回)-(2008/10/13(Mon) 19:42:36)
NGではありませんよ。(^^;

アライメントの分だけ『多く』メモリを確保していますから。

MemoryInfo_.Address = new Byte[] ( size + 256 );
MemoryInfo_.CorrectAddress = (u32)MemoryInfo_.Address & ~(256-1);

通常のメモリアロケーションAPIが内部でやることです。

開放する時のメモリアドレスは補正前のアドレスでdeleteしています。
delete[] MemoryInfo_.Address;

引用返信 編集キー/
■26527 / inTopicNo.11)  Re[10]: C++/CLRのpin_ptrについて
□投稿者/ Azulean (209回)-(2008/10/13(Mon) 19:45:00)
> アライメントの分だけ『多く』メモリを確保していますから。
その『多く』は後ろでは?
前方にはないでしょって意味合いです。

> MemoryInfo_.Address = new Byte[] ( size + 256 );
> MemoryInfo_.CorrectAddress = (u32)MemoryInfo_.Address & ~(256-1);
あえてやるなら、こんなところ?

MemoryInfo_.Address = new Byte[] ( size + 256 );
MemoryInfo_.CorrectAddress = (u32)(MemoryInfo_.Address + 0x100) & 0xFFFFFF00;

0x100足しているのは確保の時点で256 = 0x100分の拡張が保証されているので、下2桁によらず、+0x100しても問題なく、さらにマスクをかけることで下2桁が00のアドレスを得られるのかなと。

引用返信 編集キー/
■26528 / inTopicNo.12)  Re[11]: C++/CLRのpin_ptrについて
□投稿者/ Azulean (210回)-(2008/10/13(Mon) 19:50:26)
> MemoryInfo_.Address = new Byte[] ( size + 256 );
> MemoryInfo_.CorrectAddress = (u32)(MemoryInfo_.Address + 0x100) & 0xFFFFFF00;
カッコの位置が間違っている…。orz

MemoryInfo_.CorrectAddress = ((u32)MemoryInfo_.Address + 0x100) & 0xFFFFFF00;
引用返信 編集キー/
■26529 / inTopicNo.13)  Re[12]: C++/CLRのpin_ptrについて
□投稿者/ tom (10回)-(2008/10/13(Mon) 20:21:17)
ラウンドダウンのつもりがラウンドアップしちゃってますね〜。
・・・御免なさい〜!

orz

これが原因だったのか・・・。

Azuleanさん、有難う御座います。

解決済み
引用返信 編集キー/
■26530 / inTopicNo.14)  Re[13]: C++/CLRのpin_ptrについて
□投稿者/ tom (11回)-(2008/10/13(Mon) 20:22:52)
ラウンドダウンのつもりが・・・

訂正

ラウンドアップのつもりがラウンドダウンしちゃってます。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -