QuickScript .NET — различия между версиями

Материал из archestra.info
Перейти к: навигация, поиск
(Для чего очистка ресурсов после выгрузки данных в Excel)
(Очистка ресурсов после выгрузки данных в Excel)
 
(не показаны 44 промежуточные версии ещё одного участника)
Строка 1: Строка 1:
== InTouch ==
+
== Также смотри ==
 +
*[[QuickScript]] (для InTouch)
 +
*[[.NET]]
 +
*работа с [[Script Function Library]]
  
== QuickScript .NET  (для Application Server) ==
 
=== Работа с MS Excel ===
 
SR30711946:  How to maximize an excel application?  Use WWControl()
 
  
  
==== Описание объектной модели ====
+
'''[[QuickScript .NET]]  (для Application Server)'''
Самым "верхним" объектом в Excel является объект '''Application'''. Это объект приложение. И этот объект содержит ряд коллекций. Коллекция в VBA - это что-то вроде массива, только элементы в нее можно добавлять и удалять во время выполнения программы. Рабочие книги Excel входят в коллекцию '''Workbooks'''. Чтобы узнать количество открытых книг, используется метод '''Workbooks.Count'''.
+
== Общие вопросы ==
 +
== Описание функций ==
 +
=== GetCPQuality() ===
 +
Syntax
 +
Int GetCPQuality(String name)
 +
 +
Where String '''name''' is the name of the Custom Property whose quality you want to get.
 +
This script function takes the name of a custom property on the symbol. This argument is of type string and it can be a reference or a constant.
 +
If the custom property is type constant the quality is always return GOOD
  
Добавить новую книгу можно вызвав метод Workbooks.Add(). В качестве параметра этому методу можно передать имя шаблона, на основе которого будет создаваться новая книга. Чтобы открыть существующий файл Excel, вызывается метод Workbooks.Open("file.xls") - в результате будет открыт файл file.xls.
+
*''Note:  For use with Custom Properties only. It does not apply to InTouch tags.''
 +
 +
'''Return value''': The GetCPQuality() script function returns a value 0-255 of type Integer, as per the OPC quality standard. ( 192 is GOOD.)
  
Закрыть книгу можно так: Workbooks(1).Close, или так: Workbooks("Книга1").Close, или закрыть все книги сразу: Workbooks.Close. Метод Close имеет ряд необязательных параметров. Вот они.
+
=== GetCPTimeStamp() ===
expression.Close(SaveChanges, FileName, RouteWorkbook)
+
Первый параметр SaveChanges имеет тип BOOL, если он равен TRUE, сделанные изменения сохранятся, если FALSE - то нет. Если параметр не задан, то при закрытии появляется диалоговое окно с вопросом о необходимости сохранения.
+
Save changes ?
+
  
К книгам в коллекции можно обращаться через метод Item():
+
Syntax
 +
DateTime GetCPTimeStamp(String name)
 +
 +
Where String '''name''' is the name of the Custom Property whose time stamp you want to get.
 +
This script function takes the name of a custom property on the symbol. This argument is of type string and it can be a reference or a constant.
 +
If the custom property is type constant then the return value is the time the value was created.
 +
 +
''Note: For use with Custom Properties only. It does not apply to InTouch tags.''
 +
 +
'''Return value''': The GetCPQuality() script function returns a value of type DateTime
  
Sub Test()
+
Example:
  s1 = Application.Workbooks.Item(1).Name
+
cp2 = GetCPTimeStamp("cp1");                'where cp1 and cp2 are custom properties. cp2’s data type is Time.
  s2 = Application.Workbooks.Item("book.xls").FullName
+
End Sub
+
  
Доступ к книге можно получить по индексу и по имени книги. Имя книги - это имя файла, в котором она хранится. Fullname содержит полное имя, название файла и путь, а Name - только имя.
+
=== Задание размерности массива ===
 +
<pre>
 +
Dim size as integer;
 +
Size = me.ArrayAttribute[].Dimension1; 'Gets the array size as integer
 +
Size = 25;
 +
me.ArrayAttribute[].Dimension1 = Size; 'Sets the array size Note: The change must be done from within the object.
 +
