とりあえず、今日から夏休みです。
取得するのに、相当紆余曲折がありましたが…
(というか、話せば話すほど社長は僕は水と油だということを感じる。色々良くないことも多くなってきたし、試用期間までが潮時、って言うか、それすらも持たないだろうな…)
…てな話はともかく、今回は番外編というか、本当に備忘録のような内容です。
C#とC++の型
ネイティブC++の関数を呼び出すとき、ちゃんとC#側で対応する引数の型を指定しないといけないけど、主な型の対応はこんな感じ。(とりあえず、関係しそうなものだけ)
C++ | C# |
WORD | short |
DWORD | uint |
LPSTR | string |
LPWSTR |
LPCSTR |
LPCWSTR |
void* | IntPtr |
HANDLE |
LPARAM |
WPARAM |
HRESULT | int |
MMRESULT |
ネイティブC++関数呼び出し時の引数指定
MSDNなどに記載してあるネイティブC++関数呼び出し時の汎用的なルール。
※あくまで「汎用的」であって、これに当てはまらないケースも当然ある。
C++での引数指定 | C#での引数指定 |
純粋な「型名」のみ(例:DWORD、WORD) | 対応する型の「値渡し」(ref、outキーワードなし) |
接頭語「LP」+「型名」(例:LPWORD、LPDWORD) | 対応する型の「参照渡し」(ref、outキーワードあり) |
ポインタ渡し(例:LPWORD*、LPDWORD*) | IntPtr型渡し |
※コールバック関数を指定する場合は「
C#でコールバック関数を使う」を参照のこと。
配列のポインタ
関数に構造体配列のポインタを渡す場合、例えばC++だと
STRUCTURE[] structure = new STRUCTURE[2];
func(&structure);
みたいな書き方でOKだが、C#で同じことをやろうとして、例えば
STRUCTURE[] structure = new STRUCTURE[2];
int str_size = Marshal.SizeOf(structure[0]) + Marshal.SizeOf(structure[1]);
IntPtr ptr_structure = Marshal.AllocCoTaskMem(str_size);
Marshal.StructureToPtr(structure, ptr_structure, false);
func(ptr_structure);
とやっても、コンパイルエラーになってしまう。
で、これをうまくやる方法を調べたのだが、結局は原始的な方法かも知れないが、1要素目のptr_structureの値と各要素のサイズを計算して
STRUCTURE[] structure = new STRUCTURE[2];
int str_size = Marshal.SizeOf(structure[0]) + Marshal.SizeOf(structure[1]);
IntPtr ptr_structure = Marshal.AllocCoTaskMem(str_size);
Marshal.StructureToPtr(structure[0], ptr_structure, false);
Marshal.StructureToPtr(structure[1], (IntPtr)((int)ptr_structure + Marshal.SizeOf(structure[0])), false);
みたいにするしか無いみたい。(もちろん、要素数が多いならループなどを使用するべき。)
構造体の「union」をC#で実装する方法
例えば、DirectSoundなどで使用する、WAVEFORMATEXTENSIBLE構造体は、
typedef struct {
WAVEFORMATEX Format;
union {
WORD wValidBitsPerSample;
WORD wSamplesPerBlock;
WORD wReserved;
} Samples;
DWORD dwChannelMask;
GUID SubFormat;
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
となっている。
この構造体の「union」に該当するキーワードはC#にはないが、「StructLayout」と「FieldOffset」の指定をうまく使うことで、構造体のunionと同じことを行うことが出来る。
[StructLayout(LayoutKind.Explicit)]
private struct WAVEFORMAT_EXTENSIBLE
{
[FieldOffset(0)]
public WAVEFORMATEX Format;
[FieldOffset(20)]
public ushort wValidBitsPerSample;
[FieldOffset(20)]
public ushort wSamplesPerBlock;
[FieldOffset(20)]
public ushort wReserved;
[FieldOffset(22)]
public uint dwChannelMask;
[FieldOffset(26)]
public Guid SubFormat;
}
…すいません。ちょっと手抜き感が否めないですが、今回はこれでご勘弁を。