외부 부품 기술 (). 외부 구성 요소 기술 () 외부 구성 요소 "1C : Enterprise"

안스미르노프 2013년 8월 22일 오후 2시 12분

1C 8.2의 외부 구성 요소

  • 프로그램 작성,
  • C++
  • 지도 시간

소개

이 기사에서는 1C: Enterprise 시스템에서 외부 구성 요소가 작동하는 방식에 대한 아이디어를 제공합니다.
OS에서 실행되는 1C: Enterprise 시스템 버전 8.2용 외부 구성 요소를 개발하는 프로세스가 표시됩니다. Windows 제품군와 함께 파일 버전일하다. 이 옵션은 중소기업용으로 설계된 대부분의 솔루션에 사용됩니다. VK는 C++ 프로그래밍 언어로 구현됩니다.

외부 구성 요소 "1C : Enterprise"

"1C:Enterprise"는 확장 가능한 시스템입니다. 확장용 기능성시스템은 외부 구성요소(EC)를 사용합니다. 개발자의 관점에서 VC는 속성과 메서드가 있는 외부 개체이며 1C: Enterprise 시스템에서 처리할 이벤트를 생성할 수도 있습니다.
외부 구성 요소를 사용하면 1C: Enterprise에 내장된 프로그래밍 언어로 구현하기 어렵거나 심지어 불가능한 문제 클래스를 해결할 수 있습니다. 특히 이 클래스에는 낮은 수준의 상호 작용이 필요한 작업이 포함되어 있습니다. 운영 체제, 예를 들어 특정 장비를 사용하여 작업하는 경우입니다.
1C: 엔터프라이즈 시스템은 외부 구성 요소를 생성하기 위해 두 가지 기술을 사용합니다.
  • 네이티브 API 사용
  • COM 기술을 사용하여
주어진 제한 사항을 고려할 때 위에서 언급한 두 기술의 차이는 미미하므로 Native API를 사용한 비디오 게임 개발을 고려해 보겠습니다. 필요한 경우 구현된 개발은 COM 기술을 사용하는 컴퓨터 소프트웨어 개발에 적용될 수 있으며, 약간의 수정을 통해 1C: Enterprise 시스템 이외의 다른 작업 옵션과 함께 사용하도록 적용될 수도 있습니다. 파일 모드일하다.
VK 구조
1C: Enterprise 시스템의 외부 구성 요소는 DLL 라이브러리 형태로 제공됩니다. 라이브러리 코드는 하위 클래스 IComponentBase를 설명합니다. 생성된 클래스는 외부 구성 요소의 기능을 구현하는 메서드를 정의해야 합니다. 재정의된 메서드는 자료가 제시될 때 아래에서 더 자세히 설명됩니다.

데모 VK 시작

일:
  1. ITS 구독과 함께 제공되며 1C에서 외부 구성 요소 메커니즘의 주요 기능을 보여주기 위한 외부 구성 요소를 조립합니다.
  2. 데모 구성 요소를 1C 구성에 연결
  3. 선언된 함수가 올바르게 작동하는지 확인하세요.
편집
데모 VK는 ITS 구독 디스크의 "/VNCOMP82/example/NativeAPI" 디렉터리에 있습니다.
데모 VK를 구축하려면 다음을 사용합니다. 마이크로소프트 비주얼 Studio 2008. 이 제품의 다른 버전은 사용된 Visual Studio 프로젝트 형식을 지원하지 않습니다.


AddInNative 프로젝트를 엽니다. 프로젝트 설정에는 프로젝트를 빌드하는 데 필요한 헤더 파일이 있는 디렉터리가 포함되어 있습니다. 기본적으로 ITS 디스크 디렉터리에 있습니다. /VNCOMP82/포함.
빌드 결과는 파일입니다. /bind/AddInNative.dll. 1C 구성에 연결하기 위해 컴파일된 라이브러리입니다.
VK를 1C 구성에 연결
빈 1C 구성을 만들어 보겠습니다.
아래는 모듈 코드입니다 관리형 애플리케이션.
변수 DemoComp; 시스템 시작 시 절차() 외부 구성 요소 연결("...\bind\AddInNative.dll", "DemoVK", 외부 구성 요소 유형.Native); DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); 절차 종료
1C 구성을 시작할 때 오류가 보고되지 않으면 VK가 성공적으로 연결된 것입니다.
위 코드를 실행하면 구성의 전역 가시성에 객체가 나타납니다. 데모컴에는 외부 구성 요소의 코드에 정의된 속성과 메서드가 있습니다.
내장된 기능 시연
데모 VK의 기능을 확인해 보겠습니다. 이를 위해 일부 속성을 설정 및 읽고, 일부 VK 메서드를 호출하고, VK 메시지를 수신 및 처리해 보겠습니다.
ITS 디스크에 제공된 문서에는 데모 VC의 다음 기능이 설명되어 있습니다.
  1. 구성 요소 개체 상태 관리
    행동 양식: 켜다, 끄다
    속성: 포함됨
  2. 타이머 관리
    매초마다 구성 요소는 매개 변수를 사용하여 1C: 엔터프라이즈 시스템에 메시지를 보냅니다. 요소, 시간제 노동자시스템 클럭 카운터 라인.
    행동 양식: 시작타이머, 정지타이머
    속성: 타이머가 있습니다
  3. 방법 표시상태라인, 상태 표시줄에 텍스트를 표시합니다. 이 방법 y를 매개변수로
  4. 방법 사진 업로드. 다음에서 이미지를 로드합니다. 지정된 파일이를 바이너리 데이터 형식으로 1C: Enterprise 시스템에 전송합니다.
이러한 기능이 작동하는지 확인해 보겠습니다. 이렇게 하려면 다음 코드를 실행하세요.
변수 DemoComp; 시스템 시작 시 절차() ConnectExternalComponent(...); DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); DemoComp.Disable(); 보고서(DemoComp.Enabled); DemoComp.Enable(); 보고서(DemoComp.Enabled); DemoComp.StartTimer(); 프로시저 절차 종료 외부 이벤트 처리(소스, 이벤트, 데이터) 보고서(소스 + " " + 이벤트 + " " + 데이터); 절차 종료
구성 실행 결과가 이미지에 표시됩니다.


"메시지" 패널에는 메소드 호출 결과가 표시됩니다. DemoComp.Disable()그리고 데모.Comp.Enable(). 동일한 패널의 후속 라인에는 VK에서 받은 메시지 처리 결과가 포함됩니다. 원천, 이벤트그리고 데이터각기.

사용자 정의 외부 구성 요소 이름

작업: 외부 구성 요소의 이름을 임의의 이름으로 변경합니다.
이전 섹션에서는 식별자를 사용했습니다. AddInNativeExtension, 그 의미는 설명되지 않았습니다. 이 경우 AddInNativeExtension- 확장명 이름입니다.
VK 코드는 메소드를 정의합니다 확장자로 등록, 이후 시스템에 VK를 등록하는 데 필요한 이름을 1C: Enterprise 시스템으로 반환합니다. 외부 구성 요소의 본질을 어느 정도 드러내는 식별자를 지정하는 것이 좋습니다.
다음은 메소드의 전체 코드입니다. 확장자로 등록확장자 이름이 변경되었습니다.
bool CAddInNative::RegisterExtensionAs(WCHAR_T** wsExtensionName) ( wchar_t *wsExtension = L"SomeName"; int iActualSize = ::wcslen(wsExtension) + 1; WCHAR_T* dest = 0; if (m_iMemory) ( if(m_iMemory->AllocMemory ((void**)wsExtensionName, iActualSize * sizeof(WCHAR_T))) ::convToShortWchar(wsExtensionName, wsExtension, iActualSize); true를 반환; ) false를 반환; )
주어진 예에서 VK 이름은 다음으로 변경됩니다. 썸네임. 그런 다음 VK를 연결할 때 새 이름을 지정해야 합니다.
DemoComp = New("AddIn.DemoVK.SomeName");

VK 속성 목록 확장

일:
  1. VK 속성 구현 연구
  2. 문자열 유형의 읽기/쓰기 속성 추가
  3. 마지막 속성 집합의 데이터 유형을 저장하는 읽기/쓰기 문자열 속성을 추가합니다. 속성 값을 설정할 때 아무 작업도 수행되지 않습니다.

생성되는 구성 요소의 속성을 확인하려면 개발자는 AddInNative.cpp 라이브러리 코드에서 다음 메서드를 구현해야 합니다.
GetNProps
이 확장의 속성 수를 반환합니다. 속성이 없으면 0을 반환합니다.
FindProp
매개변수에 이름이 전달된 속성의 일련 번호를 반환합니다.
GetPropName
일련 번호와 전달된 언어 식별자를 기준으로 속성 이름을 반환합니다.
GetPropVal
지정된 서수가 있는 속성의 값을 반환합니다.
SetPropVal
지정된 서수로 속성 값을 설정합니다.
IsProp읽기 가능
지정된 시퀀스 번호를 가진 속성의 가독성 플래그를 반환합니다.
IsPropWritable
지정된 시퀀스 번호를 가진 속성의 쓰기 가능 플래그를 반환합니다.


