External component technology (). Technology of external components () Technology of creating external components 1c

  • Tutorial

Introduction

This article gives an idea of ​​how external components work in the 1C: Enterprise system.
The process of developing an external component for the 1C: Enterprise system version 8.2 running under OS will be shown Windows family with a file version of work. This option is used in most solutions designed for small businesses. VK will be implemented in the C++ programming language.

External components "1C: Enterprise"

"1C: Enterprise" is an extensible system. For expansion functionality The system uses external components (EC). From a developer’s point of view, a VC is an external object that has properties and methods, and can also generate events for processing by the 1C: Enterprise system.
External components can be used to solve a class of problems that are difficult or even impossible to implement in the programming language built into 1C: Enterprise. In particular, this class includes tasks that require low-level interaction with the operating system, for example, to work with specific equipment.
The 1C: Enterprise system uses two technologies for creating external components:
  • using Native API
  • using COM technology
Given the given restrictions, the difference between the two above-mentioned technologies is insignificant, so we will consider the development of video games using the Native API. If necessary, the implemented developments can be applied to the development of computer software using COM technology, and also, with minor modifications, applied for use in the 1C: Enterprise system with other operating options other than the file operating mode.
VK structure
The external component of the 1C: Enterprise system is presented in the form of a DLL library. The library code describes the descendant class IComponentBase. The created class must define methods responsible for implementing the functions of the external component. The overridden methods will be described in more detail below as the material is presented.

Launching a demo VK

Task:
  1. Assemble an external component supplied with an ITS subscription and intended to demonstrate the main capabilities of the external component mechanism in 1C
  2. Connect the demo component to the 1C configuration
  3. Make sure the declared functions work correctly
Compilation
The demo VK is located on the ITS subscription disk in the “/VNCOMP82/example/NativeAPI” directory.
To build a demo VK we will use Microsoft Visual Studio 2008. Other versions of this product do not support the Visual Studio project format used.


Open the AddInNative project. In the project settings, we include the directory with the header files necessary to build the project. By default, they are located on the ITS disk in the directory /VNCOMP82/include.
The result of the build is the file /bind/AddInNative.dll. This is the compiled library for connecting to the 1C configuration.
Connecting VK to 1C configuration
Let's create an empty 1C configuration.
Below is the module code managed application.
variable DemoComp; Procedure When System Starts() Connect External Component("...\bind\AddInNative.dll", "DemoVK", External Component Type.Native);
DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); EndProcedure
If no error was reported when starting the 1C configuration, then the VK was successfully connected. As a result of executing the above code, an object appears in the global visibility of the configuration DemoComp
, which has properties and methods that are defined in the code of the external component.
Demonstration of the built-in functionality
Let's check the functionality of the demo VK. To do this, let's try to set and read some properties, call some VK methods, and also receive and process the VK message.
  1. The documentation supplied on the ITS disk states the following functionality of the demo VC:
    Managing Component Object State Methods:, Turn on
    Switch off Properties:
  2. Included
    Timer management Every second the component sends a message to the 1C: Enterprise system with parameters, Component Timer
    Managing Component Object State and a system clock counter line., StartTimer
    Switch off StopTimer
  3. There is a Timer Method ShowInStatusLine
  4. There is a Timer , which displays in the status line the text passed to the method as parameters UploadPicture . Loads an image from specified file
and transmits it to the 1C: Enterprise system in the form of binary data.
variable DemoComp; Procedure When System Starts() ConnectExternalComponent(...);
DemoComp = New("AddIn.DemoVK.AddInNativeExtension");


DemoComp.Disable(); Report(DemoComp.Enabled); DemoComp.Enable(); Report(DemoComp.Enabled); DemoComp.StartTimer(); End of Procedure Procedure External Event Processing(Source, Event, Data) Report(Source + " " + Event + " " + Data); EndProcedure The result of running the configuration is shown in the image, The “Messages” panel displays the results of method calls DemoComp.Enable(); DemoComp.Disable() And

Demo.Comp.Enable()

. Subsequent lines in the same panel contain the results of processing messages received from VK -
Source Event Data Event respectively.
Custom external component name Task: Change the name of the external component to an arbitrary one. The previous section used the identifier
AddInNativeExtension , the meaning of which was not explained. In this case- this is the name of the extension. Task: Change the name of the external component to an arbitrary one. The VK code defines a method
RegisterExtensionAs
, returning the name to the 1C: Enterprise system, which is necessary for subsequent registration of the VK in the system. It is recommended to specify an identifier that to some extent reveals the essence of the external component. Let's give full code
method

with the extension name changed:

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, iActualSize) return false;
  1. In the example given, the VK name is changed to
  2. SomeName
  3. . Then when connecting VK you must specify a new name:

DemoComp = New("AddIn.DemoVK.SomeName");
Expanding the list of VK properties
Task:
Study the implementation of VK properties
Add a read/write property of string type
Add a read/write string property that stores the data type of the last property set. No action is taken when setting the property value
Returns the name of the property by its serial number and by the passed language identifier
GetPropVal
Returns the value of the property with the specified ordinal number
SetPropVal
Sets the value of the property with the specified ordinal number
IsPropReadable
Returns the readability flag of the property with the specified sequence number
IsPropWritable
Returns the writability flag of the property with the specified sequence number


