This is a practical application from the previous article
.Net Core, 1C, dynamic compilation, Scripting API.In essence, this is a continuation of
.NET (C #) for 1C. Dynamic compilation of a wrapper class for using .Net events in 1C via the Add Processor or Processing an External Event , but for cross-platform .Net Core. But in that development I used CodeDom. In .Net Core it is more convenient to use Roslyn Scripting API.
At one time I did a hand wrapper for WhatsApp, and there are more than 30 events. At the same time, the whole process can be automated using code generation and, ultimately, this code can be dynamically compiled.
')
In
“Creating Components Using the Native API Technology” there is a method for invoking an external event in 1C ExternalEvent. Syntax:
bool ExternalEvent(WCHAR_T* wsSource, WCHAR_T* wsMessage, WCHAR_T* wsData)
Options:
• Type: WCHAR_T *. A string with the name of the event source.
• Type: WCHAR_T *. String with the name of the event.
• Type: WCHAR_T *. String with event parameters.
But as wsData we will pass a link to the object created from the event parameters.
So, let's begin.
First, create a class description using the example of my favorite System.IO.FileSystemWatcher, which in .Net Core is located in System.IO.FileSystem.Watcher
Pure 1C nicknames can miss the enemy code.
public class System_IO_FileSystemWatcher { Action<string,string,object> 1; System.IO.FileSystemWatcher ; public System_IO_FileSystemWatcher(Action<string,string,object> 1, System.IO.FileSystemWatcher ) { this.1 = 1; this. = ; .Changed += (sender,e) => { var Changed = new { sender=sender,e=e}; 1?.DynamicInvoke("System_IO_FileSystemWatcher","Changed",Changed); }; .Created += (sender,e) => { var Created = new { sender=sender,e=e}; 1?.DynamicInvoke("System_IO_FileSystemWatcher","Created",Created); }; .Deleted += (sender,e) => { var Deleted = new { sender=sender,e=e}; 1?.DynamicInvoke("System_IO_FileSystemWatcher","Deleted",Deleted); }; .Error += (sender,e) => { var Error = new { sender=sender,e=e}; 1?.DynamicInvoke("System_IO_FileSystemWatcher","Error",Error); }; .Renamed += (sender,e) => { var Renamed = new { sender=sender,e=e}; 1?.DynamicInvoke("System_IO_FileSystemWatcher","Renamed",Renamed); }; } public static object (Action<string,string,object> 1, System.IO.FileSystemWatcher ) { return new System_IO_FileSystemWatcher(1, ); } } return new Func<Action<string,string,object>,System.IO.FileSystemWatcher,object>(System_IO_FileSystemWatcher.);
Create a class, subscribe to events. In the event, we create an anonymous class from the parameters and call the method that ultimately calls the above function in 1C.
In order to cache the result of the compilation, create a class.
public class <T> { public static readonly Func<Action<string, string, object>, T, object> ; public static Func<Action<string, string, object>, T, object> () { Type = typeof(T); string = .FullName; var = "" + .Replace(".", "_").Replace("+", "_"); var = new (); string = .(); var scr = Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default; var = ..Keys.ToArray(); scr = scr.WithReferences() .WithImports("System"); var res = (Func<Action<string, string, object>, T, object>)Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.EvaluateAsync(, scr).Result; return res; } static () { = (); } }
Create a field:
public static readonly Func<Action<string, string, object>, T, object> ;
Which is initialized when creating a class in a static constructor. Compilation uses parameter type assemblies and the type of object to be wrapped. This approach is often used in the universal creation of serializers.
Now we can call the delegate to create a wrapper object for events like this.
public static void (string ,string , object ) {
We now turn to the code in 1C. To obtain the code in C # and 1C, we use external processing of Test Change Events in the Directory .epf.
( ) e=.e; e<> e=(e); ChangeType=(e.ChangeType); ( e.FullPath + " " + .(ChangeType.())); ;
Handler methods are formed by the name of the event that is called via
= (); ( + "()");
This approach reduces manual code writing. Well and creating tracking changes in the directory
() watcher<> watcher.EnableRaisingEvents = false; ; () (); Watcher=(.("System.IO.FileSystem.Watcher")); Watcher=(Watcher.GetType("System.IO.FileSystemWatcher")); NotifyFilters=(Watcher.GetType("System.IO.NotifyFilters")); =;
At the end you need to take care of the release of resources.
() watcher<> (); .(watcher.()); watcher=; =; GC=("System.GC"); GC.Collect(); GC.WaitForPendingFinalizers(); = ;
Now you can use not only the methods and properties of .Net objects, but also events. At the same time using only native for 1C ka programming language. And not a single line in the enemy language.
In conclusion, I want to share my bewilderment about the discussion of articles. All discussion comes down to Russlish and b.
I will raise problems when using the Native API in the
Cross-platform use of the .Net classes in 1C via Native VK. Or replacing COM with LinuxSo when you create a Native API, you can see the legs from IDispatch. But they used dispinterfaces to call only Invoke.
1. Absolutely no need for methods FindMethod, FindProp, GetNParams, HasRetVal, GetParamDefValue
(IsPropReadable, IsPropWritable for the debugger only). Since the bool CallAsProc, bool CallAsFunc, bool SetPropVal and bool GetPropVal methods have a return value on success. Error information is returned via AddError. And the call by index is an anachronism from IDiapatch where there was a description of the interfaces for increasing the speed of the call.
2. When returning with the SetPropVal and GetPropVal methods, an exception is not raised.
3. Why does the installation of properties occur, where it is not required in the code?
4. A method is called as a function, where the method is called as a procedure.
5. One of the main ones is that it is impossible to return and transfer a copy of the VK from the VK methods.
I personally do not see any problems. Determine the value for this type and set the link in the pInterfaceVal field.
The Native API has a structure
struct _tVariant { ..... _ANONYMOUS_STRUCT struct { void* pInterfaceVal; IID InterfaceID; } ...... TYPEVAR vt; };
In which you can use void * pInterfaceVal; IID InterfaceID. And in vt; indicate that it is VC. Recently, you can pass byte []. So you can go on.
Reference counting takes place on the 1C side. It is possible to transfer including 1C objects only for the duration of the method call. So when using IDispatch in 1C, there is no problem when passing IDispatch in the method parameters. Now the call rate of the VK method is almost 15 times slower than the call from C ++ only
public static bool CallAsFunc(int Target, IntPtr Ptr, IntPtr ReturnValue, IntPtr , int )
And 5 times slower than the similar 1C method. In this case, instead of one method, FindMethod, GetNParams, CallAsFunc is called. And if you call directly without VK, then the speed will be similar using internal methods.
Now when transferring to the VK method via the property of the method (Object.Property) or to the method by reference without any values. 1C tries to assign a value, even if this value has not changed. You can see the transfer of changed parameters in the VC.
Now on Windows there are many components on COM. Same ADO, Excel, and so on. You can easily create your COM library in any language.
Therefore, when polling why they do not use
Using .NET assemblies in 1C 7.xb 8.x. Creating External ComponentMost replies that they do not intend to use the product is unknown from whom. This situation is similar to that of the Nemerle. A language that is more powerful than C #, but behind which there are enthusiasts nobody needs. But at the same time, everyone agrees that if this component were integrated into 1C in the likeness of a ComObject, then everyone would use it.
As for cross-platform, .Net Core gives this opportunity. At the same time, this technology is now actively developing.
NET Core RoadmapAs I showed, you can use any .Net Core classes only in 1C language. You can use dynamic compilation of scripts or write your own assembly in C #, which is much easier than writing VK.
I know that there are many 1C developers on this site. And I have a big request for them to give advice on the development of this development. If 1C does not intend to change the Native API, then I will force the force to something else. Although this development took years and I really feel sorry for her. She is like a child.
I am ready to participate for free in a research project on the application of .Net Core in 1C. The main thing is that the forces were spent not in vain.
And the possibilities of cross-platform use of .Net Core in 1C are colossal. But I wonder why 1C is not needed? Here is the answer to this question I would like to hear. As for Linux, my questions are: what is missing compared to Windows, the main thing was
The main problem is to transfer clients to Linux. And here the main brake is the work with trading equipment. Bad deal with ready and reliable firewood under the Native API under any different. A high-level canoe somehow does not hold too much. Technically, anyway.
At one time, working with the Trade Equipment, there were necessarily a SDK on C #. Even under WiCE. Many were interop wrappers over native libraries. With the advent of .Net Core will do under NetStandart. And on Linux will be more fun.
Sources and examples can be downloaded
here.