2

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 を呼び出すと、例外がスローされます。(実行エンジン例外)

4

2 に答える 2