Let's consider the implementation of the above class methods CAddInNative.
In the demo VC, 2 properties are defined: Properties: DemoComp.Enable(); StopTimer (IsEnabled DemoComp.Enable(); IsTimerPresent).
IN global area For visibility of the library code, two arrays are defined:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent"); static wchar_t *g_PropNamesRu = (L"Enabled", L"There is a Timer");
which store Russian and English property names. In the header file AddInNative.h the enumeration is defined:
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropLast // Always last );
ePropIsEnabled DemoComp.Enable(); ePropIsTimerPresent, respectively having the values ​​0 and 1, are used to replace the serial numbers of properties with meaningful identifiers. ePropLast, which has a value of 2, is used to obtain the number of properties (using the GetNProps method). These names are used only within the component code and are not available from the outside.
The FindProp and GetPropName methods perform array searches g_PropNames DemoComp.Enable(); g_PropNamesRu.
To store the values ​​of the fields in the library module, the CAddInNative class has properties that store the value of the component properties. Methods GetPropVal DemoComp.Enable(); SetPropVal return and set the value of these properties accordingly.
Methods IsPropReadable DemoComp.Enable(); IsPropWritable and return true or false, depending on the passed ordinal number of the property in accordance with the application logic.
To add arbitrary property necessary:

  1. Add the name of the property being added to arrays g_PropNames DemoComp.Enable(); g_PropNamesRu(file AddInNative.cpp)
  2. To list Props(file AddInNative.h) before ePropLast add a name that uniquely identifies the property being added
  3. Organize memory for storing property values ​​(create module component fields that store the corresponding values)
  4. Make changes to methods GetPropVal DemoComp.Enable(); SetPropVal to interact with the memory allocated in the previous step
  5. In accordance with the application logic, make changes to the methods IsPropReadable DemoComp.Enable(); IsPropWritable
Points 1, 2, 5 do not need explanation. Details of the implementation of these steps can be found by studying the appendix to the article.
Let's give names to the test properties Test DemoComp.Enable(); Type Check respectively. Then, as a result of step 1, we have:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent", L"Test", L"TestType"); static wchar_t *g_PropNamesRu = (L"Enabled", L"There is a Timer", L"Test", L"Type Check");
Transfer Props will look like:
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropTest1, ePropTest2, ePropLast // Always last );
To significantly simplify the code, we will use STL C++. In particular, for working with strings WCHAR, let's connect the library wstring.
To save a method value Test, we define in the class CAddInNative in the scope of a private field:
string test1;
To transfer string parameters between 1C: Enterprise and external components, the 1C: Enterprise memory manager is used. Let's take a closer look at his work. The functions are used to allocate and free memory respectively AllocMemory DemoComp.Enable(); FreeMemory defined in the file ImemoryManager.h. If it is necessary to pass a string parameter to the 1C: Enterprise system, the external component must allocate memory for it by calling the function AllocMemory. Her prototype looks like in the following way:
virtual bool ADDIN_API AllocMemory (void** pMemory, unsigned long ulCountByte) = 0;
Where pMemory- the address of the pointer into which the address of the allocated memory area will be placed,
ulCountByte- the size of the allocated memory area.
An example of memory allocation for a string:
WCHAR_T *t1 = NULL, *test = L"TEST_STRING"; int iActualSize = wcslen(test1)+1; m_iMemory->AllocMemory((void**)&t1, iActualSize * sizeof(WCHAR_T)); ::convToShortWchar(&t1, test1, iActualSize);
For convenience of working with string data types, we will describe the function wstring_to_p. It receives a wstring string as a parameter. The result of the function is a filled structure tVariant. Function code:
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(); return true)
Then the corresponding case section switch statement- this is the name of the extension. GetPropVal will take the form:
case ePropTest1: wstring_to_p(test1, pvarPropVal);
break; SetPropVal:
Method
case ePropTest1: if (TV_VT(varPropVal) != VTYPE_PWSTR) return false; test1 = std::wstring((wchar_t*)(varPropVal -> pstrVal));
break;
To implement the second property, we define a class field
CaddInNative
Now, when requesting to read the value of the second property, we will return the value last_type, what the designated task requires.
Let's check the functionality of the changes made.
To do this, we present appearance 1C configurations to the form:
variable DemoComp; Procedure When System Starts() Connect External Component("...", "DemoVK", External Component Type.Native);
DemoComp = New("AddIn.DemoVK.SomeName");
3
DemoComp.TypeCheck = 1;
Report(String(DemoComp.TypeCheck));
22

DemoComp.Test = "Vasya"; Report(String(DemoComp.Test)); DemoComp.Test = "Petya";

Report(String(DemoComp.Test));

Task:
  1. Report(String(DemoComp.TypeCheck)); EndProcedure
  2. As a result of the launch, we will receive a sequence of messages:
  3. Vasya Peter The second and third messages are the result of reading the property set in the previous step. The first and second messages contain the type code of the last property set. 3 corresponds to an integer value, 22 to a string value. The correspondence of types and their codes is established in the file
  4. types.h

, which is located on the ITS disk.
Expanding the list of methods, Extend the functionality of the external component with the following functionality:, Explore ways to implement external component methods
Add a function method
Function1
, which takes two strings (“Parameter1” and “Parameter2”) as a parameter. The result is a string like: “Checking. Parameter1, Parameter2"
Make sure the changes you make work.
To define the methods of the component being created, the developer must implement the following methods in the AddInNative library code:
GetNMethods
FindMethod false GetMethodName
Designed to obtain the corresponding number of methods, search for the number and name of the method. Similar to the corresponding methods for properties
false GetNParams
Returns the number of method parameters with the specified sequence number; if a method with this number is absent or has no parameters, returns 0
GetParamDefValue false, a runtime error occurs and execution of the 1C: Enterprise module is terminated. Memory for the array of parameters is allocated by 1C: Enterprise. If the return value is a string or binary data type, the component allocates memory with the function AllocMemory memory manager, writes data there and stores this address in the corresponding field of the structure. 1C: The enterprise will free this memory by calling FreeMemory.
A complete description of the methods, including a list of parameters, is described in detail in the documentation supplied on the ITS disk.
Let's consider the implementation of the methods described above.
In the component code, two arrays are defined:
static wchar_t *g_MethodNames = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture"); static wchar_t *g_MethodNamesRu = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadImage");
and enumeration:
enum Methods ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethLast // Always last );
They are used in functions Expanding the list of methods, Extend the functionality of the external component with the following functionality: DemoComp.Enable(); Explore ways to implement external component methods, by analogy with the description of properties.
Methods Function1, Make sure the changes you make work., GetNMethods implement switch, depending on the passed parameters and application logic, return the required value. Method GetNMethods in its code it has a list of only methods that can return a result. For them he returns true. For all steel methods returns false.
Methods Designed to obtain the corresponding number of methods, search for the number and name of the method. Similar to the corresponding methods for properties DemoComp.Enable(); Returns the number of method parameters with the specified sequence number; if a method with this number is absent or has no parameters, returns 0 contain directly executable code of the method.
To add a method that can only be called as a function, you need to make the following changes to source code external components:
  1. Add method name to arrays g_MethodNames DemoComp.Enable(); g_MethodNamesRu(file AddInNative.cpp)
  2. Add a meaningful method identifier to the Methods enumeration (file AddInNative.h)
  3. Make changes to the function code Function1 according to program logic
  4. If necessary, make changes to the method code Make sure the changes you make work., if you want to use the default values ​​of the method parameters.
  5. Make changes to the function GetNMethods
  6. Make changes to the logic of functions Designed to obtain the corresponding number of methods, search for the number and name of the method. Similar to the corresponding methods for properties or Returns the number of method parameters with the specified sequence number; if a method with this number is absent or has no parameters, returns 0, placing the directly executable code of the method there
