/// <summary> /// 引数の解決。 /// </summary> /// <param name="varManager">変数管理。</param> /// <param name="argsInfo">引数情報。</param> /// <param name="args">引数。</param> /// <param name="argTypes">引数の型。</param> internal static void ResolveArgs(VarPool varManager, object[] argsInfo, out object[] args, out Type[] argTypes) { args = new object[argsInfo.Length]; argTypes = new Type[argsInfo.Length]; for (int i = 0; i < argsInfo.Length; i++) { VarAddress handle = argsInfo[i] as VarAddress; //値の場合 if (handle == null) { args[i] = argsInfo[i]; if (args[i] != null) { argTypes[i] = args[i].GetType(); } } //変数の場合は登録されているオブジェクトに変換 else { VarAndType varAndType = varManager.GetVarAndType(handle); args[i] = varAndType.Core; argTypes[i] = varAndType.Type; } } }
/// <summary> /// 存命解除。 /// </summary> /// <param name="varAddress">変数アドレス。</param> internal void FreeKeepAlive(VarAddress varAddress) { lock (this) { int count = 0; if (!_keepAlive.TryGetValue(varAddress.Core, out count)) { return; } count--; if (count <= 0) { _keepAlive.Remove(varAddress.Core); if (!_handleAndObject.ContainsKey(varAddress.Core)) { //すでに変数プールから削除されているなら番号解放 _varAddressManager.FreeNo(varAddress.Core); } } else { _keepAlive[varAddress.Core] = count; } } }
/// <summary> /// 戻り値をAppVarで取得する通信。 /// </summary> /// <param name="invoker">呼び出し元。</param> /// <param name="friendlyConnector">アプリケーションとの接続者。</param> /// <param name="protocolType">通信タイプ。</param> /// <param name="operationTypeInfo">操作タイプ情報。</param> /// <param name="varAddress">変数アドレス。</param> /// <param name="typeFullName">タイプフルネーム。</param> /// <param name="operation">操作名称。</param> /// <param name="arguments">引数。</param> /// <returns>変数。</returns> internal static AppVar SendAndVarReceive(object invoker, IFriendlyConnector friendlyConnector, ProtocolType protocolType, OperationTypeInfo operationTypeInfo, VarAddress varAddress, string typeFullName, string operation, object[] arguments) { object value = SendAndValueReceive(invoker, friendlyConnector, protocolType, operationTypeInfo, varAddress, typeFullName, operation, arguments); VarAddress retHandle = value as VarAddress; return((retHandle == null) ? (null) : (new AppVar(friendlyConnector, retHandle))); }
/// <summary> /// オブジェクトの設定。 /// </summary> /// <param name="varAddress">変数アドレス。</param> /// <param name="obj">オブジェクト。</param> internal void SetObject(VarAddress varAddress, object obj) { lock (this) { //非同期実行時には、値を設定に来ても、受け取る変数自体が削除されていることがありうる if (_handleAndObject.ContainsKey(varAddress.Core)) { _handleAndObject[varAddress.Core] = new VarAndType(obj); } } }
/// <summary> /// 指定の変数アドレスが存在しない、またはnullであるか。 /// このメソッドはスレッドセーフである。 /// </summary> /// <param name="varAddress">変数アドレス。</param> /// <returns>指定の変数アドレスが存在しない、またはnullであるか。</returns> internal bool IsEmptyVar(VarAddress varAddress) { lock (this) { VarAndType varAndType; if (_handleAndObject.TryGetValue(varAddress.Core, out varAndType)) { return(object.ReferenceEquals(varAndType.Core, null)); } return(true); } }
/// <summary> /// 変数取得。 /// </summary> /// <param name="varAddress">変数アドレス。</param> /// <returns>変数。</returns> internal VarAndType GetVarAndType(VarAddress varAddress) { lock (this) { VarAndType varAndType; if (_handleAndObject.TryGetValue(varAddress.Core, out varAndType)) { return(new VarAndType(varAndType.Core, varAndType.Type)); } throw new InternalException(); } }
/// <summary> /// 存命登録。 /// </summary> /// <param name="varAddress">変数アドレス。</param> internal void KeepAlive(VarAddress varAddress) { lock (this) { int count = 0; if (!_keepAlive.TryGetValue(varAddress.Core, out count)) { count = 0; } count++; _keepAlive.Remove(varAddress.Core); _keepAlive.Add(varAddress.Core, count); } }
/// <summary> /// 呼び出し後の引数反映。 /// </summary> /// <param name="varManager">変数管理。</param> /// <param name="argsInfo">引数情報。</param> /// <param name="args">引数。</param> internal static void ReflectArgsAfterInvoke(VarPool varManager, object[] argsInfo, object[] args) { if (argsInfo.Length != args.Length) { throw new InternalException(); } for (int i = 0; i < argsInfo.Length; i++) { VarAddress handle = argsInfo[i] as VarAddress; if (handle != null) { varManager.SetObject(handle, args[i]); } } }
/// <summary> /// 存命登録解除。 /// </summary> /// <param name="varManager">変数管理。</param> /// <param name="arguments">引数情報。</param> /// <param name="handle">戻り値ハンドル。</param> static void FreeKeepAlive(VarPool varManager, object[] arguments, VarAddress handle) { if (handle != null) { varManager.FreeKeepAlive(handle); } for (int i = 0; i < arguments.Length; i++) { VarAddress aliveHandle = arguments[i] as VarAddress; if (aliveHandle != null) { varManager.FreeKeepAlive(aliveHandle); } } }
/// <summary> /// 削除。 /// </summary> /// <param name="varAddress">変数アドレス。</param> /// <returns>成否。</returns> internal bool Remove(VarAddress varAddress) { lock (this) { if (!_handleAndObject.ContainsKey(varAddress.Core)) { return(false); } _handleAndObject.Remove(varAddress.Core); if (!_keepAlive.ContainsKey(varAddress.Core)) { //存命中でなければ番号解放 _varAddressManager.FreeNo(varAddress.Core); } return(true); } }
/// <summary> /// メソッドorプロパティー実行。 /// </summary> /// <param name="async">非同期実行用。</param> /// <param name="varManager">変数管理。</param> /// <param name="info">呼び出し情報。</param> /// <param name="obj">実行対象オブジェクト。</param> /// <param name="args">操作実行引数。</param> /// <param name="method">メソッド情報。</param> /// <returns>戻り情報。</returns> static ReturnInfo ExecuteMethodOrProperty(IAsyncInvoke async, VarPool varManager, ProtocolInfo info, object obj, object[] args, MethodInfo method) { //戻り値 VarAddress handle = null; if (method.ReturnParameter.ParameterType != typeof(void)) { handle = varManager.Add(null); } //番号管理から消されないようにする KeepAlive(varManager, info.Arguments, handle); //非同期実行 async.Execute(delegate { ReturnInfo retInfo = new ReturnInfo(); try { object retObj = method.Invoke(obj, args); if (method.ReturnParameter.ParameterType != typeof(void)) { varManager.SetObject(handle, retObj); } //ref, outの解決 List <object> retArgsTmp = new List <object>(); retArgsTmp.Add(null); //完了通知変数を戻す。しかし、ここではまだ格納しない retArgsTmp.AddRange(args); ReflectArgsAfterInvoke(varManager, info.Arguments, retArgsTmp.ToArray()); } catch (Exception e) { retInfo = new ReturnInfo(new ExceptionInfo(e)); } //完了通知 varManager.SetObject((VarAddress)info.Arguments[0], retInfo); //存命状態を解く FreeKeepAlive(varManager, info.Arguments, handle); }); return(new ReturnInfo(handle)); }
/// <summary> /// フィールド操作実行。 /// </summary> /// <param name="async">非同期実行用。</param> /// <param name="varManager">変数管理。</param> /// <param name="info">呼び出し情報。</param> /// <param name="obj">実行対象オブジェクト。</param> /// <param name="args">操作実行引数。</param> /// <param name="field">フィールド情報。</param> /// <returns>戻り情報。</returns> static ReturnInfo ExecuteField(IAsyncInvoke async, VarPool varManager, ProtocolInfo info, object obj, object[] args, FieldInfo field) { //get if (args.Length == 0) { //戻り値格納用 VarAddress getVar = varManager.Add(null); //番号管理から消されないようにする KeepAlive(varManager, info.Arguments, getVar); //非同期実行 async.Execute(delegate { ReturnInfo retInfo = new ReturnInfo(); try { varManager.SetObject(getVar, field.GetValue(obj)); } catch (Exception e) { retInfo = new ReturnInfo(new ExceptionInfo(e)); } //完了通知 varManager.SetObject((VarAddress)info.Arguments[0], retInfo); //存命状態を解く FreeKeepAlive(varManager, info.Arguments, getVar); }); return(new ReturnInfo(getVar)); } //set else if (args.Length == 1) { //番号管理から消されないようにする KeepAlive(varManager, info.Arguments, null); //非同期実行 async.Execute(delegate { ReturnInfo retInfo = new ReturnInfo(); try { field.SetValue(obj, args[0]); } catch (Exception e) { retInfo = new ReturnInfo(new ExceptionInfo(e)); } //完了通知 varManager.SetObject((VarAddress)info.Arguments[0], retInfo); //存命状態を解く FreeKeepAlive(varManager, info.Arguments, null); }); return(new ReturnInfo()); } throw new InternalException(); }
/// <summary> /// コンストラクタ。 /// </summary> /// <param name="friendlyConnector">アプリケーションとの接続クラス。</param> /// <param name="varAddress">変数アドレス</param> internal AppVar(IFriendlyConnector friendlyConnector, VarAddress varAddress) { _friendlyConnector = friendlyConnector; _varAddress = varAddress; }
/// <summary> /// 戻り値を値で取得する通信処理。 /// 通信基本形。 /// </summary> /// <param name="invoker">呼び出し元。</param> /// <param name="friendlyConnector">アプリケーションとの接続者。</param> /// <param name="protocolType">通信タイプ。</param> /// <param name="operationTypeInfo">操作タイプ情報。</param> /// <param name="varAddress">変数アドレス。</param> /// <param name="typeFullName">タイプフルネーム。</param> /// <param name="operation">操作名称。</param> /// <param name="arguments">引数。</param> /// <returns>値。</returns> internal static object SendAndValueReceive(object invoker, IFriendlyConnector friendlyConnector, ProtocolType protocolType, OperationTypeInfo operationTypeInfo, VarAddress varAddress, string typeFullName, string operation, object[] arguments) { //配列の場合の調整 arguments = AdjustArrayArgs(arguments); ReturnInfo ret = friendlyConnector.SendAndReceive(new ProtocolInfo(protocolType, operationTypeInfo, varAddress, typeFullName, operation, ConvertAppVar(friendlyConnector, arguments))); GC.KeepAlive(invoker); GC.KeepAlive(friendlyConnector); for (int i = 0; i < arguments.Length; i++) { if (arguments[i] != null) { GC.KeepAlive(arguments[i]); } } if (ret.Exception != null) { throw new FriendlyOperationException(ret.Exception); } return(ret.ReturnValue); }
/// <summary> /// 同期実行。 /// しかし、Windowsの場合、操作実行は非同期で実行しないと、稀にに操作中にSendMessageが失敗してしまう操作がある。 /// そのため、非同期操作のプロトコルを使って、実行させ、終了するのを待つ。 /// </summary> /// <param name="info">呼び出し情報。</param> /// <param name="receiveWindow">受信ウィンドウ。</param> /// <returns>戻り値。</returns> private ReturnInfo Operation(ProtocolInfo info, ReceiveAfterSend receiveWindow) { //完了の成否確認用 ReturnInfo isComplete = SendForExecuteContext(new ProtocolInfo(ProtocolType.VarInitialize, null, null, string.Empty, string.Empty, new object[] { null }), receiveWindow); if (isComplete.Exception != null) { return(isComplete); } //引数の先頭に存在確認フラグを挿入 List <object> arg = new List <object>(); arg.Add(isComplete.ReturnValue); arg.AddRange(info.Arguments); //非同期実行 ReturnInfo retValue = SendForExecuteContext(new ProtocolInfo(ProtocolType.AsyncOperation, info.OperationTypeInfo, info.VarAddress, info.TypeFullName, info.Operation, arg.ToArray()), receiveWindow); if (retValue.Exception != null) { return(retValue); } //処理が完了するのを待つ VarAddress complateCheckHandle = (VarAddress)isComplete.ReturnValue; int sleepTime = 1; while (true) { //結果の確認は実行対象スレッド以外で実施する。 //処理が完了するまで、そのスレッドには割り込まない。 ReturnInfo ret = CopyDataProtocolTalker.SendAndRecieve(_friendlyConnectorWindowInAppHandleAsync, new ProtocolInfo(ProtocolType.IsEmptyVar, null, null, string.Empty, string.Empty, new object[] { complateCheckHandle }) , receiveWindow) as ReturnInfo; if (ret == null) { throw new FriendlyOperationException(ResourcesLocal.Instance.ErrorAppCommunication); } if (!(bool)ret.ReturnValue) { break; } Thread.Sleep(sleepTime); sleepTime++; if (100 < sleepTime) { sleepTime = 100; } } //結果を取得 ReturnInfo checkComplate = SendForExecuteContext(new ProtocolInfo(ProtocolType.GetValue, null, complateCheckHandle, string.Empty, string.Empty, new object[0]), receiveWindow); if (checkComplate.Exception != null) { return(checkComplate); } ReturnInfo checkComplateCore = checkComplate.ReturnValue as ReturnInfo; if (checkComplateCore == null) { throw new FriendlyOperationException(ResourcesLocal.Instance.ErrorAppCommunication); } if (checkComplateCore.Exception != null) { return(checkComplateCore); } //解放 NativeMethods.SendMessage(_friendlyConnectorWindowInAppHandle, FriendlyConnectorWindowInApp.WM_BINOFF, new IntPtr(complateCheckHandle.Core), IntPtr.Zero); //戻り値を返す return(retValue); }