WinCC (Siemens) (SCADA) のユーザー コントロールを作成しました。ここで、コントロールへのポインタを渡したいと思います。これを行う唯一の方法は、プロパティへのポインターを書き込むことです。
WinCC には、プロパティを設定するためのメソッドしかありません
- SetPropBOOL
- SetPropChar
- SetPropDouble
- SetPropWord
コントロールのプロパティにはデータ型として UInt があり、SetPropDouble メソッドを使用してオブジェクトからアドレスを設定します。
WinCC グローバル スクリプト (ANSI-C)
//autoDB is an ADODB.Connection object
//object* autoDB = __object_create("ADODB.Connection");
extern __object* autoDB;
//SetPropDouble( "PictureName", "ControlName", "PropertyName", (DWORD)(&autoDB) );
SetPropDouble( "PictureName", "ControlName", "PropertyName", (DWORD)autoDB );
コントロール (WinCC プロセスのフック) をデバッグしたところ、プロパティ セットにアドレス値 (例: 0x03041080) が割り当てられていることがわかりました。
ここで質問: アドレスで c# (.Net) のオブジェクトを取得するにはどうすればよいですか?
私の試みは例外をスローします: ExecutionEngineException
private ADODB.Connection _database;
private IntPtr _ptr = IntPtr.Zero;
public uint DataBase{
get{
return (uint)_ptr;
}
set{
if( value != 0 ){
_ptr = (IntPtr)value;
GCHandle gH = GCHandle.FromIntPtr(_ptr); // THIS LINE THROW THE EXCEPTION
_database = gH.Target;
}
}
}
OK: 使用するコードを変更しましたSTRING
WinCC
extern __object* autoDB;
DWORD addr = (DWORD)autoDB;
char sAddr[11];
sprintf( sAddr, "%d\0", addr );
SetPropChar( "PictureName", "ControlName", "DataBaseAddr", sAddr );
そしてc#は今
private string _lpszDataBaseAddr = "";
public string DataBaseAddr{
get{
return _lpszDataBaseAddr;
}
set{
uint addr;
bool ret = uint.TryParse( value, out addr );
if( ! ret ){
return;
}
IntPtr ptr = (IntPtr)addr;
GCHandle gH = GCHandle.FromIntPtr( ptr ); // THE SAME ERROR!
}
}
その他の発見!
ADO オブジェクトからのアドレスは、私のコントロールを呼び出したプロセス メモリにありません (ollydbg でデバッグ)。WinCC には 2 つのプログラムがあります。可視化用の PDLRT.exe (これは私のコントロールを呼び出しています) と GLOBAL-SCRIPT (Ansi-C) を実行するための SCRIPT.exe です。
PDLRT から、ADO-Object のポインタ アドレスにアクセスしました。ADO-object-address の C# で GCHandle を呼び出すと、例外がスローされます。(実行エンジン例外)