</pre>
  
 +
== Работа с Historian ==
 +
*'''Question''': Can I use script i AppServer to change the Historian name? '''Answer''': No, but you should be able to do so using the GRAccess Toolkit
  
 +
== Работа с файлами ==
 +
=== Примеры ===
 +
Удаление файла:
 +
System.IO.File.Delete("C:\temp\temp.xlsx"); 
  
=== Примеры Application Server 3.5 + Microsoft Excel 2007 ===
+
== Работа с MS Excel ==
 +
'''SR30711946''':  How to maximize an excel application?  Use WWControl()
  
<pre>Dim app As Object;
+
----
  
Dim wb As Object;
+
'''SR19817850''': указано много особенностей работы с Excel  (https://wdnresource.wonderware.com/automation/csparea/SRDetail.aspx?id=19817850)
  
Dim ws As Object;
+
В Windows 2008 с Excel 2007 может быть проблема с сохранением файлов, для этого см. http://social.msdn.microsoft.com/Forums/en-US/b81a3c4e-62db-488b-af06-44421818ef91/excel-2007-automation-on-top-of-a-windows-server-2008-x64 
 +
'''''Решение:'''''
 +
  ・Windows 2008 Server x64  please make this folder.    C:\Windows\SysWOW64\config\systemprofile\Desktop
 +
  ・Windows 2008 Server x86  please make this folder.    C:\Windows\System32\config\systemprofile\Desktop
  
 +
----
  
 +
Для импортирования функций Excel и возможности работы с типами Excel._Application; Excel._Workbook; Excel._WorkSheet необходимо:
 +
- Galaxy -> import -> Script Function Library файл: C:\Program Files (x86)\Microsoft Office\Office12\Excel.exe
  
app = CreateObject("Excel.Application");
 
  
LogMessage("Before wb add");
+
=== Описание объектной модели ===
 +
Самым "верхним" объектом в Excel является объект '''Application'''. Это объект приложение. И этот объект содержит ряд коллекций. Коллекция - это что-то вроде массива, только элементы в нее можно добавлять и удалять во время выполнения программы. Рабочие книги Excel входят в коллекцию '''Workbooks'''. Чтобы узнать количество открытых книг, используется метод '''Workbooks.Count'''.
  
wb = app.Workbooks.Add();
+
Добавить новую книгу можно вызвав метод '''Workbooks.Add()'''. В качестве параметра этому методу можно передать имя шаблона, на основе которого будет создаваться новая книга. Чтобы открыть существующий файл Excel, вызывается метод '''Workbooks.Open'''("file.xls") - в результате будет открыт файл file.xls.
  
LogMessage("After wb add");
+
Закрыть книгу можно так: '''Workbooks(1).Close''', или так: Workbooks("Книга1").Close, или закрыть все книги сразу: '''Workbooks.Close'''. Метод Close имеет ряд необязательных параметров. Вот они.
 +
expression.Close(SaveChanges, FileName, RouteWorkbook)
 +
Первый параметр SaveChanges имеет тип BOOL, если он равен TRUE, сделанные изменения сохранятся, если FALSE - то нет. Если параметр не задан, то при закрытии появляется диалоговое окно с вопросом о необходимости сохранения.
 +
Save changes ?
  
LogMessage("before activesheet add");
+
Доступ к книге можно получить по индексу и по имени книги. Имя книги - это имя файла, в котором она хранится. Fullname содержит полное имя, название файла и путь, а Name - только имя.
  
ws = wb.ActiveSheet;
+
=== Примеры Application Server 3.5 + Microsoft Excel 2007 ===
 +
Для импортирования функций Excel и возможности работы с типами Excel._Application; Excel._Workbook; Excel._WorkSheet необходимо: - Galaxy -> import -> Script Function Library файл: C:\Program Files (x86)\Microsoft Office\Office12\Excel.exe
  
LogMessage("After activesheet add");
+
==== Пример создания файла Excel и записи в него данных ====
  
LogMessage("get range A1");
+
Перед этим импортировать библиотеку из excel.exe (см.  выше)
 +
Тип скрипта '''асинхронный'''
 +
 
 +
<pre>
 +
LogMessage("Start Script");
 +
 
 +
dim app as Microsoft.Office.Interop.Excel._Application;
 +
dim wb as Microsoft.Office.Interop.Excel._Workbook;
 +
dim ws as Microsoft.Office.Interop.Excel._WorkSheet;
 +
 
 +
 
 +
dim a1 as Microsoft.Office.Interop.Excel.Range;
 +
dim a2 as Microsoft.Office.Interop.Excel.Range;
 +
dim a3 as Microsoft.Office.Interop.Excel.Range;
 +
 
 +
app = new Microsoft.Office.Interop.Excel.Application;
 +
 
 +
wb = app.Workbooks.Add();
 +
ws = wb.ActiveSheet;
  
ws.Range("A1").Value = 1000;
+
a1 = ws.Range("A1");
 +
a2 = ws.Range("A2");
 +
a3 = ws.Range("A3");
  
LogMessage("get range A2");
+
a1.Value2 = 1000;
 +
a2.Value2 = 2000;
 +
a3.Value2 = "=A1*A2";
  
ws.Range("A2").Value = 1000;
+
LogMessage(a3.Value2);
  
LogMessage("get range A3");
+
System.IO.File.Delete("C:\temp\temp.xlsx");
 +
LogMessage("del file");
  
ws.Range("A3").Value = "=A1+A2";
+
wb.SaveAs("C:\temp\temp.xlsx");
LogMessage(ws.Range("A3").Value);
+
LogMessage("save file");  
LogMessage("close");
+
  
wb.SaveAs("c:\temp\Book1.xlsx");
 
LogMessage("saved");
 
 
wb.Close(false);
 
wb.Close(false);
 +
LogMessage("close file");
  
 +
LogMessage("end main part");
  
LogMessage("2");
 
 
System.Runtime.InteropServices.Marshal.ReleaseComObject(ws );
 
System.Runtime.InteropServices.Marshal.ReleaseComObject(ws );
 
 
System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
 
System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
 
 
app.Quit();
 
app.Quit();
 
 
System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
 
System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
 
 
System.GC.Collect();
 
System.GC.Collect();
LogMessage("2 end");
+
System.GC.WaitForPendingFinalizers();
 +
LogMessage("end");
 
</pre>
 
</pre>
  
 
==== Примеры из руководства AS3.6 файл: Scripting.pdf ====
 
==== Примеры из руководства AS3.6 файл: Scripting.pdf ====
'''Работающий пример из руководства (AS3.6, файл: Scripting.pdf, стр. 111) Accessing an Excel Spreadsheet Using CreateObject (в руководстве не верно!!!)'''  
+
'''Доработанный пример из руководства "Accessing an Excel Spreadsheet Using CreateObject" (AS3.6, файл: Scripting.pdf, стр. 111)'''  
 +
 
 
<pre>
 
<pre>
 
dim app as object;
 
dim app as object;
Строка 111: Строка 167:
 
</pre>
 
</pre>
  
==== Для чего очистка ресурсов после выгрузки данных в Excel ====  
+
==== Очистка ресурсов после выгрузки данных в Excel ====  
 
Источник: http://www.sql.ru/forum/906372/dlya-chego-nuzhen-marshal-releasecomobject
 
Источник: http://www.sql.ru/forum/906372/dlya-chego-nuzhen-marshal-releasecomobject
 +
 
Пример кода очистки:
 
Пример кода очистки:
 
  appl.Quit();
 
  appl.Quit();
Строка 128: Строка 185:
 
**Попробуйте сгениерить через интероп экселевский документ эдак на 50 тысяч строк раз 10-20-30. И понаблюдайте за памятью. Достаточно обычная * Следует ли применять данный метод к объектам Range?  
 
**Попробуйте сгениерить через интероп экселевский документ эдак на 50 тысяч строк раз 10-20-30. И понаблюдайте за памятью. Достаточно обычная * Следует ли применять данный метод к объектам Range?  
 
** Мало того, что к Range - это такой же com-объект, как и все прочие при работе через интероп. Желательно делать свои обертки для всех используемых объектов, и обертки эти делать с реализацией IDisposable, в которых Dispose будет освобождать память по подобному сценарию. Нужно это потому, что при работе с интероп сплошь и рядом имеет место быть неявное создание ссылок на com-объекты - например, вы получаете ссылку на Selection, и работаете с Selection.Range; при этом создается неявная ссылка на Selection.Range, которую GC не подбирает. Обертка, разумеется, ведет контроль за созданием подобных ссылок.
 
** Мало того, что к Range - это такой же com-объект, как и все прочие при работе через интероп. Желательно делать свои обертки для всех используемых объектов, и обертки эти делать с реализацией IDisposable, в которых Dispose будет освобождать память по подобному сценарию. Нужно это потому, что при работе с интероп сплошь и рядом имеет место быть неявное создание ссылок на com-объекты - например, вы получаете ссылку на Selection, и работаете с Selection.Range; при этом создается неявная ссылка на Selection.Range, которую GC не подбирает. Обертка, разумеется, ведет контроль за созданием подобных ссылок.
 +
 +
'''''При использовании из AS3.5 без кода очистки не завершает процесс excel *32'''''
 +
 +
== Работа с параметрами типа indirect ==
 +
*Рекомендуемый механизм использования косвенных переменных на описан ниже. При этом имейте в виду, что переменная state – это триггер работы скрипта и одно изменение этой переменной – это только ОДИН цикл выполнение скрипта. Т.е. в примере ниже state меняется от 1 до 5, а следовательно весь скрипт выполняется за 5 циклов (или 5 сканов AppEngine)
 +
 +
*Linking to Off Engine Attributes Using a Re-entrent Script (WhileTrue  Me.BindToCmd)
 +
If state== 1 then
 +
    Dim ind1 as indirect; Dim ind2 as indirect; Dim ind3 as indirect;
 +
    Execute the indx.BindTo(“something”) methods
 +
    When done set the state to 2
 +
Elseif state == 2 then
 +
    Check the indirects using IsGood(indirect) or IsGood(ind1, ind2, ind3,…)
 +
    When all the indirects are good set the state to 3
 +
    If too long set state to 5
 +
    When done set the state to 3
 +
Elseif state == 3 then
 +
    Use the indirects
 +
    Me.Attr1 = Ind1; Me.Attr2 = Ind2; Me.Attr3 = Ind3;
 +
    When done set the state to 4
 +
Elseif state == 4 then
 +
    Ind1 = null; Ind2 = null; ind3 = null;
 +
    Turn off trigger Me.BindToCmd = false;
 +
    Set state back to 1
 +
Elseif state == 5 then
 +
    LogError(“Indirects did not work!”);
 +
    Ind1 = null; Ind2 = null; ind3 = null; Me.BindToCmd = False;
 +
Endif;
 +
 +
== Другие темы ==
 +
*[[QuickScript]] (для InTouch)
 +
*[[.NET]]
 +
*работа с [[Script Function Library]]

Текущая версия на 09:42, 26 ноября 2015

Также смотри


QuickScript .NET (для Application Server)

Общие вопросы

Описание функций

GetCPQuality()

Syntax

Int GetCPQuality(String name)

Where String name is the name of the Custom Property whose quality you want to get. This script function takes the name of a custom property on the symbol. This argument is of type string and it can be a reference or a constant. If the custom property is type constant the quality is always return GOOD

  • Note: For use with Custom Properties only. It does not apply to InTouch tags.

Return value: The GetCPQuality() script function returns a value 0-255 of type Integer, as per the OPC quality standard. ( 192 is GOOD.)

GetCPTimeStamp()

Syntax

DateTime GetCPTimeStamp(String name)

Where String name is the name of the Custom Property whose time stamp you want to get. This script function takes the name of a custom property on the symbol. This argument is of type string and it can be a reference or a constant. If the custom property is type constant then the return value is the time the value was created.

Note: For use with Custom Properties only. It does not apply to InTouch tags.

Return value: The GetCPQuality() script function returns a value of type DateTime

Example:

cp2 = GetCPTimeStamp("cp1");                 'where cp1 and cp2 are custom properties. cp2’s data type is Time.

Задание размерности массива

Dim size as integer; 
Size = me.ArrayAttribute[].Dimension1; 'Gets the array size as integer 
Size = 25; 
me.ArrayAttribute[].Dimension1 = Size; 'Sets the array size Note: The change must be done from within the object.

Работа с Historian

  • Question: Can I use script i AppServer to change the Historian name? Answer: No, but you should be able to do so using the GRAccess Toolkit

Работа с файлами

Примеры

Удаление файла:

System.IO.File.Delete("C:\temp\temp.xlsx");   

Работа с MS Excel

SR30711946: How to maximize an excel application? Use WWControl()


SR19817850: указано много особенностей работы с Excel (https://wdnresource.wonderware.com/automation/csparea/SRDetail.aspx?id=19817850)

В Windows 2008 с Excel 2007 может быть проблема с сохранением файлов, для этого см. http://social.msdn.microsoft.com/Forums/en-US/b81a3c4e-62db-488b-af06-44421818ef91/excel-2007-automation-on-top-of-a-windows-server-2008-x64 Решение:

 ・Windows 2008 Server x64  please make this folder.    C:\Windows\SysWOW64\config\systemprofile\Desktop
 ・Windows 2008 Server x86  please make this folder.    C:\Windows\System32\config\systemprofile\Desktop

Для импортирования функций Excel и возможности работы с типами Excel._Application; Excel._Workbook; Excel._WorkSheet необходимо: - Galaxy -> import -> Script Function Library файл: C:\Program Files (x86)\Microsoft Office\Office12\Excel.exe


Описание объектной модели

Самым "верхним" объектом в Excel является объект Application. Это объект приложение. И этот объект содержит ряд коллекций. Коллекция - это что-то вроде массива, только элементы в нее можно добавлять и удалять во время выполнения программы. Рабочие книги Excel входят в коллекцию Workbooks. Чтобы узнать количество открытых книг, используется метод Workbooks.Count.

Добавить новую книгу можно вызвав метод Workbooks.Add(). В качестве параметра этому методу можно передать имя шаблона, на основе которого будет создаваться новая книга. Чтобы открыть существующий файл Excel, вызывается метод Workbooks.Open("file.xls") - в результате будет открыт файл file.xls.

Закрыть книгу можно так: Workbooks(1).Close, или так: Workbooks("Книга1").Close, или закрыть все книги сразу: Workbooks.Close. Метод Close имеет ряд необязательных параметров. Вот они. expression.Close(SaveChanges, FileName, RouteWorkbook) Первый параметр SaveChanges имеет тип BOOL, если он равен TRUE, сделанные изменения сохранятся, если FALSE - то нет. Если параметр не задан, то при закрытии появляется диалоговое окно с вопросом о необходимости сохранения. Save changes ?

Доступ к книге можно получить по индексу и по имени книги. Имя книги - это имя файла, в котором она хранится. Fullname содержит полное имя, название файла и путь, а Name - только имя.

Примеры Application Server 3.5 + Microsoft Excel 2007

Для импортирования функций Excel и возможности работы с типами Excel._Application; Excel._Workbook; Excel._WorkSheet необходимо: - Galaxy -> import -> Script Function Library файл: C:\Program Files (x86)\Microsoft Office\Office12\Excel.exe

Пример создания файла Excel и записи в него данных

Перед этим импортировать библиотеку из excel.exe (см. выше) Тип скрипта асинхронный

LogMessage("Start Script");

dim app as Microsoft.Office.Interop.Excel._Application;
dim wb as Microsoft.Office.Interop.Excel._Workbook;
dim ws as Microsoft.Office.Interop.Excel._WorkSheet;


dim a1 as Microsoft.Office.Interop.Excel.Range;
dim a2 as Microsoft.Office.Interop.Excel.Range;
dim a3 as Microsoft.Office.Interop.Excel.Range;

app = new Microsoft.Office.Interop.Excel.Application;

wb = app.Workbooks.Add();
ws = wb.ActiveSheet;

a1 = ws.Range("A1");
a2 = ws.Range("A2");
a3 = ws.Range("A3");

a1.Value2 = 1000;
a2.Value2 = 2000;
a3.Value2 = "=A1*A2";

LogMessage(a3.Value2);

System.IO.File.Delete("C:\temp\temp.xlsx");
LogMessage("del file");

wb.SaveAs("C:\temp\temp.xlsx");
LogMessage("save file"); 

wb.Close(false);
LogMessage("close file"); 

LogMessage("end main part");

System.Runtime.InteropServices.Marshal.ReleaseComObject(ws );
System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
app.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
LogMessage("end");

Примеры из руководства AS3.6 файл: Scripting.pdf

Доработанный пример из руководства "Accessing an Excel Spreadsheet Using CreateObject" (AS3.6, файл: Scripting.pdf, стр. 111)

dim app as object;
dim wb as object;
dim ws as object;


app = CreateObject("Excel.Application");
wb = app.Workbooks.Add();
ws = wb.ActiveSheet;
ws.Range("A1").value = 20; 
ws.Range("A2").value = 30; 
ws.Range("A3").value = "=A1*A2"; 
LogMessage(ws.Range("A3").Value); 
wb.Close(false);


LogMessage("end main part");
System.Runtime.InteropServices.Marshal.ReleaseComObject(ws );
System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
app.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
LogMessage("end");

Очистка ресурсов после выгрузки данных в Excel

Источник: http://www.sql.ru/forum/906372/dlya-chego-nuzhen-marshal-releasecomobject

Пример кода очистки:

appl.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(worksheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(appl);
worksheet = null;
workbook = null;
appl = null;
System.GC.Collect();
  • Т.е. предложенный способ очистки ресурсов - корректный?
    • Не вполне. В конце после вызова System.GC.Collect() не хватает еще GC.WaitForPendingFinalizers().
  • К чему приведет неиспользование данного метода?
    • Попробуйте сгениерить через интероп экселевский документ эдак на 50 тысяч строк раз 10-20-30. И понаблюдайте за памятью. Достаточно обычная * Следует ли применять данный метод к объектам Range?
    • Мало того, что к Range - это такой же com-объект, как и все прочие при работе через интероп. Желательно делать свои обертки для всех используемых объектов, и обертки эти делать с реализацией IDisposable, в которых Dispose будет освобождать память по подобному сценарию. Нужно это потому, что при работе с интероп сплошь и рядом имеет место быть неявное создание ссылок на com-объекты - например, вы получаете ссылку на Selection, и работаете с Selection.Range; при этом создается неявная ссылка на Selection.Range, которую GC не подбирает. Обертка, разумеется, ведет контроль за созданием подобных ссылок.

При использовании из AS3.5 без кода очистки не завершает процесс excel *32

Работа с параметрами типа indirect

  • Рекомендуемый механизм использования косвенных переменных на описан ниже. При этом имейте в виду, что переменная state – это триггер работы скрипта и одно изменение этой переменной – это только ОДИН цикл выполнение скрипта. Т.е. в примере ниже state меняется от 1 до 5, а следовательно весь скрипт выполняется за 5 циклов (или 5 сканов AppEngine)
  • Linking to Off Engine Attributes Using a Re-entrent Script (WhileTrue Me.BindToCmd)
If state== 1 then
    Dim ind1 as indirect; Dim ind2 as indirect; Dim ind3 as indirect;
    Execute the indx.BindTo(“something”) methods
    When done set the state to 2
Elseif state == 2 then
    Check the indirects using IsGood(indirect) or IsGood(ind1, ind2, ind3,…)
    When all the indirects are good set the state to 3
    If too long set state to 5
    When done set the state to 3
Elseif state == 3 then
    Use the indirects
    Me.Attr1 = Ind1; Me.Attr2 = Ind2; Me.Attr3 = Ind3; 
    When done set the state to 4
Elseif state == 4 then
    Ind1 = null; Ind2 = null; ind3 = null;
    Turn off trigger Me.BindToCmd = false;
    Set state back to 1
Elseif state == 5 then
    LogError(“Indirects did not work!”);
    Ind1 = null; Ind2 = null; ind3 = null; Me.BindToCmd = False;
Endif;

Другие темы