Let's present the arrays g_MethodNames DemoComp.Enable(); g_MethodNamesRu, as well as listing Methods to the form:
static wchar_t *g_MethodNames = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture", L"Test"); static wchar_t *g_MethodNamesRu = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture", L"Test");

Enum Methods ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethTest, eMethLast // Always last );
Let's edit the function Expanding the list of VK properties so that it returns the number of parameters of the “Test” method:
long CAddInNative::GetNParams(const long lMethodNum) ( switch(lMethodNum) ( case eMethShowInStatusLine: return 1; case eMethLoadPicture: return 1; case eMethTest: return 2; default: return 0; ) return 0; )
Let's make changes to the function:
bool CAddInNative::GetParamDefValue(const long lMethodNum, const long lParamNum, tVariant *pvarParamDefValue) ( ​​TV_VT(pvarParamDefValue)= VTYPE_EMPTY; switch(lMethodNum) ( case eMethEnable: case eMethDisable: case eMethShowInStatusLine: case eMethStartTimer : case eMethStopTimer: case eMethTest: / / There are no parameter values ​​by default break; default: return false;
Thanks to the added line
case eMethTest:
if one or more arguments are missing, the corresponding parameters will have an empty value ( VTYPE_EMPTY). If you need a default value for a parameter, you should set it in the section eMethTest function switch statement CAddInNative::GetParamDefValue.
Since the Test method can return a value, you need to make changes to the function code GetNMethods:
bool CAddInNative::HasRetVal(const long lMethodNum) ( switch(lMethodNum) ( case eMethLoadPicture: case eMethTest: return true; default: return false; ) return false; )
And add the executable code of the method to the function Returns the number of method parameters with the specified sequence number; if a method with this number is absent or has no parameters, returns 0:
bool CAddInNative::CallAsFunc(const long lMethodNum, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) ( ... std::wstring s1, s2; switch(lMethodNum) ( case eMethLoadPicture: ... break; case eMethTest: if (!lSizeArray || !paParams) return false; s1 = (paParams) -> pwstrVal; s2 = (paParams+1) -> pwstring_to_p(std::wstring(s1+s2), pvarRetValue); ; break ; return ret ;
Let's compile the component and bring the configuration code to the form:
variable DemoComp; Procedure When System Starts() Connect External Component("...", "DemoVK", External Component Type.Native);
DemoComp = New("AddIn.DemoVK.SomeName");

lane = DemoComp.Test("Hello," "World!");

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, iActualSize) return false;
  1. Report(per); EndProcedure
  2. After launching the configuration, we will receive the message: “Hello, World!”, which indicates that the method worked successfully.
  3. types.h

Timer Study the implementation of the timer in the demo VK. Modify the “StartTimer” method by adding the ability to pass in the parameters the timer response interval (in milliseconds) will be sent to your program at the time interval that you set when creating the timer.
To create a timer, use the function SetTimer:
UINT SetTimer(HWND hWnd, // window descriptor UINT nIDevent, // timer identifier (number) UINT nElapse, // delay TIMERPROC lpTimerFunc); // pointer to function
The operating system will send a message Study the implementation of the timer in the demo VK into the program with the interval specified in the argument nElapse(in milliseconds). In the last parameter you can specify a function that will be executed each time the timer fires. The header of this function should look like this (the name can be anything):
void __stdcall TimerProc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Let's consider the implementation of a timer in the demo VC.
Since we are considering the process of developing an external component for Windows operating systems, we will not consider the implementation of a timer in other operating systems. For GNU/Linux OS, in particular, the implementation will differ in the syntax of the function SetTimer DemoComp.Enable(); TimerProc.
The executable code calls the method SetTimer, to which the function is passed MyTimerProc:
m_uiTimer = ::SetTimer(NULL,0,100,(TIMERPROC)MyTimerProc);
The ID of the created timer is placed in a variable m_uiTimer so that it can be disabled later.
Function MyTimerProc as follows:
VOID CALLBACK MyTimerProc(HWND hwnd, // handle of window for timer messages UINT uMsg, // WM_TIMER message UINT idEvent, // timer identifier DWORD dwTime // current system time) ( if (!pAsyncEvent) return; wchar_t *who = L "ComponentNative", *what = L"Timer"; wchar_t *wstime = new wchar_t; if (wstime) ( wmemset(wstime, 0, TIME_LEN); ::_ultow(dwTime, wstime, 10); pAsyncEvent->ExternalEvent(who , what, wstime); delete wstime;
The essence of the function is that the method is called ExternalEvent, which sends a message to the 1C: Enterprise system.
To expand the functionality of the method and a system clock counter line. Let's do the following:
Modifying the method code Function1 so that it is for the method eMethStartTimer returned value 1:
case eMethStartTimer: return 1;
Here is the method code Designed to obtain the corresponding number of methods, search for the number and name of the method. Similar to the corresponding methods for properties to the form:
case 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;
Now let's check the functionality. To do this, we will write the code in the managed application module of the configuration:
variable DemoComp; Procedure When System Starts() Connect External Component("...", "DemoVK", External Component Type.Native);
After starting the configuration, the program will receive messages at intervals of 2 seconds, which indicates that the timer is working correctly.

Interaction with the 1C: Enterprise system

To interact between the external component and the 1C: Enterprise system, methods of the IAddInDefBase class, described in the file AddInDefBase.h. We list the most commonly used ones:
Generating an Error Message
virtual bool ADDIN_API AddError(unsigned short wcode, const WCHAR_T* source, const WCHAR_T* descr, long scode)
wcode, scode- error codes (a list of error codes with descriptions can be found on the ITS disk)
source- source of error
descr- error description
Sending a message to the 1C: Enterprise system
virtual bool ADDIN_API ExternalEvent(WCHAR_T* wszSource, WCHAR_T* wszMessage, WCHAR_T* wszData) = 0;
wszSource- message source
wszMessage- Message text
wszData- transmitted data
Message interception is carried out by the External Event Processing procedure
Registration of an external component in the 1C: Enterprise system
virtual bool ADDIN_API RegisterProfileAs(WCHAR_T* wszProfileName)
wszProfileName- component name.
These methods are sufficient for full interaction between VK and 1C. To receive data by an external component from the 1C: Enterprise system and vice versa, the external component sends a special message, which in turn is intercepted by the 1C system and, if necessary, calls the methods of the external component to transmit data back.

tVariant data type

When exchanging data between the external component and the 1C: Enterprise system, the tVariant data type is used. It is described in the types.h file, which can be found on the ITS disk:
struct _tVariant ( _ANONYMOUS_UNION 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 ; int32_t errCode; float fltVal; bVal; wchar_t wchVal; struct _tVal; struct tm tmVal; void* pInterfaceVal; __VARIANT_NAME_2/*iface*/; pstrVal; uint32_t strLen ; //count of bytes ) __VARIANT_NAME_3/*str*/; _ANONYMOUS_STRUCT struct ( WCHAR_T* pwstrVal; uint32_t wstrLen; //count of symbol ) __VARIANT_NAME_1; dimensional array in pvarVal TYPEVAR vt);
Type tVariant is a structure that includes:
  • mixture (union) intended directly for data storage
  • data type identifier
In general, working with variables of type tVariant occurs according to the following algorithm:
  1. Determining the type of data currently stored in a variable
  2. Access the corresponding mixture field to directly access the data
Using the type tVariant significantly simplifies the interaction of the 1C: Enterprise system and external components

Application

The “examples” directory contains examples for the article
examples/1 - launch the demo component
examples/2 - demonstration of property list expansion
examples/3 - demonstration of expanding the list of methods
Each directory contains a VS 2008 project and a ready-made 1C configuration.

This article is devoted to working with external components, namely, connecting them. At the moment, to expand the capabilities of 1C Enterprise, two technologies of external components are used:

  • 1 Using Native API
  • 2 Using COM technology
In this article, I decided to highlight working with Native API components.
So, let's get started, from simple to complex:
Excerpt from ITS

1. Let’s say our VK is located in a specific directory on the disk:

Can be used in the "Thick Client (regular application)";

This is the simplest example of working with the Native component. Please note that this type of component does not require registration in the system, which greatly simplifies administration.

2. The example discussed above is not at all realistic. Most often, the component is placed in a layout. The layout must contain a zip archive with component files and a MANIFEST.xml file
Example manifest file:

3. When working in a thin and web client, be sure to use the method.
Quote from ITS:

Explanation:
%APPDATA%\1C\1Cv82\ExtCompT- directory for installing components for Thick and Thin clients.
%APPDATA%\Roaming\Mozilla\Extensions- directory (in my case) extensions for Mozilla FF/
When using the method SetExternalComponent(), depending on the client used, extensions will be unpacked into the appropriate directory.

An example of the external component installation procedure:

InstallExternalComponent- the method should be called only during the initial installation of the component and in the case when it is necessary to update the installed version of the component.

In case of thin and thick clients:
It is enough to re-execute the installation operation of the external component using the method InstallExternalComponent().

In the case of a web client to update a component:

  • It is necessary to remove the plugin through the mechanism of working with web browser add-ons (Mozilla FF)
  • Use the method InstallExternalComponent
To connect a VK you can use the following procedure:

If the component has not been installed, an exception will be thrown.

2. There are cases when a component needs to be installed from temporary storage (the file is received from a third-party source, external processing), in this case, the first parameters in the methods Attach External Component and Install External Component are the address of the archive in temporary storage. Below is a possible example of how it works:

&OnClient VariableAddressArchiveComponent; &OnClient Variable Component; &OnClient Procedure OnOpen(Failure) // address, contains a string (navigation link to the binary data of the zip archive in // temporary storage) ComponentArchiveAddress = GetArchiveAddressInTemporaryStorage(); EndProcedure // WhenOpen() &OnServer // methods ConnectExternalComponent, SetExternalComponent can take as // as the first parameter a string in the format "navigation link" // (URL to an external component packaged in a ZIP archive, in a format similar to // GetNavigationLink ). Function GetArchiveAddressInTemporaryStorage()ProcessingObject = FormAttributesValue("ProcessingObject");

The technology of external components allows you to create programs (external components) that will dynamically connect and closely interact with the 1C:Enterprise 8 system, expanding its capabilities. This technology allows you to connect various retail equipment to the 1C:Enterprise 8 system: barcode scanners, label printers, etc.

Native API

Technology is used to create external components Native API– its own system programming interface 1C:Enterprise 8. It supports Windows and Linux operating systems, and makes it possible to create external components that work under both one and another operating system. Components created using Native API technology can be connected in a thick client, in a thin client, in a web client, in an external connection and in an application server.

Built-in language extension

External components allow you to extend the built-in language with new objects. The structures of the mechanisms of external components are as close as possible to the internal structures of the 1C:Enterprise 8 system, which increases operational efficiency.

Calling a procedure to handle events controlled by an external component

An external component can raise events that are processed in a predefined language procedure Handling External Events. This allows you to connect scanners and other devices that require asynchronous data exchange to the 1C:Enterprise 8 system.

Adding a property page to the 1C:Enterprise 8 parameters

External components can add their property pages to the 1C:Enterprise 8 system parameters dialog. Thus, retail equipment can be included in the system and managed in a standard way for the 1C:Enterprise 8 system.

Saving component parameters through the “1C:Enterprise 8” parameter saving mechanism

While saving its parameters, the external component can use the mechanisms of the 1C:Enterprise 8 system.

Accessing the status bar

During operation, the state of the external component can be reflected in the status panel of the 1C:Enterprise 8 system.

OLEG FILIPOV, ANT-Inform, Deputy Head of Development Department, [email protected]

Expanding the functionality of 1C:Enterprise
Part 1: External COM Components

There comes a time in the life of every 1C developer when the tasks assigned to him exceed the capabilities of the 1C platform. Let's look at ways to “overcome the boundary of the possible”

Experienced 1C developers have probably already guessed from the first three words of the title of the article that we will be talking about external components for 1C:Enterprise. This technology has existed since the days of the 1C:Enterprise 7.7 platform (or earlier). Historically, it appeared mainly to solve problems of interaction with commercial equipment (Barcode scanners, electronic scales, cash registers), during which it became necessary for the 1C platform to process certain events initiated by the equipment. Such events are nothing more than sequences of bytes arriving on COM/LPT ports. Of course, adapting the 1C platform to work with such low-level mechanisms would not be very correct, so we came up with the technology of external components for 1C: Enterprise.

In this series of articles we will not only talk about external components: external components are a fairly powerful and complex mechanism, so using them to solve some problems is seen as “shooting sparrows with a cannon.” Nevertheless, external components are the most universal tool for solving all sorts of problems that go beyond the scope of the 1C:Enterprise platform, so we will start with them. The article will discuss the oldest, most frequently used and time-tested technology for creating external components - based on COM.

What are external components

External components, as mentioned above, appeared in 1C:Enterprise since version 7.7. Initially, according to tradition, the developers of the 1C platform “didn’t bother,” and external components were an object with certain mandatory properties and methods. The components still exist in the same form to this day. That is, components written for 1C:Enterprise 7.7 will (in theory) work with 1C:Enterprise 8.3.

In practice, there are a number of subtleties: if an external component actively interacts with the platform itself, then its functions will be specialized for a specific version.

Since version 8.2, 1C:Enterprise has introduced a new technology for developing external components, the so-called NativeAPI. Components written using this technology are no longer COM objects. On the one hand, this is a plus - these components do not require registration, on the other hand, their use anywhere else except the 1C:Enterprise platform is impossible. The development of external components has become somewhat more complicated; they must support a slightly larger number of required interfaces. But we will talk about it in the next article.

External components and COM technology

I will not describe the COM technology itself in detail, because there is a lot of literature on this topic. One should probably just say that many people “confuse” creating a regular inproc server with creating external components for 1C:Enterprise, but this is not far from the truth. Very often you can get by with just this functionality. How to create a COM object in Visual Studio is described in many different sources. In particular, the person wrote in detail how this is done, with an example of a call from 1C:Enterprise.

If you still want to make a full-fledged COM external component for 1C:Enterprise (of the options why this might be needed, I can think of only one - the component must actively interact with the system on the 1C platform, notify users, change the status line, display dialog boxes and etc.), then you need to use the technology of external components directly. So let's get started.

ansmirnov August 22, 2013 at 2:12 pm

External components in 1C 8.2

  • Programming,
  • C++
  • Tutorial

Introduction

This article gives an idea of ​​how external components work in the 1C: Enterprise system.
The process of developing an external component for the 1C: Enterprise system version 8.2, running under Windows OS with a file mode of operation, will be shown. This option is used in most solutions designed for small businesses. VK will be implemented in the C++ programming language.

External components "1C: Enterprise"

"1C: Enterprise" is an extensible system. External components (EC) are used to expand the functionality of the system. From a developer’s point of view, a VC is an external object that has properties and methods, and can also generate events for processing by the 1C: Enterprise system.
External components can be used to solve a class of problems that are difficult or even impossible to implement in the programming language built into 1C: Enterprise. In particular, this class includes tasks that require low-level interaction with the operating system, for example, to work with specific equipment.
The 1C: Enterprise system uses two technologies for creating external components:
  • using Native API
  • using COM technology
Given the given restrictions, the difference between the two above-mentioned technologies is insignificant, so we will consider the development of video games using the Native API. If necessary, the implemented developments can be applied to the development of computer software using COM technology, and also, with minor modifications, applied for use in the 1C: Enterprise system with other operating options other than the file operating mode.
VK structure
The external component of the 1C: Enterprise system is presented in the form of a DLL library. The library code describes the descendant class IComponentBase. The created class must define methods responsible for implementing the functions of the external component. The overridden methods will be described in more detail below as the material is presented.

Launching a demo VK

Task:
  1. Assemble an external component supplied with an ITS subscription and intended to demonstrate the main capabilities of the external component mechanism in 1C
  2. Connect the demo component to the 1C configuration
  3. Make sure the declared functions work correctly
Compilation
The demo VK is located on the ITS subscription disk in the “/VNCOMP82/example/NativeAPI” directory.
To build the demo VC we will use Microsoft Visual Studio 2008. Other versions of this product do not support the Visual Studio project format used.


Open the AddInNative project. In the project settings, we include the directory with the header files necessary to build the project. By default, they are located on the ITS disk in the directory /VNCOMP82/include.
The result of the build is the file /bind/AddInNative.dll. This is the compiled library for connecting to the 1C configuration.
Connecting VK to 1C configuration
Let's create an empty 1C configuration.
Below is the code for the managed application module.
variable DemoComp; Procedure When System Starts() Connect External Component("...\bind\AddInNative.dll", "DemoVK", External Component Type.Native);
DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); EndProcedure
If no error was reported when starting the 1C configuration, then the VK was successfully connected. As a result of executing the above code, an object appears in the global visibility of the configuration DemoComp
, which has properties and methods that are defined in the code of the external component.
Demonstration of the built-in functionality
Let's check the functionality of the demo VK. To do this, let's try to set and read some properties, call some VK methods, and also receive and process the VK message.
  1. The documentation supplied on the ITS disk states the following functionality of the demo VC:
    Managing Component Object State Methods:, Turn on
    Switch off Properties:
  2. Included
    Timer management Every second the component sends a message to the 1C: Enterprise system with parameters, Component Timer
    Managing Component Object State and a system clock counter line., StartTimer
    Switch off StopTimer
  3. There is a Timer Method ShowInStatusLine
  4. There is a Timer , which displays in the status line the text passed to the method as parameters. Loads an image from the specified file and transfers it to the 1C: Enterprise system in the form of binary data.
and transmits it to the 1C: Enterprise system in the form of binary data.
variable DemoComp; Procedure When System Starts() ConnectExternalComponent(...);
DemoComp = New("AddIn.DemoVK.AddInNativeExtension");


DemoComp.Disable(); Report(DemoComp.Enabled); DemoComp.Enable(); Report(DemoComp.Enabled); DemoComp.StartTimer(); End of Procedure Procedure External Event Processing(Source, Event, Data) Report(Source + " " + Event + " " + Data); EndProcedure The result of running the configuration is shown in the image, The “Messages” panel displays the results of method calls DemoComp.Enable(); DemoComp.Disable() And

Demo.Comp.Enable()

. Subsequent lines in the same panel contain the results of processing messages received from VK -
Source Event Data Event respectively.
Custom external component name Task: Change the name of the external component to an arbitrary one. The previous section used the identifier
Here is the complete code of the method Task: Change the name of the external component to an arbitrary one. The VK code defines a method
RegisterExtensionAs
, returning the name to the 1C: Enterprise system, which is necessary for subsequent registration of the VK in the system. It is recommended to specify an identifier that to some extent reveals the essence of the external component. Let's give full code
method

with the extension name changed:

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, iActualSize) return false;
  1. In the example given, the VK name is changed to
  2. SomeName
  3. . Then when connecting VK you must specify a new name:

DemoComp = New("AddIn.DemoVK.SomeName");
Expanding the list of VK properties
Task:
Study the implementation of VK properties
Add a read/write property of string type
Add a read/write string property that stores the data type of the last property set. No action is taken when setting the property value
Returns the name of the property by its serial number and by the passed language identifier
GetPropVal
Returns the value of the property with the specified ordinal number
SetPropVal
Sets the value of the property with the specified ordinal number
IsPropReadable
Returns the readability flag of the property with the specified sequence number
IsPropWritable
Returns the writability flag of the property with the specified sequence number


Let's consider the implementation of the above class methods CAddInNative.
In the demo VC, 2 properties are defined: Properties: DemoComp.Enable(); StopTimer (IsEnabled DemoComp.Enable(); IsTimerPresent).
In the global scope of the library code, two arrays are defined:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent"); static wchar_t *g_PropNamesRu = (L"Enabled", L"There is a Timer");
which store Russian and English property names. In the header file AddInNative.h the enumeration is defined:
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropLast // Always last );
ePropIsEnabled DemoComp.Enable(); ePropIsTimerPresent, respectively having the values ​​0 and 1, are used to replace the serial numbers of properties with meaningful identifiers. ePropLast, which has a value of 2, is used to obtain the number of properties (using the GetNProps method). These names are used only within the component code and are not available from the outside.
The FindProp and GetPropName methods perform array searches g_PropNames DemoComp.Enable(); g_PropNamesRu.
To store the values ​​of the fields in the library module, the CAddInNative class has properties that store the value of the component properties. Methods GetPropVal DemoComp.Enable(); SetPropVal return and set the value of these properties accordingly.
Methods IsPropReadable DemoComp.Enable(); IsPropWritable and return true or false, depending on the passed ordinal number of the property in accordance with the application logic.
In order to add a custom property you need to:

  1. Add the name of the property being added to arrays g_PropNames DemoComp.Enable(); g_PropNamesRu(file AddInNative.cpp)
  2. To list Props(file AddInNative.h) before ePropLast add a name that uniquely identifies the property being added
  3. Organize memory for storing property values ​​(create module component fields that store the corresponding values)
  4. Make changes to methods GetPropVal DemoComp.Enable(); SetPropVal to interact with the memory allocated in the previous step
  5. In accordance with the application logic, make changes to the methods IsPropReadable DemoComp.Enable(); IsPropWritable
Points 1, 2, 5 do not need explanation. Details of the implementation of these steps can be found by studying the appendix to the article.
Let's give names to the test properties Test DemoComp.Enable(); Type Check respectively. Then, as a result of step 1, we have:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent", L"Test", L"TestType"); static wchar_t *g_PropNamesRu = (L"Enabled", L"There is a Timer", L"Test", L"Type Check");
Transfer Props will look like:
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropTest1, ePropTest2, ePropLast // Always last );
To significantly simplify the code, we will use STL C++. In particular, for working with strings WCHAR, let's connect the library wstring.
To save a method value Test, we define in the class CAddInNative in the scope of a private field:
string test1;
To transfer string parameters between 1C: Enterprise and external components, the 1C: Enterprise memory manager is used. Let's take a closer look at his work. The functions are used to allocate and free memory respectively AllocMemory DemoComp.Enable(); FreeMemory defined in the file ImemoryManager.h. If it is necessary to pass a string parameter to the 1C: Enterprise system, the external component must allocate memory for it by calling the function AllocMemory. Its prototype looks like this:
virtual bool ADDIN_API AllocMemory (void** pMemory, unsigned long ulCountByte) = 0;
Where pMemory- the address of the pointer into which the address of the allocated memory area will be placed,
ulCountByte- the size of the allocated memory area.
An example of memory allocation for a string:
WCHAR_T *t1 = NULL, *test = L"TEST_STRING"; int iActualSize = wcslen(test1)+1; m_iMemory->AllocMemory((void**)&t1, iActualSize * sizeof(WCHAR_T)); ::convToShortWchar(&t1, test1, iActualSize);
For convenience of working with string data types, we will describe the function wstring_to_p. It receives a wstring string as a parameter. The result of the function is a filled structure tVariant. Function code:
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(); return true)
Then the corresponding case section of the switch statement of the method GetPropVal will take the form:
case ePropTest1: wstring_to_p(test1, pvarPropVal);
break; SetPropVal:
Method
case ePropTest1: if (TV_VT(varPropVal) != VTYPE_PWSTR) return false; test1 = std::wstring((wchar_t*)(varPropVal -> pstrVal));
break;
To implement the second property, we define a class field
CaddInNative
Now, when requesting to read the value of the second property, we will return the value last_type, what the designated task requires.
Let's check the functionality of the changes made.
To do this, let us present the appearance of the 1C configuration as follows:
variable DemoComp; Procedure When System Starts() Connect External Component("...", "DemoVK", External Component Type.Native);
DemoComp = New("AddIn.DemoVK.SomeName");
3
DemoComp.TypeCheck = 1;
Report(String(DemoComp.TypeCheck));
22

DemoComp.Test = "Vasya"; Report(String(DemoComp.Test)); DemoComp.Test = "Petya";

Report(String(DemoComp.Test));

Task:
  1. Report(String(DemoComp.TypeCheck)); EndProcedure
  2. As a result of the launch, we will receive a sequence of messages:
  3. Vasya Peter The second and third messages are the result of reading the property set in the previous step. The first and second messages contain the type code of the last property set. 3 corresponds to an integer value, 22 to a string value. The correspondence of types and their codes is established in the file
  4. types.h

, which is located on the ITS disk.
Expanding the list of methods, Extend the functionality of the external component with the following functionality:, Explore ways to implement external component methods
Add a function method
Function1
, which takes two strings (“Parameter1” and “Parameter2”) as a parameter. The result is a string like: “Checking. Parameter1, Parameter2"
Make sure the changes you make work.
To define the methods of the component being created, the developer must implement the following methods in the AddInNative library code:
GetNMethods
FindMethod false GetMethodName
Designed to obtain the corresponding number of methods, search for the number and name of the method. Similar to the corresponding methods for properties
false GetNParams
Returns the number of method parameters with the specified sequence number; if a method with this number is absent or has no parameters, returns 0
GetParamDefValue false, a runtime error occurs and execution of the 1C: Enterprise module is terminated. Memory for the array of parameters is allocated by 1C: Enterprise. If the return value is a string or binary data type, the component allocates memory with the function AllocMemory memory manager, writes data there and stores this address in the corresponding field of the structure. 1C: The enterprise will free this memory by calling FreeMemory.
A complete description of the methods, including a list of parameters, is described in detail in the documentation supplied on the ITS disk.
Let's consider the implementation of the methods described above.
In the component code, two arrays are defined:
static wchar_t *g_MethodNames = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture"); static wchar_t *g_MethodNamesRu = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadImage");
and enumeration:
enum Methods ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethLast // Always last );
They are used in functions Expanding the list of methods, Extend the functionality of the external component with the following functionality: DemoComp.Enable(); Explore ways to implement external component methods, by analogy with the description of properties.
Methods Function1, Make sure the changes you make work., GetNMethods implement switch, depending on the passed parameters and application logic, return the required value. Method GetNMethods in its code it has a list of only methods that can return a result. For them he returns true. For all steel methods returns false.
Methods Designed to obtain the corresponding number of methods, search for the number and name of the method. Similar to the corresponding methods for properties DemoComp.Enable(); Returns the number of method parameters with the specified sequence number; if a method with this number is absent or has no parameters, returns 0 contain directly executable code of the method.
To add a method that can only be called as a function, you must make the following changes to the source code of the external component:
  1. Add method name to arrays g_MethodNames DemoComp.Enable(); g_MethodNamesRu(file AddInNative.cpp)
  2. Add a meaningful method identifier to the Methods enumeration (file AddInNative.h)
  3. Make changes to the function code Function1 according to program logic
  4. If necessary, make changes to the method code Make sure the changes you make work., if you want to use the default values ​​of the method parameters.
  5. Make changes to the function GetNMethods
  6. Make changes to the logic of functions Designed to obtain the corresponding number of methods, search for the number and name of the method. Similar to the corresponding methods for properties or Returns the number of method parameters with the specified sequence number; if a method with this number is absent or has no parameters, returns 0, placing the directly executable code of the method there
Let's present the arrays g_MethodNames DemoComp.Enable(); g_MethodNamesRu, as well as listing Methods to the form:
static wchar_t *g_MethodNames = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture", L"Test"); static wchar_t *g_MethodNamesRu = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture", L"Test");

Enum Methods ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethTest, eMethLast // Always last );
Let's edit the function Expanding the list of VK properties so that it returns the number of parameters of the “Test” method:
long CAddInNative::GetNParams(const long lMethodNum) ( switch(lMethodNum) ( case eMethShowInStatusLine: return 1; case eMethLoadPicture: return 1; case eMethTest: return 2; default: return 0; ) return 0; )
Let's make changes to the function:
bool CAddInNative::GetParamDefValue(const long lMethodNum, const long lParamNum, tVariant *pvarParamDefValue) ( ​​TV_VT(pvarParamDefValue)= VTYPE_EMPTY; switch(lMethodNum) ( case eMethEnable: case eMethDisable: case eMethShowInStatusLine: case eMethStartTimer : case eMethStopTimer: case eMethTest: / / There are no parameter values ​​by default break; default: return false;
Thanks to the added line
case eMethTest:
if one or more arguments are missing, the corresponding parameters will have an empty value ( VTYPE_EMPTY). If you need a default value for a parameter, you should set it in the section eMethTest function switch statement CAddInNative::GetParamDefValue.
Since the Test method can return a value, you need to make changes to the function code GetNMethods:
bool CAddInNative::HasRetVal(const long lMethodNum) ( switch(lMethodNum) ( case eMethLoadPicture: case eMethTest: return true; default: return false; ) return false; )
And add the executable code of the method to the function Returns the number of method parameters with the specified sequence number; if a method with this number is absent or has no parameters, returns 0:
bool CAddInNative::CallAsFunc(const long lMethodNum, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) ( ... std::wstring s1, s2; switch(lMethodNum) ( case eMethLoadPicture: ... break; case eMethTest: if (!lSizeArray || !paParams) return false; s1 = (paParams) -> pwstrVal; s2 = (paParams+1) -> pwstring_to_p(std::wstring(s1+s2), pvarRetValue); ; break ; return ret ;
Let's compile the component and bring the configuration code to the form:
variable DemoComp; Procedure When System Starts() Connect External Component("...", "DemoVK", External Component Type.Native);
DemoComp = New("AddIn.DemoVK.SomeName");

lane = DemoComp.Test("Hello," "World!");

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, iActualSize) return false;
  1. Report(per); EndProcedure
  2. After launching the configuration, we will receive the message: “Hello, World!”, which indicates that the method worked successfully.
  3. types.h

Timer Study the implementation of the timer in the demo VK. This message will be sent to your program at the time interval that you set when creating the timer.
To create a timer, use the function SetTimer:
UINT SetTimer(HWND hWnd, // window descriptor UINT nIDevent, // timer identifier (number) UINT nElapse, // delay TIMERPROC lpTimerFunc); // pointer to function
The operating system will send a message Study the implementation of the timer in the demo VK into the program with the interval specified in the argument nElapse(in milliseconds). In the last parameter you can specify a function that will be executed each time the timer fires. The header of this function should look like this (the name can be anything):
void __stdcall TimerProc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Let's consider the implementation of a timer in the demo VC.
Since we are considering the process of developing an external component for the Windows OS family, we will not consider the implementation of the timer in other operating systems. For GNU/Linux OS, in particular, the implementation will differ in the syntax of the function SetTimer DemoComp.Enable(); TimerProc.
The executable code calls the method SetTimer, to which the function is passed MyTimerProc:
m_uiTimer = ::SetTimer(NULL,0,100,(TIMERPROC)MyTimerProc);
The ID of the created timer is placed in a variable m_uiTimer so that it can be disabled later.
Function MyTimerProc as follows:
VOID CALLBACK MyTimerProc(HWND hwnd, // handle of window for timer messages UINT uMsg, // WM_TIMER message UINT idEvent, // timer identifier DWORD dwTime // current system time) ( if (!pAsyncEvent) return; wchar_t *who = L "ComponentNative", *what = L"Timer"; wchar_t *wstime = new wchar_t; if (wstime) ( wmemset(wstime, 0, TIME_LEN); ::_ultow(dwTime, wstime, 10); pAsyncEvent->ExternalEvent(who , what, wstime); delete wstime;
The essence of the function is that the method is called ExternalEvent, which sends a message to the 1C: Enterprise system.
To expand the functionality of the method and a system clock counter line. Let's do the following:
Modifying the method code Function1 so that it is for the method eMethStartTimer returned value 1:
case eMethStartTimer: return 1;
Here is the method code Designed to obtain the corresponding number of methods, search for the number and name of the method. Similar to the corresponding methods for properties to the form:
case 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;
Now let's check the functionality. To do this, we will write the code in the managed application module of the configuration:
variable DemoComp; Procedure When System Starts() Connect External Component("...", "DemoVK", External Component Type.Native);
After starting the configuration, the program will receive messages at intervals of 2 seconds, which indicates that the timer is working correctly.

Interaction with the 1C: Enterprise system

To interact between the external component and the 1C: Enterprise system, methods of the IAddInDefBase class, described in the file AddInDefBase.h. We list the most commonly used ones:
Generating an Error Message
virtual bool ADDIN_API AddError(unsigned short wcode, const WCHAR_T* source, const WCHAR_T* descr, long scode)
wcode, scode- error codes (a list of error codes with descriptions can be found on the ITS disk)
source- source of error
descr- error description
Sending a message to the 1C: Enterprise system
virtual bool ADDIN_API ExternalEvent(WCHAR_T* wszSource, WCHAR_T* wszMessage, WCHAR_T* wszData) = 0;
wszSource- message source
wszMessage- Message text
wszData- transmitted data
Message interception is carried out by the External Event Processing procedure
Registration of an external component in the 1C: Enterprise system
virtual bool ADDIN_API RegisterProfileAs(WCHAR_T* wszProfileName)
wszProfileName- component name.
These methods are sufficient for full interaction between VK and 1C. To receive data by an external component from the 1C: Enterprise system and vice versa, the external component sends a special message, which in turn is intercepted by the 1C system and, if necessary, calls the methods of the external component to transmit data back.

tVariant data type

When exchanging data between the external component and the 1C: Enterprise system, the tVariant data type is used. It is described in the types.h file, which can be found on the ITS disk:
struct _tVariant ( _ANONYMOUS_UNION 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 ; int32_t errCode; float fltVal; bVal; wchar_t wchVal; struct _tVal; struct tm tmVal; void* pInterfaceVal; __VARIANT_NAME_2/*iface*/; pstrVal; uint32_t strLen ; //count of bytes ) __VARIANT_NAME_3/*str*/; _ANONYMOUS_STRUCT struct ( WCHAR_T* pwstrVal; uint32_t wstrLen; //count of symbol ) __VARIANT_NAME_1; dimensional array in pvarVal TYPEVAR vt);
Type tVariant is a structure that includes:
  • mixture (union) intended directly for data storage
  • data type identifier
In general, working with variables of type tVariant occurs according to the following algorithm:
  1. Determining the type of data currently stored in a variable
  2. Access the corresponding mixture field to directly access the data
Using the type tVariant significantly simplifies the interaction of the 1C: Enterprise system and external components

Application

The “examples” directory contains examples for the article
examples/1 - launch the demo component
examples/2 - demonstration of property list expansion
examples/3 - demonstration of expanding the list of methods
Each directory contains a VS 2008 project and a ready-made 1C configuration.