위 클래스 메소드의 구현을 고려해 봅시다. CAddInNative.
데모 VC에서는 2가지 속성이 정의됩니다. 포함됨그리고 타이머가 있습니다 (사용 가능그리고 IsTimerPresent).
라이브러리 코드의 전역 범위에는 두 개의 배열이 정의됩니다.
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent"); static wchar_t *g_PropNamesRu = (L"활성화됨", L"타이머가 있습니다");
러시아어와 영어 속성 이름을 저장합니다. 헤더 파일에서 애드인네이티브.h열거형은 다음과 같이 정의됩니다.
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropLast // 항상 마지막 );
eProp이 활성화되었습니다.그리고 ePropIsTimerPresent는 각각 0과 1의 값을 가지며 속성의 일련 번호를 의미 있는 식별자로 대체하는 데 사용됩니다. 값이 2인 ePropLast는 속성 수를 가져오는 데 사용됩니다(GetNProps 메서드 사용). 이러한 이름은 구성 요소 코드 내에서만 사용되며 외부에서는 사용할 수 없습니다.
FindProp 및 GetPropName 메서드는 배열 검색을 수행합니다. g_PropNames그리고 g_PropNamesRu.
라이브러리 모듈의 필드 값을 저장하기 위해 CAddInNative 클래스에는 구성 요소 속성 값을 저장하는 속성이 있습니다. 행동 양식 GetPropVal그리고 SetPropVal반환하고 이에 따라 이러한 속성의 값을 설정합니다.
행동 양식 IsProp읽기 가능그리고 IsPropWritable그리고 돌아오다 진실또는 거짓, 애플리케이션 로직에 따라 전달된 속성의 서수에 따라 달라집니다.
사용자 정의 속성을 추가하려면 다음을 수행해야 합니다.

  1. 배열에 추가되는 속성의 이름을 추가합니다. g_PropNames그리고 g_PropNamesRu(파일 AddInNative.cpp)
  2. 나열하려면 소품(파일 애드인네이티브.h) 전에 ePropLast추가되는 속성을 고유하게 식별하는 이름을 추가하세요.
  3. 속성값 저장을 위한 메모리 정리(해당 값을 저장하는 모듈 컴포넌트 필드 생성)
  4. 메소드 변경 GetPropVal그리고 SetPropVal이전 단계에서 할당된 메모리와 상호 작용합니다.
  5. 애플리케이션 로직에 따라 메소드를 변경합니다. IsProp읽기 가능그리고 IsPropWritable
1, 2, 5번 항목은 설명이 필요하지 않습니다. 이러한 단계의 구현에 대한 자세한 내용은 기사의 부록을 검토하여 확인할 수 있습니다.
테스트 속성에 이름을 지정해 보겠습니다. 시험그리고 유형 확인각기. 그런 다음 1단계의 결과는 다음과 같습니다.
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent", L"Test", L"TestType"); static wchar_t *g_PropNamesRu = (L"활성화됨", L"타이머가 있습니다", L"테스트", L"유형 확인");
옮기다 소품다음과 같이 보일 것입니다:
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropTest1, ePropTest2, ePropLast // 항상 마지막 );
코드를 대폭 단순화하기 위해 STL C++를 사용하겠습니다. 특히 문자열 작업의 경우 WCHAR, 라이브러리를 연결하자 wstring.
메소드 값을 저장하려면 시험, 우리는 클래스에서 정의합니다 CAddInNative비공개 필드의 범위에서:
문자열 테스트1;
1C: Enterprise와 외부 구성 요소 간에 문자열 매개 변수를 전송하려면 1C: Enterprise 메모리 관리자가 사용됩니다. 그의 작품을 좀 더 자세히 살펴보자. 함수는 각각 메모리를 할당하고 해제하는 데 사용됩니다. 할당메모리그리고 여유 메모리파일에 정의되어 있음 ImemoryManager.h. 필요한 경우 1C: Enterprise 시스템으로 전송 문자열 매개변수, 외부 구성 요소는 함수를 호출하여 메모리를 할당해야 합니다. 할당메모리. 프로토타입은 다음과 같습니다.
virtual bool ADDIN_API AllocMemory (void** pMemory, unsigned long ulCountByte) = 0;
어디 p메모리- 할당된 메모리 영역의 주소가 위치할 포인터의 주소,
ulCountByte- 할당된 메모리 영역의 크기.
문자열에 대한 메모리 할당의 예:
WCHAR_T *t1 = NULL, *테스트 = L"TEST_STRING"; int iActualSize = wcslen(test1)+1; m_iMemory->AllocMemory((void**)&t1, iActualSize * sizeof(WCHAR_T)); ::convToShortWchar(&t1, test1, iActualSize);
문자열 데이터 유형 작업의 편의를 위해 다음 함수를 설명하겠습니다. wstring_to_p. 매개변수로 wstring 문자열을 받습니다. 함수의 결과는 채워진 구조입니다. t변형. 기능 코드:
bool CAddInNative::wstring_to_p(std::wstring str, tVariant* val) ( char* t1; TV_VT(val) = VTYPE_PWSTR; m_iMemory->AllocMemory((void**)&t1, (str.length()+1) * sizeof(WCHAR_T)); memcpy(t1, str.c_str(), (str.length()+1) * sizeof(WCHAR_T)); val -> pstrVal = t1; val -> strLen = str.length(); 사실을 반환; )
그런 다음 메소드의 스위치 문의 해당 케이스 섹션 GetPropVal다음과 같은 형식을 취합니다.
케이스 ePropTest1: wstring_to_p(test1, pvarPropVal); 부서지다;
방법 SetPropVal:
케이스 ePropTest1: if (TV_VT(varPropVal) != VTYPE_PWSTR) return false; test1 = std::wstring((wchar_t*)(varPropVal -> pstrVal)); 부서지다;
두 번째 속성을 구현하기 위해 클래스 필드를 정의합니다. CaddInNative
uint8_t last_type;
마지막으로 전송된 값의 유형을 저장합니다. 이렇게 하려면 CaddInNative::SetPropVal 메서드에 명령을 추가합니다.
last_type = TV_VT(varPropVal);
이제 두 번째 속성 값 읽기를 요청하면 해당 값을 반환합니다. last_type, 지정된 작업에 필요한 것.
변경된 내용의 기능을 확인해 보겠습니다.
이를 위해 우리는 모습 1C 구성은 다음과 같습니다.
변수 DemoComp; 시스템 시작 시 절차() Connect 외부 구성 요소("...", "DemoVK", 외부 구성 요소 유형.Native); DemoComp = New("AddIn.DemoVK.SomeName"); DemoComp.TypeCheck = 1; Report(String(DemoComp.TypeCheck)); DemoComp.Test = "바샤"; Report(String(DemoComp.Test)); DemoComp.Test = "페트야"; Report(String(DemoComp.Test)); Report(String(DemoComp.TypeCheck)); 절차 종료
출시 결과, 우리는 다음과 같은 일련의 메시지를 받게 됩니다.
3
바샤
베드로
22

두 번째 및 세 번째 메시지는 이전 단계에서 설정된 속성을 읽은 결과입니다. 첫 번째와 두 번째 메시지에는 마지막 속성 집합의 유형 코드가 포함되어 있습니다. 3은 정수 값에 해당하고, 22는 문자열 값에 해당합니다. 유형과 해당 코드의 대응이 파일에 설정됩니다. 유형.h, ITS 디스크에 있습니다.

메소드 목록 확장

일:
  1. 다음 기능을 사용하여 외부 구성 요소의 기능을 확장합니다.
  2. 외부 구성 요소 메서드를 구현하는 방법 탐색
  3. 함수 메서드 추가 기능1, 두 개의 문자열("Parameter1" 및 "Parameter2")을 매개변수로 사용합니다. 결과는 다음과 같은 문자열입니다. “Checking. 매개변수1, 매개변수2"
  4. 변경한 내용이 제대로 작동하는지 확인하세요.

