|
이 글의 원본은 CitectSCADA Knowledgebase Q3876 'Common Questions about ActiveX Controls in CitectSCADA' 입니다. 이 글은 원래 CitectSCADA에 국한하여 썼지만 CitectSCADA가 ActiveX Container이기 때문에 일부 내용을 제외하고는 사실 모든 응용 프로그램에 대해서 적용될 수 있는 내용입니다. 그래서 여기서 그 글을 소개합니다.
1. KB Q3229 글에 있는 예제가 왜 어떤 고객의 컴퓨터에서는 동작하지 않습니까?
우선 KBQ3229의 글은 Microsoft ADO Data Control ActiveX Object를 사용할 때 발생하는 문제점에 대해서 언급을 하고 있습니다. 그런데 이 ActiveX를 사용하려면 Microsoft Visual C++ v6.0 이상이 설치되어 있어야 사용이 가능합니다. 어찌되었거나 이 ActiveX Object에 대한 사용예는 다음과 같습니다.
FUNCTION InsertADO()
OBJECT hADO;
hADO = CreateControlObject("Microsoft ADO Data Control, version 6.0 (OLEDB)", "ADO", 100,500,500,530,"");
_ObjectSetProperty(hADO, "ConnectionString", "DSN=TestDB");
_ObjectSetProperty(hADO, "CommandType", "2");
_ObjectSetProperty(hADO, "RecordSource", "variable");
END
FUNCTION InsertDBGrid()
CreateControlObject("Microsoft DataGrid Control, Version 6.0 (OLEDB)", "DBGrid", 100, 100, 500, 480, "");
END
FUNCTION SetGridDataSource()
OBJECT hADO;
hADO = ObjectByName("ADO");
_ObjectSetProperty(ObjectByName("DBGrid"), "DataSource", hADO);
END
질문은 이 코드가 특정 사용자의 컴퓨터에서는 동작하지 않는다는 것입니다. CreateControlObject() Cicode 함수는 ProgID 또는 GUID에 대해서 사람이 인식할 수 있는 이름을 사용하여 인스턴스를 생성할 수 있습니다. 백워드 호환성을 위해서 다른 버전 사이에서도 객체의 ProdID와 GUID는 항상 같은 값을 유지합니다. 하지만 사람이 인식할 수 있는 이름은 바뀔 수가 있습니다. 예를 들면 'Microsoft ADO Data Control 6.0 (OLEDB)'는 Service Pack 4 설치 이후에 'Microsoft ADO Data Control 6.0 (SP4) (OLEDB)'로 이름이 바뀝니다. 하지만 GUID인 {67397AA3-7FB1-11D0-B148-00A0C922E820} 값이나 ProgID인 'MSAdodcLib.Adodc.6'는 그대로 유지 됩니다. 따라서 ActiveX Control의 이름 보다는 ProgID 또는 GUID를 사용하여 프로그래밍을 하는 것이 더 좋은 방법입니다.
2. VB에서 작은 수정이 있는 경우에 새로 컴파일(build)을 하고 다시 추가를 해야 합니까?
VB로 ActiveX control을 개발할 때는 그 객체의 'Binary Compatibility'를 유지해야 합니다. 그렇지 않으면 새로운 버전을 생성(build)할 때마다 VB는 그 컨트롤에 대해서 새로운 GUID를 자동적으로 생성할 것입니다. 결국 사용자는 그래픽 페이지에 다시 추가를 해야 합니다. VB로 개발을 할 때는 다음과 같이 하시기 바랍니다.:
1. VB project properties 페이지로 이동합니다.
2. 'Component' 탭을 클릭합니다.
3. 'Binary Compatibility' 옵션을 선택합니다.
4. 'Browser' 버튼을 사용하여 컨테이너에 삽입된 컨트롤을 선택합니다. (이 경우 CitectSCADA도 컨테이너로서 동작하는 것입니다.)
컨트롤을 다시 생성(build)하기 전에 반드시 Citect Explorer와 Citect Runtime을 종료해야 합니다. 또한 Binary Compatibility를 유지하기 위해서는 public interface들을 작제하거나 변경해서는 안됩니다. (하지만 새로운 public interface는 허용이 됩니다.) 레지스트리에서 ActiveX 정보를 완전히 제거하려면 Q3809의 KB 글을 참조하시기 바랍니다.
3. 직접 개발한 컨트롤의 인터페이스를 변경해야 할 때, 어떻게 컨트롤을 다시 추가하지 않도록 할 수 있습니까?
CitectSCADA 페이지에 ActiveX Control을 삽입하는 방법은 두 가지가 있습니다.
1. 디자인 할 때 Graphics Builder를 사용하여 페이지에 ActiveX Control을 삽입할 수 있습니다. 이 방법으로 (만약 그 컨트롤이 property 페이지가 작성되어 있다면) 모든 property들을 미리 구성하고 태그들을 할당 할 수가 있습니다. ActiveX Control 구성 정보들은 CTF 파일에 저장됩니다. 만약 페이지를 저장한 이후에 ActiveX Control의 인터페이스가 수정된 경우에는, 그 컨트롤을 다시 추가하고 다시 설정해야 합니다. 따라서 매번 같은 페이지에 그 컨트롤을 다시 추가하기 위해서는 그 컨트롤에 대한 구성 정보와 할당된 태그 정보에 대해서 항상 문서로 잘 남겨 놓아야 합니다.
2. 런타임 시에 CreateControlObject(sClass, sName, x1, y1, x2, y2, sEventClass) 함수를 사용하여 인스턴스를 생성할 수 있으며, _ObjectSetProperty(hObject, sProperty, vValue) 함수를 사용하여 프라퍼티를 설정할 수 있습니다. 만약 CitectSCADA의 태그를 할당하고 싶다면 ObjectAssociatePropertyWithTag(sObject, sPropertyName, sTagName, s[안내]태그제한으로등록되지않습니다-xx[안내]태그제한으로등록되지않습니다-xx[안내]태그제한으로등록되지않습니다-xx[안내]태그제한으로등록되지않습니다-xx[안내]태그제한으로등록되지않습니다-xxOnChangeEvent) 함수를 사용할 수 있습니다. 이것을 호출할 때는 필요한 모든 함수들을 작성한 다음에 'On Page Entry' 이벤트 명령에서 정의하면 됩니다. 함수들에 대한 자세한 내용은 온라인 도움말을 참조하시기 바랍니다. 이 방법을 사용할 때는 컨트롤이 수정될 때마다 OCX와 Cicode 파일만 고객에게 전달하면 됩니다. 사용자는 이 파일들을 복사하고, OCX를 다시 등록하면 됩니다. 이 방법의 단점은 Graphics Builder에서 미리 설정한 경우에 비해서는 페이지 표시할 때의 시간이 다소 느려집니다.
4. 태그가 할당된 프라퍼티가 변경되었을 때 왜 할당된 태그의 값은 갱신되지 않습니까?
기본적으로 태그 연결은 단방향성을 가집니다. 태그 값이 변경될 때마다 관련 프라퍼티도 갱신이 됩니다. 하지만 만약 ActiveX 프라퍼티가 변경된 경우에는 CitectSCADA는 그 프라퍼티가 변경되었는지를 알지를 못하기 때문에 그곳에 할당된 태그의 값은 갱신되지 않습니다. 프라퍼티가 변경될 때마다, 연결된 태그를 CitectSCADA가 자동적으로 갱신하도록 하기 위해서는 각각의 태그 연결에 ActiveX event를 지정하는 것이 필요합니다.
하지만 양방향성 갱신에는 문제가 하나 있습니다. 연결된 태그가 "Read Pending" 상태에 있을 때는 쓰기는 무시가 됩니다. 이것은 일시적으로 발생되며, 연결된 태그의 큐에 쌓여 있는 읽기와 쓰기 사이의 타이밍에 따라 달라집니다.
이 문제는 Cicode에서 이벤트 핸들러를 사용하여 이 문제를 피해갈 수 있습니다. 예를 들면, click 이벤트 발생시 'Value1' 프라퍼티에 할당되어 있는 Tag1의 값을 갱신할 수 있습니다. 'Update association on' 대신에 Click 이벤트를 다음과 같이 사용합니다.
function PageName_ANxx_Click(This Object)
int iValue;
iValue = _ObjectGetProperty(ObjectByName("ANxx"), "Value1");
Tag1 = iValue;
end
5. Cicode에서는 ActiveX Control의 배열 타입의 프라퍼티를 왜 사용할 수 없습니까?
Cicode는 컨트롤의 배열 프라퍼티를 지원하지 않습니다. 만약 배열 타입의 프라퍼티를 사용하고 싶다면 VB를 사용하여 이 컨트롤에 대한 Cicode에서 지원되는 새로운 인터페이스를 추가(wrap)하여 사용할 수 있습니다. 예를 들어, 사용자는 MS Flex Grid ActiveX Control을 사용하려고 할 수도 있습니다. 이 컨트롤의 ColWidth 프라퍼티는 배열 타입의 속성을 가집니다. VB에서 이 프라퍼티는 MSFlexGrid1.ColWidth(n) 구문을 사용하여 설정할 수 있습니다. 여기서 n은 열 번호(0, 1, 2, 등)입니다. 이것을 CitectSCADA에서 사용하기 위해서는 다음과 같이 합니다.
VB: wrapper에서는 메쏘드를 사용합니다.
Public Sub SetColWidth(Index As Long, Value As Long)
MSFlexGrid1.ColWidth(Index) = Value
End Sub
Cicode : MSFlexGrid1.ColWidth(0) = 100 값을 입력하려면 이 메쏘드를 사용합니다.
_ObjectCallMethod(ObjectByName("An35"), "SetColWidth", 0, 100);
6. CiVBA에서 ActiveX Control의 배열 타입의 프라퍼티를 왜 사용할 수 없습니까?
CiVBA에 이 문제가 있는 것은 확인을 하였습니다. 그 예로 Microsoft Form 2.0의 ListBox Control을 들 수 있습니다. 6 x 3의 배열을 생성하고 값을 채웁니다. 엑셀과 CitectSCADA에서의 결과는 아래 그림과 같습니다. 엑셀에서의 결과는 올바르지만 CiVBA에서의 결과는 첫 번째 열의 값이 복사되는 것을 볼 수가 있습니다.
< 엑셀에서의 결과 >
< CiVBA에서의 결과 >
만약 이 문제를 경험하게 된다면 5번 항목에서 설명한 것 처럼 wrap 방법을 사용하시기 바랍니다.
7. 왜 가끔씩 ActiveX 페이지로 이동할 때 하드웨어 알람이 발생합니까?
이 문제에 대한 대부분의 원인은 'On page entry'로 불리는 ActiveX Control에 대한 초기화 코드입니다. 이것은 삽입된 ActiveX Control과 CitectSCADA 사이에서 타이밍과 관련되어 있습니다. 만약 초기화 코드가 그 컨트롤이 페이지에 생성되기 전에 호출된다면 CitectSCADA는 'Unrecognized object class or properties' 또는 '355 - Object has no interface - ANxx' 라는 하드웨어 알람을 발생할 것입니다. 이 문제를 피하려면 (그 컨트롤이 VB로 작성되었다고 가정한다면) UserControl_Show의 OnShow 이벤트를 사용해야 합니다. 이 이벤트가 발생되었을 때, 이것은 생성된 인스턴스들을 허가하여 줍니다. CitectSCADA 측에서는 이 이벤트를 사용합니다. 기본적으로 Cicode 함수는 다음과 같은 형태가 될 것입니다.
FUNCTION PgaeName_ANXX_OnShow(This OBJECT, your event arguments)
Add your initialisation code here……..
………….
END
이 기능이 지원되지 않는다면 사용자의 초기화 코드에서 에러 처리 구문이 적용되어야 합니다.
버전 6부터는 <On page shown>이라는 새로운 페이지 이벤트가 추가 되었습니다. 이 이벤트는 ActiveX Control을 포함하여 페이지의 모든 객체들이 초기화 된 후에 발생됩니다. 초기화 코드를 이 이벤트 명령 필드에 입력함으로써 사용자는 더욱 안전하게 사용할 수가 있습니다.
8. ActiveX Control 페이지에 접근할 때 #COM이 표시됩니다.
이 문제에 대한 대부분의 원인은 ActiveX Control의 초기화 코드와 관련이 있습니다. 그 전형적인 예로서 ADODB가 있습니다. 이 컨트롤로 리모트의 MS SQL Server에 연결할 때 UserControl_Initialize()를 사용하게 됩니다. 만약 연결 시간이 오래 걸리거나 또는 타임아웃 된다면, #COM으로 표시되게 됩니다. 그 이유는 ActiveX Control은 포그라운드 객체로 취급되기 때문입니다. ActiveX Control에서 시간이 많이 걸리는 함수 호출은 CitectSCADA의 주 쓰레드에 영향을 줄 것이고, 다른 모든 것들을 중지시키는(block) 결과를 초래할 수 있습니다. 그래서 이 경우에 MS SQL Server에 연결할 때 비동기 연결 옵션을 사용하는 것이 좋습니다. 비동기 연결은 그 ActiveX Control에 대해서 다른 쓰레드를 사용하기 때문에, CitectSCADA는 오랜 시간이 걸리는 태스크가 있더라도 영향을 받지 않을 것입니다. 비동기 연결을 사용하려면 다음과 같이 합니다.:
1. 연결 객체를 'WithEvents' 키워드로 선언합니다.
2. Connection open에서 AsyncConnect 옵션을 사용합니다.
3. Event의 populating recordset에 아래의 코드를 추가합니다.
Connection_ConnectComplete
만약 동기 연결을 고수하고 싶다면 연결 시간 줄이는 것을 고려해야 합니다. 기본적으로 'ConnectionTimeout' 프라퍼티의 값은 15초입니다.
9. CiRecipe Control로 DBF 파일을 사용할 때 ODBC 에러가 발생합니다.
이 현상은 DBF에 대한 ODBC 드라이버가 윈도우즈 리소스(핸들) 해제에 문제가 있어서 발생됩니다. 이 문제는 CiRecipe의 인스턴스가 실행되고 있는 페이지를 빈번하게 열고 닫을 때 발생합니다. CiRecipe Control을 포함하고 있는 페이지를 닫을 때, 그 컨트롤 리소스는 종료시 해제되어야 합니다. 하지만 문제가 발생할 때 윈도우즈의 작업 관리자에서 '프로세스' 탭의 '핸들' 열을 선택하여 보면, Citect32 프로세스의 핸들 값이 증가하는 것을 볼 수가 있습니다. 만약 CiRecipe로 DBF 파일을 사용해야 한다면 CiRecipe 페이지를 닫지 말고 뒤로 숨기기 방법을 사용하시기 바랍니다.
이 문제는 ODBD driver for dBase가 BDE(Borland Database Engine)를 통해 진행될 때 BDE가 원인이 되어 발생하는 것 같습니다. 아래 레지스트리 설정에서 BDE를 빌활성 시킬 수가 있습니다. 이 값은 윈도우즈 XP SP2에서 테스트가 되었습니다.
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Xbase]
"BDE"=dword:00000002
10. CitectSCADA에 VB6 기반의 ActiveX Control을 사용할 때 어떤 점을 고려해야 합니까?
VB6는 단일 쓰레드 프로그래밍 언어입니다. ActiveX Container로서의 CitectSCADA는ActiveX Control을 포그라운드 객체로 취급하게 될 것입니다. 이러한 ActiveX Control 실행은 CitectSCADA의 주 쓰레드에 영향을 주게 될 것입니다. 이러한 이유로 ActiveX Control이 CitectSCADA의 IOServer 또는 트렌드 서버와 같이 중요한 싸이텍 노드에서 실행하는 것은 권장하지 않습니다. 예를 들면, 트렌드 서버에서 실행 시간이 긴 메쏘드를 실행할 때 트렌드 샘플을 놓치는 경우를 볼 수 있습니다.
VB6로 ActiveX Control을 개발할 때는 UserControl_Terminate() 이벤트에서 레퍼런스를 해제하는 것을 잊어서는 안됩니다. 또한 그 컨트롤과 CitectSCADA 사이의 통신 향상을 위해서 메쏘드 및 이벤트 사용을 고려해야 합니다. 예를 들면, CitectSCADA에게 그 컨트롤의 창이 페이지에 추가되었다는 것을 알리기 위해서 UserControl_Show() 이벤트를 생성할 수도 있습니다. 일단 CitectSCADA가 그 이벤트를 인지하면, 사용자는 크 객체의 배경 색상을 바꾼다거나 그림을 그리기 위한 등등의 메쏘드를 호출할 수 있습니다.
UserControl.Extender.Name은 그 컨트롤의 현재의 인스턴스를 확인하기 위해서 사용이 되지만, CitectSCADA에서는 이 프라퍼티가 지원되지 않습니다. 따라서 이 프라퍼티는 사용하지 마시기 바랍니다.
11. Cicode에서 ActiveX Control의 글꼴 변경이 되지 않습니다.
v5.41 이전의 Cicode에서는 ActiveX Control의 프라퍼티로서 글꼴 객체를 지원하지 않습니다. Cicode 도움말에 있는 예제 코드는 동작하지 않습니다. 이 버전에서는 CiVBA를 사용해야 합니다. 이 버그는 v5.51부터 수정이 되었습니다.
12. CitectSCADA에서 탭 컨트롤을 사용할 수 없습니다.
CitectSCADA의 그래픽은 페이지마다 단일 뷰를 기반으로 하는 구조가 사용되며, 그래픽 빌더에서 아무런 문제없이 탭 메뉴가 있는 ActiveX Control을 페이지에 추가할 수는 있지만 개별적인 탭 페이지에 대한 자체 설정을 할 수 있는 방법은 없습니다.
CitectSCADA에서 탭 대화 상자처럼 시뮬레이트 하기 위해서는, 그래픽 빌더에서 하나의 페이지에 필요한 객체들을 그린 다음 그룹으로 묶고, PageGetInt() 함수를 사용하여 각 그룹의 visibility 속성을 설정하여 사용할 수는 있습니다. 탭에 해당하는 버튼을 생성하여 이 버튼이 눌릴 때 PageSetInt() 함수로 정수 값을 할당하여 특정의 그룹만 표시를 하고 다른 그룹은 표시를 하지 않도록 합니다. 이 방법의 단점은 객체들이 겹쳐있기 때문에 작업이 다소 번거롭다는 것입니다.
13. 그래픽 빌더에서 CiVBA로 ActiveX Control의 기본 ID를 변경할 수 없습니다.
CitectSCADA는 디자인 시에 ActiveX Control의 ID를 변경할 수 있습니다. 하지만 이것은 Cicode로 그 컨트롤을 참조할 때만 유효합니다. 그것은 ID 맵핑이 런타임에 대해서만 설계가 되었고, Cicode에 의한 ActiveX 프라퍼티 및 메소드 접근은 Cicode 함수에 의해서 이루어지기 때문입니다.
CiVBA에 있어서는, ActiveX 프라퍼티 및 메쏘드를 접근하려면 점(dot) 확장자를 사용합니다. IP 맵핑이 아직 사직되지 않았기 때문에 CitectSCADA 컴파일러는 그 ActiveX Control의 기본 ID를 참조할 것이고, 'Undefined function....' 에러가 발생될 것입니다.
14. 그래픽 페이지에 어떻게 Crystal Report를 생성할 수 있습니까?
사용자는 'Crystal Report Viewer Control'(crviewer.dll)을 'Crystal Runtime Application'(craxdrt.dll)과 같이 사용할 수 있습니다. 아래에는 CiVBA를 사용하여 어떻게 Crystal Report를 생성하는지에 대한 예제 코드가 있습니다. (참고 : 이 예제는 Crystal Report 8에서 제공되는 crviewer.dll v8.0.0.371을 사용합니다.)
1. 그래픽 페이지에 'Crystal Report Viewer Control'을 삽입합니다.
2. 페이지에 버튼을 추가합니다.
3. 명령 필드에 다음과 같이 입력합니다.
CIVBA
CreateReport "C:\Citect\Data\Reports\OperatorInput.rpt"
4. 페이지를 'CRViewer'로 저장합니다.
5. 아래 코드를 작성합니다.
Sub CreateReport (Byval sReportTemplate As String)
Dim crpApp As Object
Dim crpReport As Object
'Clear the source, or “Memory full” error if func called twice
CRViewer_AN35.ReportSource = crpReport
'Create an instance of crystal runtime application
Set crpApp = CreateObject("CrystalRuntime.Application")
'Open Report Template and create a report object
Set crpReport = crpApp.OpenReport(sReportTemplate, 1)
'Discard any saved data
crpReport.DiscardSavedData
'Set report source, CRViewer_AN35 is the default instance name
CRViewer_AN35.ReportSource = crpReport
CRViewer_AN35.ViewReport
Set crpApp = Nothing
Set crpReport = Nothing
End Sub
위의 기능을 확장하기 위해서 아래의 코드를 추가하고 이 함수를 호출하는 버튼을 그래픽 페이지에 추가를 합니다. 이 함수를 사용하여 RPT 파일을 검색하여 선택하고, 선택된 Crystal Report를 표시할 수 있습니다.
FUNCTION OpenCrystalReport()
STRING sFile;
sFile = FormOpenFile("Open", "*.RPT", "Report Files (*.RPT)|*.RPT|");
IF FileExist(sFile) THEN
VbCallRun(VbCallOpen("CreateReport", sFile));
END
END
CitectSCADA에 Crystal Report를 적용할 때는 주의를 해야 한다는 점을 명심하시기 바랍니다. 이 뷰어는 포그라운드 객체로 간주되기 때문에, 알람, 트렌드 또는 IOServer 등과 같이 중요한 CitectSCADA 노드에서는 적용하지 마시기 바랍니다.
Crystal Report Viewer Control의 모습을 구성하려면 Crystal Report 패키지에 포함되어 있는 문서를 참조하시기 바랍니다.
15. 사용자 질의 없이 Crystal Report를 출력할 수 있습니까?
이 기능의 적용에서는 코드에서 'Crystal Runtime Application'(craxdrt.dll)만 필요합니다. 아래 예제어서 어떻게 사용하는지가 나타나 있습니다.
Sub PrintReport(Byval sReportTemplate As string)
Dim crpApp As Object
Dim crpReport As Object
'Create an instance of crystal runtime application
Set crpApp = CreateObject("CrystalRuntime.Application")
'Open Report Template and create a report object
Set crpReport = crpApp.OpenReport(sReportTemplate, 1)
'Discard any saved data
crpReport.DiscardSavedData
'Prints the report to default printer
'PrintOut([promptUser],[numberOfCopy],[collated],[startPageN], [stopPageN])
crpReport.PrintOut False, 1, False, 1, 1
Set crpApp = Nothing
Set crpReport = Nothing
End Sub
위의 예제는 기본 프린터에 리포트의 첫 번째 페이지를 출력하는 것입니다. 만약 리포트에 파라미터가 설정되어 있다면 그 리포트 객체의 'ParameterFields' 프라퍼티를 사용하여 원하는 값을 전달해야 합니다. 그렇지 않으면 그 파라미터 입력을 위하여 사용자에게 대화 상자가 팝업될 것입니다. 자세한 내용은 Crystal Report v8.0.0.371에 포함되어 있는 문서를 참조하시기 바랍니다.
또한 CitectSCADA 이벤트를 사용하여 자동으로 리포트 출력을 할 수도 있습니다. 그렇게 하기 위해서는 아래의 VB 함수를 (이벤트 엔진에서는 VB 함수를 바로 호출할 수 없으므로) Cicode를 통하여 호출하면 됩니다. 예를 들면, 다음과 같이 Cicode 함수를 작성할 수 있습니다.
FUNCTION PrintCrystalReport()
VbCallRun(VbCallOpen("PrintReport", "C:\Reports\Inventory.rpt"));
END
이제 리포트 트리거 이벤트의 명령 필드에 'PrintCrystalReport' 함수를 추가하면 됩니다.
16. 문장을 음성으로 변환하는 Microsoft Text Voice Control을 CitectSCADA에서 어떻게 사용할 수 있습니까?
'Text Voice' ActiveX Control은 텍스트 문장을 'document reader'와 같은 음성으로 변환하는데 사용됩니다. 이것을 스피커가 있는 알람 시스템에 매우 유용합니다.
이 컨트롤(VText.dll)은 c:\windows\Speech for WindowsXP 또는 c:\winnt\Speech for Windows2000에 위치하고 있습니다. WindowsNT의 경우 마이크로소프트 웹 사이트에서 이 컨트롤을 다운 받아야 합니다. 아래 예제 코드는 Cicode에서 어떻게 적용하는지를 보여줍니다.
GLOBAL OBJECT goVText;
FUNCTION VTextInit();
STRING sClassID;
sClassID = "{2398E32F-5C6E-11D1-8C65-0060081841DE}";
//ProgID "Vtext.Vtext.1"
goVText = CreateObject(sClassID);
END
// Function converts text to voice
FUNCTION VTextSpeak(STRING sText);
_ObjectCallMethod(goVText, "Speak", sText);
END
VTextInit() 함수는 프로젝트의 Startup 코드에 추가를 합니다. goVText는 모듈 변수로 선언되었기 때문에, 이 변수에 다른 객체를 할당하거나 또는 NullObject로 설정하기 까지는 이 객체는 남아있게 됩니다.
이 기능은 CiVBA에서는 모듈 변수가 지원되지 않음으로 CiVBA에서는 적용되지 않음을 명심하시기 바랍니다.
17. 태그 연결을 위한 프라퍼티 목록에서 어떤 프라퍼티가 포함되어 있지 않습니다.
이 현상은 ActiveX Control에서 이 프라퍼티들을 어떻게 설정했느냐에 따라 달라집니다. 예를들어, 어떤 프라퍼티는 Property Browswer에서 숨기기 기능을 할 수도 있습니다. 하지만 런타임에서는 여전히 접근이 가능합니다. 만약 VB6로 그 컨트롤을 만들었다면, 선택된 프라퍼티에 대해서 'Don't show in Property Browser' 속성을 활성화하기 위해서 Procedure Attributes를 사용하시기 바랍니다.
'Visible' 또는 'Left' 등과 같은 어떤 특유한 프라퍼티는 CitectSCADA에서 지원되지 않기 때문에 의도적으로 프라퍼티 목록에서 제외되어 있습니다. 만약 Cicode로 'Visible' 프라퍼티를 토글하려고 한다면 'Invalid parameter' 하드웨어 알람이 발생할 것입니다. 하지만 만약 CiVBA로 이 프라퍼티를 설정한다면 커널에서 'Class does not support Automation or does not support expected interface' 라는 에러로 로깅이 될 것입니다.
18. 런타임 시에 컨트롤의 크기 조정 및 위치 속성을 어떻게 숨길 수 있습니까?
컨트롤의 크기 조정, 보기 및 이동 인터페이스는 ActiveX Container인 CitectSCADA에서는 적용되지 않습니다. 따라서 보기 제어 또는 크기 조정을 위해서 ActiveX Control의 'Visible', Width' 및 'Height' 프라퍼티는 사용할 수 없습니다.
그래픽에서 ActiveX Control은 CitectSCADA의 객체로 취급됩니다. 따라서 그 기능들은 객체의 속성으로 사용할 수는 있습니다. 예를 들면, 객체의 속성에서 'Scaling(Vertical/Horizontal)' 속성에 태그를 추가하고, 그 값을 바꿈으로써 그 컨트롤의 크기를 조정할 수 있습니다. 마찬가지로 'Visibility' 속성에 디지털 태그를 정의하여 보기를 제어할 수 있으며, 'Movement(Vertical/Horizontal)' 속성을 사용하여 페이지에서의 위치를 조정할 수 있습니다.
'Movement' 속성은 컨트롤의 'Top', 'Left' 프라퍼티와 동일합니다. 'Scaling' 속성은 컨트롤의 'Width', 'Height' 프라퍼티와 동일하며, 'Visibility' 속성은 컨트롤의 'Visible' 프라퍼티와 같습니다.
이와 관련된 내용은 KB Q3899 및 Q3900을 참조하시기 바랍니다.
19. Cicode에서는 ActiveX Control 메쏘드의 옵션 아규먼트를 무시할 수 없습니까?
Cicode에서는 메쏘드의 옵션 아규먼트를 지원하지 않습니다. 따라서 _ObjectCallMethod를 사용할 때 메쏘드에서 필요로하는 모든 옵션 아규먼트에 대해서도 지정을 해야 합니다. Microsoft Form 2.0의 ListBox Control을 예로 들면, AddItem 메쏘드는 아래와 같이 두 개이 옵션 아규먼트를 가지고 있습니다.
Sub AddItem([pvargItem], [pvargIndex])
Member of MSForms.ListBox
만약 Microsoft Object Browser를 사용한다면, [ ] 괄호로 감싸여져 있는 아규먼트들은 옵션입니다. 아래에 이 메쏘드를 어떻게 사용하는지 예가 있습니다. 만약 그래픽 페이지에서 ListBox가 AN35로 추가되었다고 가정하고, 10개의 아이템을 추가한다면:
FUNCTION AddItems()
INT Index;
STRING sItemName;
FOR Index = 0 TO 9 DO
sItemName = "Item " + Index:#00;
_ObjectCallMethod(ObjectByName("AN35"), "AddItem", sItemName, Index);
END
END
이 코드의 결과는 아래 그림과 같습니다. 그리고 ListBox의 인덱스는 0부터 연속되는 값을 가져야 함을 명심하시기 바랍니다.
20. MS Forms ListBox Control의 'Persist ActiveX Data between Page Transitions' 활성화 옵션이 원래의 의도대로 동작하지 않습니다.
CitectSCADA v6에 'Persist ActiveX Data between Page Transitions' 옵션을 적용할 때 잘못 인지하고 있는 부분이 있습니다. 이 옵션은 퍼블릭 인터페이스를 통해서 ActiveX Control의 현재 설정을 임시 데이터 파일로 저장하기 위해서 사용됩니다. 이 파일은 페이지가 다시 오픈이 될 때 참조가 됩니다. ActiveX Control의 데이터의 영속성을 유지하려면 그 컨트롤은 반드시 퍼블릭 프라퍼티를 가져야 하며, 다음의 사양을 지원해야 합니다.
1. Read/Write
2. Single value
3. CitectSCADA에서 지원하는 데이터 타입
저장된 프라퍼티들을 불러오기를 했을 때 그 컨트롤이 어떻게 동작할지는 그 컨트롤 자체에 따라 달라집니다. ListBox 컨트롤의 경우에는 거주된 데이터는 자체의 메모리에 상주를 하고 있다가 페이지가 바뀌어 그 컨트롤이 제거되었을 때 사라져 버립니다. 그 데이터가 프라퍼티 인터페이스를 통하여 적용되어 있지 않는한 CitectSCADA 는 그 데이터를 복원하거나 영속시킬 수가 없습니다. 하지만 만약 ListBox 컨트롤이 위와 같은 방법으로 모든 아이템은 파일 또는 SQL 테이블 등과 같은 데이터 소스로부터 불러오기가 되도록 적용되어 있다면, 이 프라퍼티를 사용하여 프라퍼티 변경 이벤트에 대해서 데이터 소스로부터 아이템을 불러오도록 할 수가 있습니다. 이 경우 ListBox Control의 데이터 영속성이 유지될 것입니다.
21. 어떤 ActiveX Control Method는 v5.42에서 v6.00으로 업그레이드 한 후에 다르게 동작합니다.
이 문제는 오토메이션 인터페이스와 관련된 문제입니다. 버전 6 이전에서는 ActiveX Control Method에 전달되는 파라미터의 타입을 검사하지 않았습니다. 그래서 데이터는 타입에 상관없이 전달이 되었습니다. 하지만 더 좋은 운영성의 요구에 의해서 좀 더 엄격한 규칙이 버전 6부터 적용되었습니다. 이러한 이유로 인터페이스 타입 정보에서 파라미터가 [out] 마크가 표시되지 않는한 데이터는 전달되지 않습니다. 마찬가지로 만약 [in] 마크가 표시되어 있지 않다면 오토메이션 호출 전데 데이터를 복사하지 않습니다.
만약 사용하는 ActiveX Control이 VB6로 작성된 것이고, 그 메쏘드가 이 파라미터에 어떤 변경 작업을 하는 것이라면, 그 ActiveX Control의 메쏘드에서 ByRef로 파라미터를 분명하게 정의를 해야 합니다. 만약 Visual Basic에서 아규먼트 또는 파라미터의 타입을 선언하지 않으면 기본적으로 ByRef가 사용됩니다. 따라서 만약 데이터 파라미터가 전달이 되어야 한다면 그 파라미터는 반드시 ByVal로 선언이 되어야 합니다.
첫댓글 좋은 정보 감사합니다.
감사합니다
감사합니다.