Windows Shell 開発覚書
■パスからITEMIDLISTを取得するには
SHParseDisplayName
例:「c:\temp\my.txt」ファイルのITEMIDLISTを取得するとしよう
LPITEMIDLIST pItemIDLIST = NULL;
HRESULT hr = SHParseDisplayName(file, NULL, &pItemIDLIST, 0, NULL);
if (SUCCEEDED(hr)) {
CoTaskMemFree(pItemIDLIST); // 使い切ったら、開放すべき。
}
COM開発の覚書
#2019/06/18
◎IStream
■メモリから直接作成
・CreateStreamOnHGlobal
■BYTE配列から作成
・SHCreateMemStream
■既存ファイルから作成
・SHCreateStreamOnFile (Ex)
勘のまましてはいけないこと>>>>C# ulong vs VC ULONG
勘のままだと、両方同じサイズを持つものだ。実は間違いました。
C# の ulongは8バイトであり、
VCのULONGは unsigned long であって、4バイトでした。
ちなみに
DWORD = ULONG = unsigned long
CreateFileでAVStream minidriverから HANDLEの取得方法
マイクロソフトさんのドライバサンプルを例にする
ドライバに「コマンド(IOCTL)」を送る(DeviceIoControlを利用)際に、予め「CreateFile」で対象ドライバのハンドル(HANDLE)取るべき。
CreateFileの1つ目の引数にドライバから公開した「Symbolic Link」を使えばいいですが、AVStream minidriverみたいなWDMドライバだと、「IoCreateSymbolicLink」を使えないため、代わりに「IoRegisterDeviceInterface」を利用する。
サンプルでの実装だと、
①「device.cpp」の先頭に、以下の宣言を追加
const GUID IF_NAME_GUID =
{ 0xe7b615ba, 0x1909, 0x40a3,{ 0xbd, 0x24, 0xb2, 0x67, 0x14, 0xa6, 0x25, 0x52 } };
static UNICODE_STRING symbleName;
IF_NAME_GUIDはVisual Studio のツール「GUIDの作成」を利用し、作成する。
②「device.cpp」のCCaptureDevice::DispatchCreate静的関数の中に以下のソースを追加
...
if (!CapDevice) {
...
}
else {
KsAcquireDevice(Device);
...
if (NT_SUCCESS(Status)) {
Status = IoRegisterDeviceInterface(Device->PhysicalDeviceObject
, &IF_NAME_GUID, NULL, &symbleName);
if (NT_SUCCESS(Status)) {
DbgPrint("[avshws::DriverEntry] %S", symbleName.Buffer);
Status = IoSetDeviceInterfaceState(&symbleName, TRUE);
}
}
KsReleaseDevice(Device);
...
}
...
IoSetDeviceInterfaceStateルーチンの呼出しは設定したSymbolic Linkを有効させるため。
そうすると、以下のようなSymbolic Linkが出来上がり。
\\?\Root#UNKNOWN#0000#{GUID}
できたSymbolic Linkそのまま使えないので、下記の形にしてください。
\\?\Root#UNKNOWN#0000#{GUID}\GLOBAL
ドライバを開く
HANDLE file = CreateFile(L"\\\\?\\Root#UNKNOWN#0000#{GUID}\\GLOBAL"
,GENERIC_READ | GENERIC_WRITE
, FILE_SHARE_READ | FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0
, NULL);
==以上==
Javaアプリのリソースファイル(データ)を取得する際にリソースパスについ
・リソースの取得
すべてのJavaアプリに対し、下記3つのリソースがあれば
src
main
com
pkg
Main.java
main.properties
resources
template
1.html
my.properties
それぞれの取得に以下のパスで行う。
・main.properties
ClassLoader.getSystemResource("com/pkg/main.properties")
・1.html
ClassLoader.getSystemResource("template/1.html")
・my.properties
ClassLoader.getSystemResource("my.properties")
ではなぜなのか?実際にコンパイルしたフォルダの構成にかかってる
上記のソースフォルダツリーであれば、コンパイル後に以下のアウトプットをできる
classes
com
pkg
Main.class
main.properties
template
1.html
my.properties
つまり、リソースのパスはコンパイル後の場所と関係していることが分かりました。
2018/06/11 IntelliJの中に、リソースフォルダの追加方法
Visual Studio CodeでNODE-REDのデバッグ方法
NODE-REDのインストールは、
で書いてある「Developer」方法でスラスラやればいい。
もちろん誰よりも先にNodeJSのインストールを済ませる。
NODE-REDを起動する際に以下のコマンドラインで行ってください。
<node-red実施にインストールされたフォルダ>$ node --inspect-brk red.js
※ポイントは「--inspect-brk」オプションを付けること。当方のNodeJSのバージョンはv8.11.1、古い「--debug-brk」で付けると無視される。
上記の設定で問題なく起動すると、以下のメッセージを表示される。
Debugger listening on ws://127.0.0.1:9229/ee6542cb-bd43-46e5-b7ce-c681999f11db
For help see https://nodejs.org/en/docs/inspector
それから、Visual Studio Codeの登場
1.まず、node-redのインストール先フォルダを開く
2.デバッグ設定
3.上記設定を終わったら、アタッチしてデバッグを行いましょう。
==以上==
C#から文字列の配列をC/C++ DLLへの渡し方
■ネイティブ関数の引数が「char**」の場合
C関数
void init(int argc, char** argv);
[DllImport("XXXXX.dll")]
public static extern int init(int argc, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex =1)]string argv);
これは無難だろう
■ネイティブ関数の引数が構造体であって、その中に「char**」があった場合
C構造体
struct ARGS
{
int argc;
char** argv;
};
void init(struct ARGS * pArgs);
C#側
public struct ARGS
{
int Argc;
IntPtr Argv;
public ARGS(string argv)
{
Argc = argv.Length;
Encoding encoding = Encoding.GetEncoding(932);
List<string> list = new List<string>(argv);
Argv = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(IntPtr)) * list.Count);
for (int index = 0; index < list.Count; index++)
{
int len = encoding.GetByteCount(list[index]) + 1;
IntPtr point = Marshal.AllocCoTaskMem(len);
Marshal.Copy(encoding.GetBytes(list[index]), 0, point, len - 1);
Marshal.WriteByte(point, len - 1, 0);
Marshal.WriteIntPtr(Argv, index * Marshal.SizeOf(typeof(IntPtr)), point);
}
}
}
[DllImport("XXXXXX.dll")]
public static extern int Init(ref ARGS args);