생성되는 구성 요소의 메서드를 정의하려면 개발자는 AddInNative 라이브러리 코드에서 다음 메서드를 구현해야 합니다.
GetN메소드, Find메소드, GetMethodName
해당 방법의 수를 얻도록 설계되었으며, 방법의 번호와 이름을 검색하십시오. 속성에 해당하는 메서드와 유사
GetNParams
지정된 시퀀스 번호가 있는 메서드 매개변수의 수를 반환합니다. 이 숫자를 가진 메소드가 없거나 매개변수가 없으면 0을 반환합니다.
GetParamDef값
지정된 메소드의 지정된 매개변수의 기본값을 반환합니다.
HasRetVal
지정된 서수 반환 값이 있는 메서드에 반환 값이 있는지 여부에 대한 플래그를 반환합니다. 반환 값이 있는 메서드의 경우 true이고 거짓그렇지 않으면
CallAsProc
거짓, 런타임 오류가 발생하고 1C: Enterprise 모듈의 실행이 종료됩니다. 매개변수 배열을 위한 메모리는 1C: Enterprise에 의해 할당 및 해제됩니다.
CallAsFunc
지정된 시퀀스 번호로 메서드를 실행합니다. 메서드가 반환되는 경우 거짓, 런타임 오류가 발생하고 1C: Enterprise 모듈의 실행이 종료됩니다. 매개변수 배열을 위한 메모리는 1C: Enterprise에서 할당됩니다. 반환 값이 문자열 또는 이진 데이터 유형인 경우 구성 요소는 다음 함수를 사용하여 메모리를 할당합니다. 할당메모리메모리 관리자는 거기에 데이터를 쓰고 이 주소를 구조의 해당 필드에 저장합니다. 1C: 기업은 호출을 통해 이 메모리를 해제합니다. 여유 메모리.
매개변수 목록을 포함한 메소드에 대한 전체 설명은 ITS 디스크에 제공된 문서에 자세히 설명되어 있습니다.
위에서 설명한 메서드의 구현을 고려해 보겠습니다.
구성 요소 코드에는 두 개의 배열이 정의됩니다.
static wchar_t *g_MethodNames = (L"활성화", L"비활성화", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture"); static wchar_t *g_MethodNamesRu = (L"활성화", L"비활성화", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadImage");
그리고 열거:
enum Methods ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethLast // 항상 마지막 );
그들은 함수에 사용됩니다 GetN메소드, Find메소드그리고 GetMethodName, 속성 설명과 유사합니다.
행동 양식 GetNParams, GetParamDef값, HasRetVal전달된 매개변수와 애플리케이션 로직에 따라 스위치를 구현하고 필요한 값을 반환합니다. 방법 HasRetVal코드에는 결과를 반환할 수 있는 메서드 목록만 있습니다. 그들을 위해 그는 돌아왔다 진실. 모든 철강 방법 반품에 대해 거짓.
행동 양식 CallAsProc그리고 CallAsFunc메소드의 직접 실행 가능한 코드를 포함합니다.
함수로만 호출할 수 있는 메서드를 추가하려면 다음과 같이 변경해야 합니다. 소스 코드외부 구성요소:
  1. 배열에 메소드 이름 추가 g_MethodNames그리고 g_MethodNamesRu(파일 AddInNative.cpp)
  2. Methods 열거형(파일)에 의미 있는 메소드 식별자를 추가합니다. 애드인네이티브.h)
  3. 함수 코드를 변경합니다. GetNParams프로그램 로직에 따라
  4. 필요한 경우 메서드 코드를 변경합니다. GetParamDef값, 메소드 매개변수의 기본값을 사용하려는 경우.
  5. 기능을 변경하세요. HasRetVal
  6. 함수의 논리를 변경합니다. CallAsProc또는 CallAsFunc, 거기에 메서드의 직접 실행 가능한 코드를 배치합니다.
배열을 제시해보자 g_MethodNames그리고 g_MethodNamesRu, 목록뿐만 아니라 행동 양식다음 형식으로:
static wchar_t *g_MethodNames = (L"활성화", L"비활성화", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture", L"Test"); static wchar_t *g_MethodNamesRu = (L"활성화", L"비활성화", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture", L"Test");

