/
smwwiki
/
OneScript_fork
Обзор
Документация
Войти
/
smwwiki
/
OneScript_fork
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
src/OneScript.StandardLibrary/NativeApi/NativeApiComponent.cs
301 строка
10 KB
EvilBeaver
Замечания сонара по паттерну Dispose
26 окт 2023, 11:53
26 окт 2023, 11:53
b21d19c
Код
Авторство
О чём код?
/*---------------------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v.2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ using System; using OneScript.Contexts; using OneScript.Exceptions; using OneScript.Types; using OneScript.Values; using ScriptEngine.Machine; namespace OneScript.StandardLibrary.NativeApi { /// <summary> /// Экземпляр внешней компоненты Native API /// </summary> class NativeApiComponent : NativeApiValue, IRuntimeContextInstance, IDisposable { private IntPtr _object; public override IRuntimeContextInstance AsObject() { return this; } public event OnComponentEvent OnComponentEvent; public event OnComponentError OnComponentError; public event OnComponentStatusText OnComponentStatusText; private enum ErrorCodes { ADDIN_E_NONE = 1000, ADDIN_E_ORDINARY = 1001, ADDIN_E_ATTENTION = 1002, ADDIN_E_IMPORTANT = 1003, ADDIN_E_VERY_IMPORTANT = 1004, ADDIN_E_INFO = 1005, ADDIN_E_FAIL = 1006, ADDIN_E_MSGBOX_ATTENTION = 1007, ADDIN_E_MSGBOX_INFO = 1008, ADDIN_E_MSGBOX_FAIL = 1009, } private static string S(IntPtr ptr) { return NativeApiProxy.Str(ptr); } private MessageStatusEnum Status(ushort wcode) { switch ((ErrorCodes)wcode) { case ErrorCodes.ADDIN_E_NONE: return MessageStatusEnum.WithoutStatus; case ErrorCodes.ADDIN_E_ORDINARY: return MessageStatusEnum.Ordinary; case ErrorCodes.ADDIN_E_IMPORTANT: return MessageStatusEnum.Important; case ErrorCodes.ADDIN_E_INFO: return MessageStatusEnum.Information; case ErrorCodes.ADDIN_E_VERY_IMPORTANT: case ErrorCodes.ADDIN_E_FAIL: return MessageStatusEnum.VeryImportant; case ErrorCodes.ADDIN_E_ATTENTION: case ErrorCodes.ADDIN_E_MSGBOX_ATTENTION: case ErrorCodes.ADDIN_E_MSGBOX_INFO: case ErrorCodes.ADDIN_E_MSGBOX_FAIL: return MessageStatusEnum.Attention; default: return MessageStatusEnum.Ordinary; } } public NativeApiComponent(object host, NativeApiLibrary library, TypeDescriptor typeDef, string componentName) { if (!NativeApiProxy.IsAvailable) throw new RuntimeException("Native API Proxy DLL is not loaded"); _object = NativeApiProxy.GetClassObject(library.Module, componentName, (wcode, source, descr, scode) => { OnComponentError?.Invoke(Status(wcode), scode, S(source), S(descr)); }, (source, message, data) => { OnComponentEvent?.Invoke(S(source), S(message), S(data)); }, (status) => { OnComponentStatusText?.Invoke(S(status)); } ); DefineType(typeDef); } public bool IsIndexed => true; public bool DynamicMethodSignatures => false; public IValue GetIndexedValue(IValue index) { var propNum = GetPropertyNumber(index.AsString()); return GetPropValue(propNum); } public void SetIndexedValue(IValue index, IValue value) { var propNum = GetPropertyNumber(index.AsString()); SetPropValue(propNum, value); } public int GetPropertyNumber(string name) { var propNumber = NativeApiProxy.FindProp(_object, name); if (propNumber < 0) throw PropertyAccessException.PropNotFoundException(name); return propNumber; } public bool IsPropReadable(int propNum) { return NativeApiProxy.IsPropReadable(_object, propNum); } public bool IsPropWritable(int propNum) { return NativeApiProxy.IsPropWritable(_object, propNum); } public int GetPropCount() { return NativeApiProxy.GetNProps(_object); } public string GetPropName(int propNum) { var name = string.Empty; NativeApiProxy.GetPropName(_object, propNum, 0, n => name = NativeApiProxy.Str(n) ); return name; } public IValue GetPropValue(int propNum) { IValue result = ValueFactory.Create(); NativeApiProxy.GetPropVal(_object, propNum, variant => result = NativeApiVariant.Value(variant) ); return result; } public void SetPropValue(int propNum, IValue value) { using (var variant = new NativeApiVariant()) { variant.Assign(value); NativeApiProxy.SetPropVal(_object, propNum, variant.Ptr); }; } public int GetMethodsCount() { return NativeApiProxy.GetNMethods(_object); } public int GetMethodNumber(string name) { var methodNumber = NativeApiProxy.FindMethod(_object, name); if (methodNumber < 0) throw RuntimeException.MethodNotFoundException(name); return methodNumber; } public BslMethodInfo GetMethodInfo(int methodNumber) { var method = BslMethodBuilder.Create(); if (methodNumber < 0) throw new RuntimeException("Метод не найден"); NativeApiProxy.GetMethodName(_object, methodNumber, 0, str => method.Name(NativeApiProxy.Str(str)) ); NativeApiProxy.GetMethodName(_object, methodNumber, 1, str => method.Alias(NativeApiProxy.Str(str)) ); var paramCount = NativeApiProxy.GetNParams(_object, methodNumber); for (int i = 0; i < paramCount; i++) { var parameter = method.NewParameter() .Name($"p{i}") .ByValue(true); if (NativeApiProxy.HasParamDefValue(_object, methodNumber, i)) { parameter.DefaultValue(BslSkippedParameterValue.Instance); // кажется что значение не нужно в данном кейсе использования // если что - раскомментировать // NativeApiProxy.GetParamDefValue(_object, methodNumber, i, variant => // { // var value = (BslPrimitiveValue)NativeApiVariant.Value(variant); // parameter.DefaultValue(value); // }); } } method.ReturnType(NativeApiProxy.HasRetVal(_object, methodNumber) ? typeof(BslValue) : typeof(void)); method.IsExported(true); return method.Build(); } public BslPropertyInfo GetPropertyInfo(int propertyNumber) { var propName = GetPropName(propertyNumber); var isReadable = IsPropReadable(propertyNumber); var isWritable = IsPropWritable(propertyNumber); return BslPropertyBuilder.Create() .Name(propName) .CanRead(isReadable) .CanWrite(isWritable) .Build(); } private void SetDefValues(int methodNumber, int paramCount, IValue[] arguments) { for (int i = 0; i < paramCount; i++) if (arguments[i] == null) NativeApiProxy.GetParamDefValue(_object, methodNumber, i, variant => arguments[i] = NativeApiVariant.Value(variant) ); } public void CallAsProcedure(int methodNumber, IValue[] arguments) { int paramCount = NativeApiProxy.GetNParams(_object, methodNumber); using (var variant = new NativeApiVariant(paramCount)) { SetDefValues(methodNumber, paramCount, arguments); for (int i = 0; i < paramCount; i++) variant.Assign(arguments[i], i); NativeApiProxy.CallAsProc(_object, methodNumber, variant.Ptr); } } public void CallAsFunction(int methodNumber, IValue[] arguments, out IValue retValue) { var result = ValueFactory.Create(); int paramCount = NativeApiProxy.GetNParams(_object, methodNumber); using (var variant = new NativeApiVariant(paramCount)) { SetDefValues(methodNumber, paramCount, arguments); for (int i = 0; i < paramCount; i++) variant.Assign(arguments[i], i); NativeApiProxy.CallAsFunc(_object, methodNumber, variant.Ptr, res => result = NativeApiVariant.Value(res) ); } retValue = result; } private void ReleaseUnmanagedResources(bool isDisposing) { if (_object == IntPtr.Zero) return; try { NativeApiProxy.DestroyObject(_object); } catch (Exception) { if (isDisposing) throw; } finally { _object = IntPtr.Zero; } } public void Dispose() { ReleaseUnmanagedResources(true); GC.SuppressFinalize(this); } ~NativeApiComponent() { ReleaseUnmanagedResources(false); } } }