열거형 메서드( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethTest, eMethLast // 항상 마지막);
함수를 수정해보자 GetNProps"Test" 메소드의 매개변수 수를 반환합니다.
long CAddInNative::GetNParams(const long lMethodNum) ( 스위치(lMethodNum) ( 케이스 eMethShowInStatusLine: 반환 1; 케이스 eMethLoadPicture: 반환 1; 케이스 eMethTest: 반환 2; 기본값: 반환 0; ) 반환 0; )
함수를 변경해 보겠습니다.
bool CAddInNative::GetParamDefValue(const long lMethodNum, const long lParamNum, tVariant *pvarParamDefValue) ( ​​​​TV_VT(pvarParamDefValue)= VTYPE_EMPTY; switch(lMethodNum) ( 케이스 eMethEnable: 케이스 eMethDisable: 케이스 eMethShowInStatusLine: 케이스 eMethStartTimer: 케이스 eMethStopTimer: 케이스 eMethTest : // 기본적으로 매개변수 값은 없습니다. break; 기본값: false를 반환; ) false를 반환; )
추가된 라인 덕분에
eMethTest:
하나 이상의 인수가 누락된 경우 해당 매개변수는 빈 값을 갖습니다( VTYPE_EMPTY). 매개변수의 기본값이 필요한 경우 섹션에서 설정해야 합니다. eMethTest기능 스위치 명령문 CAddInNative::GetParamDefValue.
Test 메서드는 값을 반환할 수 있으므로 함수 코드를 변경해야 합니다. HasRetVal:
bool CAddInNative::HasRetVal(const long lMethodNum) ( switch(lMethodNum) ( 케이스 eMethLoadPicture: 케이스 eMethTest: return true; 기본값: return false; ) return false; )
그리고 메소드의 실행 코드를 함수에 추가합니다. CallAsFunc:
bool CAddInNative::CallAsFunc(const long lMethodNum, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) ( ... std::wstring s1, s2; switch(lMethodNum) ( 케이스 eMethLoadPicture: ... break; 케이스 eMethTest: if(!lSizeArray || !paParams)는 false를 반환합니다. s1 = (paParams) -> pwstrVal; s2 = (paParams+1) -> pwstrVal; wstring_to_p(std::wstring(s1+s2), pvarRetValue); ret = true ; 중단; ) ret 반환; )
구성 요소를 컴파일하고 구성 코드를 다음 형식으로 가져옵니다.
변수 DemoComp; 시스템 시작 시 절차() 외부 구성 요소 연결("...", "DemoVK", 외부 구성 요소 유형.Native); DemoComp = New("AddIn.DemoVK.SomeName"); Lane = DemoComp.Test("안녕하세요," "세계!"); 보고서(개); 절차 종료
구성을 시작한 후 메서드가 성공적으로 작동했음을 나타내는 "Hello, World!"라는 메시지를 받게 됩니다.

시간제 노동자

일:
  1. 데모 VK에서 타이머 구현을 연구하세요.
  2. 매개변수에 타이머 응답 간격(밀리초)을 전달하는 기능을 추가하여 "StartTimer" 메서드를 수정합니다.
  3. 변경한 내용이 제대로 작동하는지 확인하세요.

WinAPI에서는 메시지를 사용하여 시간 작업을 수행할 수 있습니다. WM_TIMER. 이 메시지타이머를 생성할 때 설정한 시간 간격으로 프로그램에 전송됩니다.
타이머를 생성하려면 다음 기능을 사용하세요. 타이머 설정:
UINT SetTimer(HWND hWnd, // 윈도우 설명자 UINT nIDevent, // 타이머 식별자(숫자) UINT nElapse, // 지연 TIMERPROC lpTimerFunc); // 함수에 대한 포인터
운영 체제에서 메시지를 보냅니다. WM_TIMER인수에 지정된 간격으로 프로그램에 n경과(밀리초 단위). 마지막 매개변수에서는 타이머가 실행될 때마다 실행될 함수를 지정할 수 있습니다. 이 함수의 헤더는 다음과 같습니다(이름은 무엇이든 가능).
void __stdcall TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
데모 VC에서 타이머 구현을 고려해 보겠습니다.
Windows OS 제품군을 위한 외부 구성요소 개발 프로세스를 고려 중이므로 다른 운영 체제에서의 타이머 구현은 고려하지 않을 것입니다. 특히 GNU/Linux OS의 경우 구현은 함수 구문이 다릅니다. 타이머 설정그리고 타이머프로크.
실행 가능한 코드는 메소드를 호출합니다. 타이머 설정, 함수가 전달되는 곳 마이타이머프록:
m_uiTimer = ::SetTimer(NULL,0,100,(TIMERPROC)MyTimerProc);
생성된 타이머의 ID는 변수에 저장됩니다. m_uiTimer나중에 비활성화할 수 있도록 합니다.
기능 마이타이머프록다음과 같이:
VOID CALLBACK MyTimerProc(HWND hwnd, // 타이머 메시지용 창 핸들 UINT uMsg, // WM_TIMER 메시지 UINT idEvent, // 타이머 식별자 DWORD dwTime // 현재 시스템 시간) ( if (!pAsyncEvent) return; wchar_t *who = L "ComponentNative", *what = L"타이머"; wchar_t *wstime = new wchar_t; if (wstime) ( wmemset(wstime, 0, TIME_LEN); ::_ultow(dwTime, wstime, 10); pAsyncEvent->ExternalEvent(who , 무엇, wstime); wstime 삭제; ) )
함수의 본질은 메서드가 호출된다는 것입니다. 외부이벤트, 1C: Enterprise 시스템에 메시지를 보냅니다.
메서드의 기능을 확장하려면 시작타이머다음을 수행해 보겠습니다.
메소드 코드 수정 GetNParams그래서 그것은 방법을위한 것입니다 eMethStartTimer반환된 값 1:
케이스 eMethStartTimer: 1을 반환합니다.
메소드 코드는 다음과 같습니다. CallAsProc다음 형식으로:
케이스 eMethStartTimer: if (!lSizeArray || TV_VT(paParams) != VTYPE_I4 || TV_I4(paParams)<= 0) return false; pAsyncEvent = m_iConnect; #ifndef __linux__ m_uiTimer = ::SetTimer(NULL,0,TV_I4(paParams),(TIMERPROC)MyTimerProc); #else // код для GNU/Linux #endif break;
이제 기능을 확인해 보겠습니다. 이를 위해 구성의 관리되는 애플리케이션 모듈에 코드를 작성합니다.
변수 DemoComp; 시스템 시작 시 절차() 외부 구성 요소 연결("...", "DemoVK", 외부 구성 요소 유형.Native); DemoComp = New("AddIn.DemoVK.SomeName"); DemoComp.StartTimer(2000); 절차 종료
구성을 시작한 후 프로그램은 2초 간격으로 타이머가 올바르게 작동하고 있음을 나타내는 메시지를 수신합니다.

1C와의 상호 작용 : 엔터프라이즈 시스템

외부 구성 요소와 1C: Enterprise 시스템 간의 상호 작용을 위해 파일에 설명된 IAddInDefBase 클래스의 메서드 AddInDefBase.h. 우리는 가장 일반적으로 사용되는 것들을 나열합니다:
오류 메시지 생성
virtual bool ADDIN_API AddError(부호 없는 짧은 wcode, const WCHAR_T* 소스, const WCHAR_T* 설명, 긴 scode)
wcode, 스코데- 오류 코드(설명이 포함된 오류 코드 목록은 ITS 디스크에서 찾을 수 있음)
원천- 오류의 원인
설명- 오류 설명
1C : Enterprise 시스템에 메시지 보내기
virtual bool ADDIN_API 외부 이벤트(WCHAR_T* wszSource, WCHAR_T* wszMessage, WCHAR_T* wszData) = 0;
wsz소스- 메시지 소스
wsz메시지- 메시지 텍스트
wszData- 전송된 데이터
메시지 차단은 외부 이벤트 처리 절차에 의해 수행됩니다.
1C : Enterprise 시스템에 외부 구성 요소 등록
가상 bool ADDIN_API RegisterProfileAs(WCHAR_T* wszProfileName)
wsz프로필 이름- 구성 요소 이름.
이러한 방법은 VK와 1C 간의 완전한 상호 작용에 충분합니다. 1C: Enterprise 시스템에서 외부 구성 요소로 데이터를 수신하거나 그 반대의 경우 외부 구성 요소는 특수 메시지를 보내고, 이 메시지는 1C 시스템에서 가로채고 필요한 경우 외부 구성 요소의 메서드를 호출하여 데이터를 다시 전송합니다. .

tVariant 데이터 유형

외부 구성 요소와 1C: Enterprise 시스템 간에 데이터를 교환할 때 tVariant 데이터 유형이 사용됩니다. 이는 ITS 디스크에 있는 type.h 파일에 설명되어 있습니다.
struct _tVariant ( _ANONYMOUS_UNION 공용체 ( int8_t i8Val; int16_t shortVal; int32_t lVal; int intVal; unsigned int uintVal; int64_t llVal; uint8_t ui8Val; uint16_t ushortVal; uint32_t ulVal; uint64_t ullVal; in t32_t errCode; 긴 hRes; 부동 fltVal; 이중 dblVal; bool bVal; char chVal; wchar_t wchVal; DATE 날짜; IID IDVal; struct _tVariant *pvarVal; struct tm tmVal; _ANONYMOUS_STRUCT 구조체( void* pInterfaceVal; IID InterfaceID; ) __VARIANT_NAME_2/*iface*/; _ANONYMOUS_STRUCT 구조체( char* pstrVal; uint3 2_t strLen ; //바이트 수 ) __VARIANT_NAME_3/*str*/; _ANONYMOUS_STRUCT struct ( WCHAR_T* pwstrVal; uint32_t wstrLen; //기호 수 ) __VARIANT_NAME_4/*wstr*/; ) __VARIANT_NAME_1; uint32_t cbElements; //1의 차원 - pvarVal TYPEVAR vt;의 차원 배열; );
유형 t변형다음을 포함하는 구조입니다.
  • 데이터 저장을 위해 직접적으로 의도된 혼합(결합)
  • 데이터 유형 식별자
일반적으로 유형의 변수를 사용하여 작업 t변형다음 알고리즘에 따라 발생합니다.
  1. 현재 변수에 저장된 데이터 유형 확인
  2. 해당 혼합물 필드에 접근하여 데이터에 직접 접근
유형 사용 t변형 1C: 엔터프라이즈 시스템과 외부 구성 요소의 상호 작용을 크게 단순화합니다.

애플리케이션

"examples" 디렉터리에는 기사에 대한 예제가 포함되어 있습니다.
예제/1 - 데모 구성요소 실행
예제/2 - 속성 목록 확장 데모
예제/3 - 메소드 목록 확장 시연
각 디렉토리에는 VS 2008 프로젝트와 미리 만들어진 1C 구성이 포함되어 있습니다.

이 기사에서는 외부 구성 요소 작업, 즉 연결에 대해 다룹니다. 현재 1C Enterprise의 기능을 확장하기 위해 두 가지 외부 구성 요소 기술이 사용됩니다.

  • 1 네이티브 API 사용
  • 2 COM 기술 사용
이 기사에서는 네이티브 API 구성 요소 작업을 강조하기로 결정했습니다.
이제 간단한 것부터 복잡한 것까지 시작해 보겠습니다.
ITS에서 발췌

1. VK가 디스크의 특정 디렉터리에 있다고 가정해 보겠습니다.

"Thick Client(일반 응용 프로그램)"에서 사용할 수 있습니다.

이는 네이티브 구성 요소를 사용하는 가장 간단한 예입니다. 이러한 유형의 구성 요소는 시스템에 등록할 필요가 없으므로 관리가 크게 단순화됩니다.

2. 위에서 논의한 예는 전혀 현실적이지 않습니다. 대부분의 경우 구성 요소는 레이아웃에 배치됩니다. 레이아웃에는 구성 요소 파일과 MANIFEST.xml 파일이 포함된 zip 아카이브가 포함되어야 합니다.
매니페스트 파일 예시:

3. 씬 클라이언트와 웹 클라이언트에서 작업할 때는 반드시 이 방법을 사용하세요.
ITS의 인용문:

설명:
%APPDATA%\1C\1Cv82\ExtCompT- Thick 및 Thin 클라이언트용 구성 요소를 설치하기 위한 디렉터리입니다.
%APPDATA%\Roaming\Mozilla\Extensions- (내 경우에는) Mozilla FF/용 디렉토리 확장
방법을 사용할 때 SetExternalComponent(), 사용된 클라이언트에 따라 확장 프로그램이 적절한 디렉터리에 압축이 풀립니다.

외부 구성 요소 설치 절차의 예:

외부 구성 요소 설치- 해당 메소드는 구성 요소를 처음 설치하는 동안과 설치된 구성 요소 버전을 업데이트해야 하는 경우에만 호출해야 합니다.

씬 클라이언트와 씩 클라이언트의 경우:
다음 방법을 사용하여 외부 구성 요소의 설치 작업을 다시 실행하면 충분합니다. 외부 구성 요소 설치().

구성요소를 업데이트하는 웹 클라이언트의 경우:

  • 웹 브라우저 추가 기능(Mozilla FF) 작업 메커니즘을 통해 플러그인을 제거해야 합니다.
  • 방법을 사용하십시오 외부 구성 요소 설치
VK를 연결하려면 다음 절차를 사용할 수 있습니다.

구성 요소가 설치되지 않은 경우 예외가 발생합니다.

2. 임시 저장소에서 구성 요소를 설치해야 하는 경우가 있습니다(파일이 타사 소스에서 수신됨, 외부 처리). 이 경우 외부 구성 요소 연결 및 외부 구성 요소 설치 방법의 첫 번째 매개 변수는 임시 저장소에 있는 아카이브의 주소입니다. 다음은 작동 방식에 대한 가능한 예입니다.

&OnClient VariableAddressArchiveComponent; &OnClient 변수 구성요소; &OnClient Procedure OnOpen(Failure) // 주소, 문자열 포함(임시 저장소에 있는 zip 아카이브의 바이너리 데이터에 대한 탐색 링크 //) ComponentArchiveAddress = GetArchiveAddressInTemporaryStorage(); EndProcedure // WhenOpen() &OnServer // 메소드 ConnectExternalComponent, SetExternalComponent는 // "탐색 링크" 형식의 문자열을 첫 번째 매개변수로 사용할 수 있습니다. // GetNavigationLink ). 함수 GetArchiveAddressInTemporaryStorage()ProcessingObject = FormAttributesValue("ProcessingObject"); 보관 링크 = PlaceInTemporaryStorage(ProcessingObject.GetLayout("MIKO_phone_IP"), New UniqueIdentifier); ReturnLinkToArchive; EndFunction // GetArchiveAddressInTemporaryStorage() &OnClient // 구성 요소가 아직 설치되지 않았거나 // 업데이트해야 하는 경우 프로시저는 한 번만 호출해야 합니다. Procedure InstallComponent(Command) InstallExternalComponent(ArchiveComponentAddress)를 시도합니다. Exception Report("외부 구성 요소를 설치하지 못했습니다."); 시도 종료; 절차 종료 // InstallComponent() &OnClient // 구성 요소 초기화를 위한 기본 절차 Procedure 초기화(Command) 외부 구성 요소 연결 시도(ComponentArchiveAddress,"Comp" ,ExternalComponentType.Native); 구성요소 = New("AddIn.Comp.MIKO_phone_IP"); Exception Report("초기화 예외입니다. 구성요소가 아직 설치되지 않았을 수 있습니다."); 시도 종료; 절차 종료

기사 제목에는 "인형을 위한"이라는 문구가 포함되어 있습니다. 찻주전자란 무엇보다도 나 자신을 의미했습니다. C++에 대한 나의 모든 지식은 내가 1C의 비뚤어진 길을 시작했을 때 대학 3~4년 수준에 머물렀습니다. 모든 것이 괜찮을 것이지만 최근에는 외부 구성 요소를 작성해야 하는 작업이 발생했습니다. 나는 내 기억을 떠올리고 C++ 지식을 털어내야 했습니다. 모든 것이 그렇게 무섭지 않다는 것이 밝혀졌습니다. 외부 구성 요소 작성에 대한 간단한 소개를 제공하고 싶습니다.

ITS의 템플릿 구성 요소

ITS 디스크에는 외부 구성 요소의 메커니즘에 대한 완전한 문서가 포함되어 있으며, 예제 프로젝트와 자체 개발을 위한 템플릿이 보완되어 있습니다. 해당 소재를 '외장부품기술'이라고 부른다. 문서는 훌륭하지만 여전히 문서를 이해해야 하며 평소와 같이 시간이 부족합니다. 실제로 주목할 가치가 있는 몇 가지 핵심 사항만 있으며 나머지는 부패와 허영입니다. :)

필요한 재료

외부 구성 요소를 만들려면 다음이 필요합니다.

  1. ITS에 소재 '외부 부품 제작 기술' 탑재
  2. 재료에 포함된 빈 외부 구성요소 템플릿
  3. MS 비주얼 스튜디오. Express 버전은 무료이며 우리의 요구에 충분합니다.
  4. C++ 구문에 대한 기본 지식이 있어야 합니다.
  • 변수 선언을 루프 또는 조건과 구별하는 기능
  • 순수한 형태의 문자열이 C++에 존재하지 않는다는 점을 이해하면 분명히 메모리 문제를 해결해야 하는 배열이 있습니다.
  • 물론, 지정된 언어로 작업을 구현하는 능력이 필요합니다. 최소한 C++에서 모든 것을 자체적으로 수행하는 타사 라이브러리를 호출하는 기능입니다.

발굴을 시작하자

Native API에 대한 문서는 매우 자세합니다. 요약하면 다음과 같습니다.

  1. 외부 구성 요소를 사용하면 새 개체(또는 여러 개)로 내장 언어를 확장할 수 있습니다. 저것들. "New" 연산자를 사용하여 생성할 수 있는 클래스를 생성하고 내장 언어에서 이 객체의 메서드를 호출하겠습니다.
  2. 우리의 객체가 작동하기 위해 플랫폼은 우리가 제공해야 하는 특정 프로토콜을 사용하여 객체와 "통신"합니다.
  3. 구성 요소 코드 자체는 일반적으로 두 부분으로 구성됩니다. 첫 번째는 시스템에 구성 요소 자체를 등록하는 것이고, 두 번째는 새 클래스의 작동 및 플랫폼과의 상호 작용입니다.

우리는 구현의 세부 사항을 다루지 않을 것이며 마감 기한이 촉박하고 역량이 충분하지 않습니다. 구성 요소가 작동하려면 라인을 입력해야 하는 위치를 빠르게 이해해야 합니다. 이렇게 하려면 ITS가 포함된 구성 요소 템플릿을 가져와 Visual Studio에서 엽니다. 템플릿은 압축을 푼 아카이브의 템플릿 폴더에 있습니다. 여기에 무엇이 있는지 살펴보겠습니다.

AddInNative.cpp 파일에 관심이 있습니다. 모든 깨달음은 거기에 있습니다. 여기에는 필요한 모든 방법에 대한 템플릿이 포함되어 있으므로 약간만 사용자 정의하면 됩니다. 그러나 빈 템플릿을 기본으로 사용하는 것이 아니라 실제 예제를 다루는 것이 더 쉽다는 것이 밝혀졌습니다. 빈 템플릿에는 포함되지 않은 몇 가지 유용한 기능이 있습니다. 이해가 오면 빈 템플릿을 가져와 문제에 대한 지식으로 다듬어야 합니다. 작업 구성 요소의 예는 example\NativeAPI 폴더에 있고 빈 템플릿은 템플릿 폴더에 있습니다.

예제 폴더와 그 안에 있는 AddInNative.cpp 파일에서 프로젝트를 열어 보겠습니다.

파일의 맨 처음에는 상수와 보조 함수 선언이 있습니다. 우리는 다음 라인에 관심이 있습니다:

우리의 객체는 "실제" 객체로서 러시아어와 영어로 작성된 메서드를 지원합니다. 이를 위해 속성과 메서드의 이름이 두 가지 언어로 선언됩니다. 파란색 프레임은 영국식 목욕탕, 빨간색 프레임은 러시아식 목욕탕입니다. 그림은 예제가 이미 여러 메서드와 속성을 구현하고 있음을 보여줍니다. 우리의 임무는 그것들을 제거하고 우리 자신의 것을 삽입하는 것입니다.

클래스 이름이 선언된 줄은 녹색 프레임으로 강조 표시됩니다. 솔직히 말해서 무슨 뜻인지 이해하지 못했습니다. 변경하면 아무것도 작동하지 않습니다. 그들이 처음에 나를 '멍청이'라고 예약했기 때문에 용서받을 수 있습니다. :)

따라서 객체에 "RunCalculation" 메서드와 "Destination" 속성이 포함된 경우 g_MethodNamesRu 및 g_PropNamesRu 배열에 각각 이 이름을 설명해야 합니다.

1C 언어로 전화

따라서 우리 객체에는 하나의 메서드와 읽기-쓰기 속성이 포함됩니다.

다음과 같은 사용 시나리오를 가정해 보겠습니다.

OurObject = New("AddIn.MyComponent.DataSender"); OurObject. 대상 = "somemail@server. com";
OurObject. RunCalculation(PaymentAmount, “공과금용”);

문자열 속성과 숫자 및 문자열 매개 변수가 있는 메서드가 있습니다. 이 모든 것이 작동하기 위해 1C는 구성 요소와 대략 다음 통신 프로토콜을 수행합니다.

플랫폼은 객체에 미리 정의된 함수를 호출하고 이에 응답하고 명령을 실행합니다. 상황은 메소드와 유사하며 메소드 번호 외에 매개변수 수, 반환 값의 존재 및 선택적 매개변수의 존재가 요청됩니다.

코드로 돌아가 보겠습니다. "마법의 숫자"를 방지하기 위해 메서드와 속성의 수를 결정하는 CAddInNative 클래스에 두 개의 열거형이 선언됩니다. CAddInNative.h 파일을 열고 맨 처음부터 살펴보겠습니다.

빈 템플릿에는 이러한 열거가 포함되어 있지 않으며 러시아어 통화와 러시아어가 아닌 통화를 구분하는 예도 없습니다. 이 접근 방식은 선택 사항입니다. 인터페이스를 따르는 것이 중요하며 전송 여부는 귀하가 결정합니다.

유니코드 문자열

많은 사람들은 플랫폼이 유니코드 형식의 2바이트 문자로 작동한다는 것을 알고 있을 것입니다. 템플릿은 이 목적을 위해 특수 유형 WCHAR_T를 선언합니다. 이 유형은 크로스 플랫폼 래퍼이며 Windows 및 Linux에서 동일한 문자 크기를 보장합니다. 표준 wchar_t 유형은 시스템마다 크기가 다를 수 있습니다. 또한 모든 문자열 리터럴은 문자 L 접두사로 선언됩니다. 이는 해당 문자열이 wchar_t 유형이라는 것을 의미합니다.

간단한 규칙이 있습니다. 내부적으로 문자열 구성 요소는 wchar_t(Linux에서는 4바이트, Windows에서는 2바이트일 수 있음)로 처리되지만 문자열을 1C로 전송하거나 거기에서 수신하자마자 WCHAR_T가 필요합니다(엄격히) 모든 시스템에서 2바이트).

한 유형의 문자열을 다른 유형으로 변환하기 위해 템플릿은 보조 기능을 제공합니다.

첫 번째는 표준 wchar_t에서 WCHAR_T를 형성합니다.

uint32_t convToShortWchar(WCHAR_T** 대상, const wchar_t* 소스, uint32_t len ​​​​= 0);

두 번째는 그 반대입니다. WCHAR_T에서 wchar_t를 형성합니다.

uint32_t constFromShortWchar(wchar_t** 대상, const WCHAR_T* 소스, uint32_t len ​​​​= 0);

플랫폼과 상호작용할 때 항상 WCHAR_T만 사용됩니다.

변형 유형

또 다른 흥미로운 점은 일반 Variant 데이터 유형입니다. 이를 통해 우리는 아시다시피 입력되지 않고 각 변수에 무엇이든 포함될 수 있는 1C 언어와 상호 작용할 수 있습니다. 이 유형은 값을 교환할 때 사용됩니다. RunCalculation 메서드에 숫자와 문자열이라는 두 개의 매개 변수를 전달합니다. 구성 요소는 두 개의 변형 값을 받습니다. 실제 유형을 확인하는 것은 우리의 책임입니다. 아무도 당신이 구성 요소에 숫자가 아닌 값 테이블을 전달하는 것을 막을 수 없습니다.

하지만 내가 틀린 것 같습니다. 제 생각에는 여전히 값 테이블을 NativeAPI로 전송하는 것이 불가능할 것 같습니다. 왜냐하면... 허용되는 유형 목록에는 없지만 String 대신 Date를 전달할 수 있습니다. 이것도 좋지 않습니다. 1C에서 온 변수의 실제 타입을 확인해야 합니다.

Variant 유형은 간단합니다. 이는 속성이 다양한 유형의 값인 구조입니다. DATE, wchar_t, int 등과 같은 속성이 있습니다. Variant의 주요 부분은 변수의 실제 유형을 저장하고 이 Variant를 해석하는 방법을 정확하게 이해할 수 있는 "vt" 속성입니다. 또한 Variant 유형 작업을 단순화하기 위해 여러 보조 매크로가 선언되었습니다.

요점을 파악하세요

소개는 여기까지인 것 같습니다. 외부 구성 요소 구현의 예를 고려해 볼 것을 제안합니다. TK는 ITS 디스크의 구성 요소의 예입니다. 이 예에서는 다음 기능을 설명합니다.

  • 메인 창의 상태 표시줄에 텍스트를 표시합니다.
  • 외부 타이머 이벤트 보내기
  • 바이너리 데이터를 1C:Enterprise로 전송하는 중입니다.
  • 속성 구현
  • 절차의 이행
  • 기능 구현

구성요소에는 다음과 같은 API가 있습니다.

  • 속성:
    • 활성화됨/활성화됨;
    • IsTimer/IsTimerPresent;
    • 행동 양식:
      • 할 수 있게 하다;
      • 비활성화/비활성화;
      • ShowInStatusLine;
      • 활성화 타이머/시작 타이머;
      • 타이머/정지 타이머를 끄십시오.
      • 로드픽처/로드픽처;

1C 코드에서 구독할 수 있는 타이머에 따라 외부 이벤트가 발생합니다.

우리가 가지고 있는 지식을 바탕으로 구성요소를 처음부터 살펴보겠습니다.

등록 구성 요소

우리 개체는 별도의 C++ 클래스(이 경우 CAddInNative)로 구현됩니다. 1C가 우리 클래스를 보려면 dll 라이브러리는 3가지 함수를 내보내야 합니다.

  • 클래스객체 가져오기
  • DestroyObject
  • 클래스 이름 가져오기

이러한 내보내기는 VisualStudio 프로젝트 트리의 AddInNative.def 파일에서 볼 수 있습니다. 다음 함수의 코드를 살펴보겠습니다.

가장 간단한 것인 GetClassNames 함수는 1C 플랫폼에 구성 요소에 어떤 클래스가 있는지 알려줍니다. C++ 전문가가 나를 정정해 주도록 하세요. 여기에서 플랫폼은 C++ 클래스를 가져올 수 있도록 C++ 클래스의 이름으로 응답해야 하는 것 같습니다. 이것이 바로 녹색 "프레임"이 있는 g_kClassNames 배열이 사용되는 용도입니다. 특별히 확인해 보지는 않았지만 단지 컴포넌트를 작동시키기만 하면 되는 경우에는 예제에 나온 대로 모두 놔두시면 됩니다. 이미 작동하고 있으므로 당분간은 손댈 필요가 없습니다.

따라서 GetClassNames는 외부 구성 요소의 유용한 개체를 구현하는 클래스 이름 배열을 플랫폼에 반환합니다. 이 예에서 구성 요소는 클래스 이름이 CAddInNative인 한 요소의 배열을 플랫폼에 반환합니다.

플랫폼은 WCHAR_T 유형의 값을 수신하며 g_kClassNames 배열의 클래스 이름은 wchar_t 유형입니다. 따라서 위에서 설명한 도우미 함수를 사용하여 캐스트가 수행됩니다.

다음 함수는 GetClassObject입니다. 기업 코드에 "New"를 썼을 때 호출됩니다. 플랫폼에서는 클래스의 새 인스턴스를 만들고 새 개체에 대한 포인터를 반환해야 합니다.

플랫폼이 우리에게 알려주는 첫 번째 매개변수는 어떤 클래스를 생성할지(GetClassNames 메서드에 의해 제공된 클래스로부터)라는 점에 다시 한 번 유의하세요. 클래스가 하나만 있기 때문에 이 이름은 여기서 전혀 확인되지 않습니다. 객체는 단순히 new를 통해 생성되고 출력 매개변수 pInterface를 통해 반환됩니다.

마지막으로 필요한 내보내기 기능은 DestroyObject입니다. 이름은 그 자체로 말합니다. 플랫폼에서 객체가 더 이상 필요하지 않으면 삭제해야 합니다. 이전에 생성된 객체에 대한 포인터가 제공됩니다. 불필요한 포인터를 삭제하고 재설정하여 해제합니다.

설명된 구현은 매우 보편적입니다. 구성 요소가 하나의 클래스만 구현하는 경우(예제에서처럼) 이러한 함수를 자체에 복사하기만 하면 됩니다. 유일한 조건은 이름이 CAddInObject가 아닌 다른 이름인 경우 GetClassObject 함수에서 올바른 클래스를 만드는 것입니다.

구성 요소 초기화/종료

구성 요소를 구현하는 클래스를 생성한 후 플랫폼은 이 클래스의 메서드를 호출합니다. 작업을 시작하기 전에 플랫폼은 플랫폼 자체의 특정 메서드를 호출할 수 있는 "자체" 개체를 알려줍니다. 이는 Init 메서드에서 발생합니다. 예제에서 플랫폼 개체는 m_iConnect 변수에 저장됩니다.

또 다른 중요한 방법은 setMemManager입니다. 플랫폼 자체에서 해제할 메모리 블록을 할당할 수 있습니다. 다음과 같이 구현됩니다.

우리는 플랫폼이 우리에게 전달하는 메모리 관리자에 대한 포인터를 저장하기만 하면 됩니다. 그런 다음 이 관리자를 사용하여 플랫폼 자체에서 해제된 메모리를 할당합니다.

그리고 다시 내보내기 기능의 경우와 마찬가지로 초기화 방법은 매우 보편적입니다. 간단히 복사할 수 있으며 실제로 필요할 때까지 "마무리"하는 것에 대해 걱정할 필요가 없습니다.

유효 탑재량. 구성요소 객체의 메서드 및 속성

등록

물론, 우리는 초기화를 위해서가 아니라 몇 가지 유용한 기능을 위해 구성 요소를 만들었습니다. 어떻게 구현되는지 살펴보는 시간입니다.

먼저 1C 언어에서 생성하고 호출할 수 있는 개체를 등록해야 합니다. 이 개체는 RegisterExtensionAs 메서드에 등록됩니다.

이 방법에서는 1C 언어에서 볼 수 있는 클래스 이름을 플랫폼에 알립니다. 이 이름으로 우리는 "New"를 통해 그것을 만들 것입니다. 이 경우 객체 생성은 다음 코드로 수행됩니다.

ConnectExternalComponent(파일, "MyComponent", externalComponentType.Native);
ObjectComponents = 신규( "AddIn.MyComponent.AddInNativeExtension");

문서에 따르면 클래스 이름이 있는 문자열의 메모리는 메모리 관리자에 의해 할당되고 이름은 "AddInNativeExtension" 주소에 기록됩니다. 여기에는 고통 없이 이름을 쓸 수 있습니다. wchar_t에서 WCHAR_T 플랫폼으로의 변환이 다시 발생한다는 점에 유의하세요.

용법

위에서 쓴 것처럼 플랫폼은 구성 요소에서 다양한 언어 기능을 쿼리합니다. 지정된 속성이 존재하는지, 쓰기 가능한지, 함수 매개변수에 기본값이 있는지, 반환 값이 있는지 등이 있습니다. 이전에 제공된 예제 코드를 사용하면 다음과 같습니다.

OurObject = 신규( "AddIn.MyComponent.DataSender"); // DataSender는 RegisterExtensionAs 함수의 이름입니다(아래 설명).
OurObject. 수취인 = " [이메일 보호됨]" ;
OurObject. 계산실행(결제금액, "유틸리티용");

그러면 다음 설문조사가 수행됩니다.

  1. "대상" 속성이 있나요?
  2. 녹음을 지원하나요?
  3. RunCalculation이라는 메서드가 있나요?
  4. 매개변수는 몇 개입니까?
  5. 반환값이 있나요?
  6. 선택적 매개변수의 기본값은 무엇입니까(있는 경우)

여기에서는 예제를 보고 문서를 확인하는 것이 가장 유용합니다. 이러한 모든 설문조사의 구현은 매우 간단합니다. 다양한 방법이 상호 작용을 담당합니다. 모든 내용을 다루지는 않겠습니다. 꽤 잘 문서화되어 있고 구현도 간단합니다. 가장 중요한 순간만 고려되며, 우리는 인형으로서 손을 잡아야 합니다. :). 기본 접근 방식은 다음과 같습니다. 속성이나 메서드가 처음 언급되면 플랫폼은 이를 이름으로 검색하도록 요청합니다. 우리는 이 속성(메서드)의 고유 번호로 응답해야 합니다. 이후의 모든 의사소통은 숫자로만 이루어집니다. 여기서는 이러한 숫자를 저장하는 언급된 열거형이 도움이 될 것입니다.

속성

가장 먼저 고려해야 할 것은 부동산 인프라입니다. 플랫폼은 FindProp 메서드를 사용하여 속성의 존재를 요청합니다.

플랫폼은 우리가 찾고 있는 속성의 이름을 WCHAR_T 형식으로 전달합니다. 보조 메소드를 사용하여 wchar_t로 변환되며 이 텍스트는 먼저 영어 용어로 검색된 다음 러시아어 용어로 검색됩니다. 부동산 번호를 반환해야 합니다. 여기에는 findName 도우미 함수가 포함되어 있습니다. 구현은 예제에 있지만 구성 요소는 빈 템플릿에 없습니다. 구성 요소에 이중 언어 용어를 포함할 계획이라면 해당 항목을 사용자 쪽으로 끌어오는 것이 적절해 보입니다.

다음으로 GetPropName 메서드는 반대 작업을 수행하여 해당 번호로 속성 이름을 가져옵니다. 이름 문자열은 엔터프라이즈 메모리 관리자를 통해서도 할당됩니다. 디버거에서 더하기 기호가 있는 개체의 속성을 확장할 때 GetPropName 메서드와 GetNProps가 사용되는 것 같습니다. 그런 다음 플랫폼은 총 속성 수를 수신하고 각 속성에 대한 이름을 요청합니다.

다음 메서드 쌍은 IsPropReadable/IsPropWritable입니다. 여기에서는 모든 것이 간단합니다. 지정된 속성 번호에 대해 읽기/쓰기 가능 여부를 말해야 합니다.

값 수신 및 쓰기는 GetPropVal/SetPropVal 메소드를 사용하여 수행됩니다. 여기서 더 자세히 알아볼 가치가 있습니다. 우리는 1C:Enterprise 유형으로 작업하기 시작했습니다. 이는 Variant가 등장한다는 의미입니다.

구성 요소 템플릿은 Variant 작업을 단순화하기 위한 보조 매크로 세트를 정의합니다. 첫 번째는 값 유형 확인입니다. 예를 들어 TV_VT 매크로를 사용하면 값 유형을 확인/설정할 수 있습니다. 지원되는 각 유형에 대해 명명된 상수도 정의됩니다. 이러한 상수와 1C:Enterprise 유형에 대한 해당 내용은 설명서에 나열되어 있습니다.

TV_BOOL 매크로는 작업할 수 있는 변형으로부터 부울 값을 받습니다. 비유적으로 정수 값(TV_INT), 문자열(TV_WSTR) 등을 얻습니다. 정확한 값은 코드에 있으므로 언제든지 확인할 수 있습니다.

중요한 점은 변형에 값을 할당하는 것만으로는 충분하지 않으며 실제 유형도 할당해야 한다는 것입니다. GetPropVal에 주의하세요. TV_BOOL = true 할당 외에도 TV_VT = VTYPE_BOOL이라는 유형 할당이 있습니다. 유형이 할당되지 않으면 플랫폼은 어떤 유형의 값이 반환되었는지 알 수 없습니다. 물론 엉망이 되어 잘못된 유형을 설정할 수도 있습니다. 이것은 종종 플랫폼이 떨어지는 것을 동반합니다.

위의 내용을 요약해 보겠습니다.

옵션에서 값을 얻습니다.

bool someVariable = TV_BOOL(pVariant);

옵션에 값을 씁니다.

TV_VT(pVariant) = VTYPE_BOOL; // 유효한 데이터 유형

TV_BOOL(pVariant) = someBooleanVariable; //값 자체를 설정

그리고 지금 - 꼽추 방법!

메서드는 조금 더 복잡하지만 일반적으로 속성과 유사합니다. 첫째, 이름으로 메소드를 검색하고, 총 메소드 수를 가져오고, 숫자로 이름을 가져오는 것과 똑같은 기능이 있습니다. 그러나 위의 기능 외에도 다음과 같은 기능이 추가됩니다.

  • 메소드가 값을 반환할 수 있는 경우 "계산"에서 사용할 수 있으며 1C 언어로 할당 작업 오른쪽에 쓸 수 있습니다. 그렇지 않은 경우 이는 프로시저이므로 "프로시저를 함수로 사용" 예외가 발생합니다.
  • 메소드에는 매개변수가 있습니다. 플랫폼은 해당 번호를 알아야 합니다. 호출에서 메서드 시그니처에 지정된 것보다 더 많은 인수를 지정하면 "매개 변수가 너무 많습니다"라는 오류가 발생합니다.
  • 메서드에 전달된 인수가 충분하지 않으면 그 중 일부는 선택 사항일 수 있으며, 선택적 매개 변수가 없으면 "매개 변수 부족" 오류가 발생합니다.
  • 호출 시 프로시저인 경우 반환 값이 있을 수 없습니다. 함수라면 반환값이 있습니다. 또한 처리가 필요합니다.

이름과 문서를 보면 그 목적이 명확한 여러 가지 간단한 방법이 있습니다. 여기에는 HasRetVal, GetNParams, GetParamDefValue가 포함됩니다. 나는 그것들을 고려하지 않기를 제안합니다; 예는 충분합니다. 우리의 관심은 페이로드의 직접적인 구현에 쏠릴 것입니다. 이는 CallAsProc 및 CallAsFunc 메서드에서 구현됩니다. 첫 번째는 프로시저 호출을 담당하고, 두 번째는 함수 호출을 담당합니다. CallAsFunc에는 함수의 반환 값을 플랫폼에 전달하는 추가 출력 매개 변수가 있다는 점이 다릅니다.

호출은 다음과 같이 수행됩니다. 플랫폼은 호출된 메서드의 번호, 실제 매개변수의 배열 및 해당 번호를 전달합니다. 메소드 번호를 구문 분석하고 전달된 매개변수를 제공해야 합니다. 함수의 경우 반환 값에 무언가를 써야 합니다.

예제에서는 스위치/케이스에서 메소드 번호를 분석하고, 해당 번호에 따라 메소드 로직을 실행합니다. 활성화/비활성화 방법의 경우 확인란을 선택하기만 하면 됩니다. ShowInStatusLine 메서드는 흥미롭습니다. 1C:Enterprise 창의 상태 표시줄에 전달된 내용이 표시됩니다. 이를 위해 구성 요소를 등록할 때 "발행"된 m_iConnect 플랫폼 연결 개체를 사용합니다. 해당 기능의 전체 목록은 설명서에 설명되어 있습니다.

흥미로운 점. 여기서 예제에서는 1C에서 도착하는 값의 종류를 확인하지 않고 단순히 문자열 부분 Variant로 SetStatusLine을 호출합니다. 1C 언어에서 구성 요소 메서드를 호출하고 (문자열 대신) 숫자나 날짜를 전달하면 아무것도 작동하지 않을 것 같습니다... 다시 한 번 전문가가 수정하도록 놔두세요. 하지만 pwstrVal 포인터가 가리키는 것 같습니다 그것이 기업에서 나온 것인지, 정직한 문자열이 아닌 숫자라고 가정해 봅시다. SetStatusLine을 호출하면 플랫폼은 알 수 없는 주소에서 행을 읽으려고 시도하며 충돌이 발생할 가능성이 높습니다. 항상 예상되는 유형을 확인하는 것이 좋습니다. 당신은 결코 알지 못합니다.

예제의 LoadImage 함수는 플랫폼과 문자열 및 바이너리 데이터를 교환할 수 있는 가능성을 고려하여 보다 흥미로운 방식으로 구현되었습니다.

먼저 여기에서 전달된 매개변수의 개수를 확인합니다. 존재하지 않으면 통화가 실패한 것으로 간주됩니다. 플랫폼에서 호출 오류로 해석되는 false를 반환합니다.

다음으로 전달된 매개변수의 유형을 여기에서 확인합니다. 좁은 문자열(VTYPE_PSTR)인 경우 변형의 char 부분이 사용됩니다. 예에서는 paParam->pstrVal이라고 되어 있지만 TV_STR 매크로를 사용할 수 있으며 동일하지만 옵션 작업의 일관성도 유지됩니다.

와이드 문자열(VTYPE_PWSTR)인 경우 변환은 먼저 wchar_t로 수행된 다음 char로 수행됩니다. 사실은 파일 경로가 1C 언어에서 이 메서드로 전달된 다음 fopen(char*) 함수에서 사용된다는 것입니다. 이 함수에는 입력으로 char* 유형이 필요하며 WCHAR_T는 플랫폼에서 우리에게 전송됩니다. 을 위한 올바른 작동문자열 변환이 수행됩니다.

마지막으로 이것이 전혀 문자열이 아닌 경우 호출은 실패한 것으로 간주되어 false가 반환됩니다.

메모리 관리자를 사용하여 이진 데이터에 대한 메모리를 할당합니다. 이는 논리적입니다. 바이너리 데이터는 플랫폼 내에서 완전한 개체가 되며 이를 통해 관리되어야 합니다. 외부 구성 요소 함수의 반환 값인 pvarRetValue 변형에 대해 메모리가 할당됩니다.

전체 파일을 할당된 버퍼로 읽어 들입니다. 반드시바이트 크기는 strLen 옵션 속성과 VTYPE_BLOB 옵션의 데이터 유형에 지정됩니다. 메모리가 성공적으로 할당되면 전체 함수에 대한 성공적인 호출의 표시로 true를 반환합니다.

따라서 1C 언어에서는 다음과 같이 작성됩니다.

BinaryData = 구성 요소. 사진 업로드("C:\pic.jpg");

위에서 설명한 대로 구성 요소 개체의 CallAsFunc 메서드가 호출되어 경로를 전달하고 이진 데이터를 반환합니다.

성공하면 BinaryData 변수에 완전한 1C 언어 개체가 포함됩니다. 범위를 벗어나면 플랫폼에서 점유한 모든 메모리를 해제합니다. 그렇기 때문에 메모리 관리자를 통해 할당되었습니다.

결론

이 이야기는 인형용 찻주전자로 작성되었으므로 용어가 부정확할 가능성이 높습니다. 그러나 이 문서의 목적은 외부 구성 요소를 빠르게 소개하는 것입니다. 불필요한 번거로움이나 긴 논의 없이 단시간에 구성 요소를 신속하게 만들어야 한다면 이 기사가 도움이 되기를 바랍니다. 내 실수로 인해 기분이 나빠지면 C++ 전문가로서 댓글로 알려주시면 수정하겠습니다.

관심을 가져주셔서 감사합니다.

외부 구성 요소 기술을 사용하면 1C:Enterprise 8 시스템과 동적으로 연결하고 긴밀하게 상호 작용하여 기능을 확장하는 프로그램(외부 구성 요소)을 만들 수 있습니다. 이 기술바코드 스캐너, 라벨 프린터 등 다양한 소매 장비를 1C:Enterprise 8 시스템에 연결할 수 있습니다.

네이티브 API

기술은 외부 구성 요소를 만드는 데 사용됩니다. 네이티브 API– 자체 시스템 프로그래밍 인터페이스 1C:Enterprise 8. 운영을 지원합니다. 윈도우 시스템및 Linux를 사용하여 하나 또는 다른 운영 체제에서 실행되는 외부 구성 요소를 생성할 수 있습니다. 기본 API 기술을 사용하여 생성된 구성 요소는 씩(thick) 클라이언트에 연결될 수 있습니다. 씬 클라이언트, 웹 클라이언트, 외부 연결 및 애플리케이션 서버에서.

내장 언어 확장

외부 구성 요소를 사용하면 새 개체로 내장 언어를 확장할 수 있습니다. 외부 구성 요소의 메커니즘 구조는 1C:Enterprise 8 시스템의 내부 구조와 최대한 유사하여 운영 효율성이 향상됩니다.

외부 구성 요소에 의해 제어되는 이벤트를 처리하는 프로시저 호출

외부 구성 요소는 미리 정의된 언어 프로시저에서 처리되는 이벤트를 발생시킬 수 있습니다. 외부 이벤트 처리. 이를 통해 비동기 데이터 교환이 필요한 스캐너 및 기타 장치를 1C:Enterprise 8 시스템에 연결할 수 있습니다.

1C:Enterprise 8 매개변수에 속성 ​​페이지 추가

외부 구성 요소는 1C:Enterprise 8 시스템 매개 변수 대화 상자에 해당 속성 페이지를 추가할 수 있으므로 소매 장비를 시스템에 포함하고 1C:Enterprise 8 시스템에 대한 표준 방식으로 관리할 수 있습니다.

"1C:Enterprise 8" 매개변수 저장 메커니즘을 통해 구성요소 매개변수 저장

매개변수를 저장하는 동안 외부 구성요소는 1C:Enterprise 8 시스템의 메커니즘을 사용할 수 있습니다.

상태 표시줄에 액세스하기

작동 중에 외부 구성 요소의 상태는 1C:Enterprise 8 시스템의 상태 패널에 반영될 수 있습니다.

올렉 필리포프, ANT-Inform, 개발부 부국장, [이메일 보호됨]

1C:Enterprise의 기능 확장
1부: 외부 COM 구성요소

모든 1C 개발자의 삶에는 자신에게 할당된 작업이 1C 플랫폼의 기능을 초과하는 때가 있습니다. '가능성의 경계를 뛰어넘는' 방법을 살펴보자

숙련된 1C 개발자는 기사 제목의 처음 세 단어에서 1C:Enterprise의 외부 구성 요소에 대해 이야기할 것임을 이미 추측했을 것입니다. 이 기술은 1C:Enterprise 7.7 플랫폼(또는 이전)부터 존재했습니다. 역사적으로 이는 상용 장비(바코드 스캐너, 전자 저울, KKM), 이 기간 동안 1C 플랫폼은 장비에서 시작된 특정 이벤트를 처리해야 합니다. 이러한 이벤트는 COM/LPT 포트에 도착하는 일련의 바이트에 지나지 않습니다. 물론 1C 플랫폼을 이러한 하위 수준 메커니즘과 함께 작동하도록 조정하는 것은 그다지 정확하지 않으므로 1C: Enterprise용 외부 구성 요소 기술을 생각해 냈습니다.

이 기사 시리즈에서는 외부 구성 요소에 대해서만 이야기하는 것이 아닙니다. 외부 구성 요소는 상당히 강력하고 복잡한 메커니즘이므로 이를 사용하여 일부 문제를 해결하는 것은 "대포로 참새를 쏘는 것"으로 간주됩니다. 그러나 외부 구성 요소가 가장 많이 사용됩니다. 보편적인 치료법 1C:Enterprise 플랫폼을 넘어서는 모든 종류의 문제를 해결하기 위해 먼저 시작하겠습니다. 이 기사에서는 COM을 기반으로 외부 구성 요소를 생성하기 위해 가장 오래되고 가장 자주 사용되며 시간 테스트를 거친 기술에 대해 설명합니다.

외부 구성요소란 무엇입니까?

위에서 언급한 외부 구성 요소는 버전 7.7부터 1C:Enterprise에 나타났습니다. 처음에는 전통에 따라 1C 플랫폼 개발자가 "신경 쓰지 않았으며"외부 구성 요소는 특정 필수 속성과 방법을 가진 개체였습니다. 구성 요소는 오늘날에도 여전히 동일한 형태로 존재합니다. 즉, 1C:Enterprise 7.7용으로 작성된 구성 요소는 (이론적으로) 1C:Enterprise 8.3에서도 작동합니다.

실제로는 미묘한 점이 많이 있습니다. 외부 구성 요소가 플랫폼 자체와 적극적으로 상호 작용하는 경우 해당 기능은 특정 버전에 맞게 특화됩니다.

버전 8.2부터 1C:Enterprise는 NativeAPI라는 외부 구성 요소 개발을 위한 새로운 기술을 도입했습니다. 이 기술을 사용하여 작성된 구성 요소는 더 이상 COM 개체가 아닙니다. 한편으로 이것은 장점입니다. 이러한 구성 요소는 등록이 필요하지 않지만 1C:Enterprise 플랫폼을 제외한 다른 곳에서는 사용할 수 없습니다. 외부 부품의 개발이 다소 어려워졌습니다. 많은 분량필수 인터페이스를 지원해야 합니다. 하지만 다음 기사에서 이에 대해 이야기하겠습니다.

외부 구성 요소 및 COM 기술

COM 기술 자체에 대해서는 이 주제에 관한 문헌이 많기 때문에 자세히 설명하지 않겠습니다. 많은 사람들이 일반 inproc 서버 생성과 1C:Enterprise용 외부 구성 요소 생성을 "혼란"한다고 말해야 하지만 이는 사실과 멀지 않습니다. 이 기능만으로 문제를 해결할 수 있는 경우가 많습니다. Visual Studio에서 COM 개체를 만드는 방법은 다양한 소스에 설명되어 있습니다. 특히 그 사람은 1C:Enterprise의 전화 예를 들어 이것이 어떻게 수행되는지 자세히 썼습니다.

1C:Enterprise에 대한 본격적인 COM 외부 구성 요소를 만들고 싶다면(이것이 필요한 옵션 중 하나만 생각할 수 있습니다. 구성 요소는 1C 플랫폼의 시스템과 적극적으로 상호 작용해야 하며 사용자에게 알려야 합니다. 상태 표시줄 변경, 대화 상자 표시 등), 외부 구성 요소의 기술을 직접 사용해야 합니다. 그럼 시작해 보겠습니다.

공유하다