DZWON

Są tacy, którzy czytają tę wiadomość przed tobą.
Subskrybuj, aby otrzymywać najnowsze artykuły.
E-mail
Nazwa
Nazwisko
Jak chciałbyś przeczytać The Bell?
Bez spamu

Pytanie: Zewnętrzny natywny komponent Api w C++ dla Linuksa (Ubuntu x64) na 1C 8.3


Piszę VK, nie mogę połączyć się z 1s na ubuntu. Nawet exapl z 1s nie jest podłączony. Więc pytanie o to:

1) Próbuję podłączyć VK z przykładu VNCOMPS podanego w artykule

(link znajduje się na samym końcu: „Kopiowanie”).
Wewnętrznie projekt NativeApi ma plik makefile. Dzięki niemu buduję bibliotekę .so na Ununtu.
Ale przy "Podłącz komponent zewnętrzny" 1 startuje.
Podobnie, jeśli buduję za pomocą "build.sh" (w katalogu głównym projektu).

W samym makefile zmieniam flagę z m32 na m64, bo 1c i sam system x64. (z parametrem m32 i tak nie odbiera)
Oto przykład wywołania VK z 1C 8.3:
Połączenie wykonane = Podłącz zewnętrzny komponent(„/home/alexeyubuntux64-20 gb/Documents/VNCOMP83/przykład/NativeAPI/AddInNative.so”, „AddInNative”, ExternalComponentType.Native); Jest artykuł właśnie na ten temat.
Ale, o ile widzę, wszystkie te punkty zostały już uwzględnione i poprawione w przykładzie VNCOMPS.

Ale tak naprawdę biznes w parametrach kompilacji. Zewnętrzny komponent MB 32bit łączy się normalnie z 32bit 1c, ale wdrożyłem na Ubuntu x64 1c enterprise83 8.3.5-1486 amd64. I chcę jej odebrać VK.

Czy ktoś ma jakiś pomysł jak rozwiązać ten problem?
Przykład VNCOMPS powinien działać, ale parametry kompilacji muszą zostać poprawione lub sama platforma, na której testuję, jest niepoprawna.

Odpowiadać: Co ciekawe, czy można napisać zewnętrzny komponent w Javie?

Pytanie: Komponent zewnętrzny (natywny) nie jest podłączony


Opracowałem przykład z ITS, dla systemów 64 i 32-bitowych.

Łączę się tak:
ConnectionResult = ConnectExternalComponent(CDLLPath, "Comp", ExternalComponentType.Native); Jeden komputer się łączy, drugi nie. Jest różnica w systemie operacyjnym. Tam, gdzie idzie połączenie, jest Win7, gdzie nie ma Win10. W tym samym czasie standardowe komponenty działają na komputerze, na którym mój komponent nie działa.

Testowane na różnych platformach (8.3.4.482, 8.3.6.2100, 8.3.11.2700, 8.3.12.1412).

Jak zrozumieć, dlaczego się nie łączy?

Odpowiadać: vc_redist nie zapomniał?

Pytanie: 1C8 i komponent zewnętrzny z typem Native


Dzień dobry.
Istnieje konfiguracja BP 3.0.50.12 i chęć wdrożenia ważenia firmy Scales-Soft przy użyciu UniServerAuto.
Deweloperzy skompilowali składnik Native dla Windows 32 i 64 i umieścili go w archiwum z plikiem maifest. Jest też przykład dla 1C, jak można obliczyć wagę. W nim, za pomocą układu z danymi binarnymi, wskazane jest to archiwum, jak rozumiem. W tym przykładzie wszystko jest w porządku: komponent jest zainstalowany, podłączony, następnie połączenie jest nawiązywane i odczytywana jest waga.
Ale jak tylko zaczniesz przenosić się na 1C, waga nie jest odczytywana. Wygląda na to, że wszystko jest po prostu napisane, ale nie rozumiem, gdzie jest prowizja.
Kto będzie miał trochę czasu - pomóż, spójrz jednym okiem, może rozwiązanie jest na powierzchni, ale idę gdzieś w złym miejscu i robię coś złego. Nigdy wcześniej nie pracowałem z technologią natywną...

A w załączniku jest mój tekst do przetwarzania

Odpowiadać:

Cóż, mam kilka wieści...
Właśnie zacząłem przyglądać się krok po kroku, w którym momencie zaczyna zawodzić. Aby to zrobić, utworzyłem pustą bazę danych i przetwarzanie za pomocą polecenia. Analogicznie do przykładu dostawcy przeniosłem layout do nowego konfi - działa drugi raz. Tych. Pierwszy raz nie, drugi raz tak. To zrodziło pomysł, że w jego przetwarzaniu nadal konieczne będzie rozdzielenie połączenia komponentu i obiektu według różnych procedur.
Następnie przeniosłem go do mojej bazy danych z połączeniem układu - działa. Fuh, już jest dobrze.... Ale chciałbym to bez wprowadzania zmian w konfiguracji, więc przejdźmy dalej

Próbuję dodać układ do przetwarzania. Jego rozmiar od razu wzrasta z 10kb do 3mb i zauważalne jest znaczne spowolnienie - nie pasuje. Zaczynam kopać w kierunku podłączenia komponentu przez bibliotekę dll. Tych. w zasadzie taki sam, jak tam, gdzie zacząłeś. Ale jest jedno „ALE”: wyszukując nazwę biblioteki dll w folderze użytkownika, zauważyłem, że ta biblioteka dll leży tam, gdzie (jak rozumiem) dodawane są biblioteki dll zarejestrowane w 1C:
C:\Użytkownicy\UŻYTKOWNIK\AppData\Roaming\1C\1cv8\ExtCompT
w związku z tym nie ma potrzeby używania pełnej ścieżki do biblioteki dll, wystarczy wpisać jej nazwę:
ConnectExternalComponent("Add1CUniServerAuto32.dll", "UniServerAuto", ExternalComponentType.Native);

Próbuję... przeklina przy rejestracji, ale zwraca wynik ważenia. Okazuje się, że biblioteka dll jest już zarejestrowana, co oznacza, że ​​wystarczy ją podłączyć. Usuwam i wszystko działa.
Podsumowując:
1. W przetwarzaniu ważenia w procedurze Przy otwieraniu dodałem połączenie elementu zewnętrznego oraz połączenie z obiektem.
2. Ścieżka do dll nie napisałem, tylko wskazałem jej nazwę.

Teraz siedzę i myślę, kiedy dll zainstalował się w 1C? W momencie instalacji oprogramowania? Prawie... W momencie uruchamiania konfiguracji deweloperskiej tej biblioteki dll, gdzie jest ona ustawiana po otwarciu formularza? Nie wiem, ale wydaje mi się bliskie... Co o tym myślisz?
A po drugie, w nowym miejscu, gdy trzeba zainstalować ten sam terminal, co trzeba zrobić, żeby wszystko działało? Zainstaluj oprogramowanie całkowicie, uruchom config dostawcy, aby sprawdzić pracę, a następnie (teoretycznie) moje przetwarzanie powinno działać? Coś trochę skomplikowanego... Lub po zainstalowaniu oprogramowania w moim przetwarzaniu, czy raz InstallExternalComponent?

Chciałbym usłyszeć twoje przemyślenia na ten temat...

Pytanie: Zewnętrzny plik component.dll


Dzień dobry wszystkim.
Pytanie.
składnik dll, który działa dobrze w 1C 7.7
w 1s 8.1 w ogóle nie chce się uruchamiać ...
Wypróbowałem i wklej go w C:\Program Files\1cv81\bin\cache1c.dll
Próbowałem zarejestrować się za pomocą regsvr32 "C:\Program Files\1cv81\bin\cache1c.dll"
Zarejestrowany bez problemów.
Gdy próbuję uzyskać do niego dostęp, otrzymuję komunikat o błędzie:

Błąd podczas ładowania komponentu zewnętrznego! cache1c.dll
Procedura Wykonaj PrzyciskKliknij(Przycisk) Próba Załadowania Komponentu Zewnętrznego( „C:\Program Files\1cv81\bin\cache1c.dll”); Raport wyjątków ( "Błąd podczas ładowania komponentu zewnętrznego!"+ "cache1c.dll"); Koniec próby; Próba // Pobranie obiektu komponentu. // m = Nowy ("cache1c.GTMcmd" ); m = Nowy COMObject("cache1c.GTMcmd" ); Raport wyjątków(); Koniec próby; Koniec procedury

Odpowiadać: Banalne aż do niemożliwości...
Konieczne jest utrzymywanie przerw między połączeniami (milisekundy)...
Procedura ButtonExecuteClick(Button) Próba // Pobierz obiekt komponentu. m = Nowy COMObject("cache1c.GTMcmd" ); Raport wyjątków ( „Nie można utworzyć obiektu komponentu zewnętrznego”); Koniec próby; m.RemoteHost = "192.168.1.101" ; m.Port zdalny = 6330; m.Połącz(); m.pauza(100); ...... itd
Za 1s 7,7 - nie jest to konieczne, okazuje się, że krążenie jest szybsze.

Pytanie: Praca zewnętrznego komponentu z serwerem 1C ...


Dzień dobry,

Istnieje zewnętrzny komponent napisany w C ++, którego zadaniem jest odbieranie informacji z zewnętrznej bazy danych i zwracanie wyniku zapytania w postaci tabeli wartości w 1C.
Do utworzenia tabeli wartości w chwili obecnej wykorzystywany jest interfejs IDispatch* pBackConnection, który jest odbierany jako parametr w funkcji Init(). Dalej, po prostu, używając funkcji 1C, tworzę tabelę wartości, wypełniam ją i zwracam do drugiego parametru w CallAsFunc (...).
Problemy zaczęły się wraz z przejściem na cienkie klienty 1C. Po stronie serwera komponent zewnętrzny tak naprawdę się nie uruchamia. Możesz go uruchomić po stronie klienta, ale wszystko wygląda jak kule i wypada z ogólnej logiki „klient-serwer” w 1C. Na przykład klient nie rozumie, czym jest tabela wartości, problemy ze zmiennymi „globalnymi”, sesjami itp.
NativeAPI jest pod tym względem jeszcze bardziej okrojony.
Taniec z tamburynem spowodował, że udało mi się uruchomić zewnętrzny komponent pod serwerem 1C, ALE praca toczy się do momentu próby wywołania Invoke na pBackConnection. 64-bitowa wersja serwera 8.2 próbuje coś zrobić, dopóki nie spadnie limit czasu, wersja 32-bitowa (VK jest oczywiście również 32-bitowa) po prostu odpada.
Zakładam, że serwer 1C nie obsługuje tego trybu działania.
W związku z tym pojawiają się pytania, czy jest to tymczasowe, czy logika 1C sprowadza się do zniesienia tego schematu pracy? Jeśli niemożliwe jest stworzenie w ten sposób wewnętrznych struktur 1C (tablicy wartości), czy w zasadzie istnieje opis tego, czym jest tabela wartości na poziomie systemu, aby spróbować stworzyć ją w C + +, wypełnij go, a następnie po prostu prześlij 1C jako parametr zwrotny? Chciałbym przynajmniej dowiedzieć się, w którym kierunku kopać.

Dziękuję Ci.

Odpowiadać:

Piszesz jedno, a masz na myśli coś innego.
W środowisku 1C deklarowanie zmiennych, które będą widoczne w różnych sesjach, nie jest teraz niemożliwe, a wcześniej nie było to możliwe. Inna sesja to fizycznie inny proces.
Sesja to sesja połączenia z bazą danych, tj. sesja użytkownika. A może umieszczasz coś własnego i tej koncepcji?

W ramach jednej sesji można było, a teraz można, zadeklarować w module sesji zmienne, które będą żyły i będą widoczne w ramach sesji z różnych miejsc… właściwie jest ich 4.
- Moduł sesji;
- Regularny moduł aplikacji;
- Zarządzany moduł aplikacji;
- Zewnętrzny moduł połączeniowy.

I oczywiście trzeba pamiętać o kontekście. Kontekst serwera nie jest bezpośrednio dostępny po stronie klienta i odwrotnie.

Ogólnie architektura 1C zapewnia, że ​​wymiana danych będzie przebiegać:
- za pomocą parametrów/zwrotów procedur/funkcji;
- za pomocą tzw. parametrów sesji (nie mogą to być obiekty, faktycznie widać to w palecie).

Tabela na formularzu... i jest połączona z dowolną tabelą obiektów (np. przetwarzania)? albo nie. Jeśli tak, to jest również dostępny na serwerze (&AtServer) i tam edytuj....

I tak, ValueTable nie jest dostępne w UV po stronie klienta. Cóż, tak zdecydował 1C.

Daj spokój! Tutaj działa z Excelem, działa z FSO i wieloma innymi, ale tutaj nie działa. Złap błąd i przeanalizuj....

Próba
...
Twoje działania
...
Wyjątek
str = OpisBłąd();
Koniec próby;

Przy nowoczesnych możliwościach sprzętowych to wcale nie jest argument.

Czysto twoja osobista opinia. Nie ma nic wspólnego z rzeczywistością. W żaden sposób. Powtarzam jeszcze raz, 1C świetnie współpracuje z COM. Zarówno z in-proc, jak i out-proc.

Podaj kod, który przesyłasz i stosujesz do VK.

Swoją drogą, VK... w twoim przypadku to COM czy Native API?
Jeśli COM, to rejestrujesz go jako... przez regsvr32... to jak "rozwiązać" problem z głębią bitową?

Pytanie: Instalowanie zewnętrznego komponentu


Proszę mi powiedzieć, jak zainstalować zewnętrzny komponent. Podczas wykonywania poniższego kodu zgłaszany jest błąd. Znajdź NameDecl.dll w układzie

Próba SetExternalComponent("GeneralLayout.Layout"); Wyjątek EndTry ;
Błąd: Instalacja wtyczki nie powiodła się!

Odpowiadać: ()
ConnectExternalComponent("GeneralLayout.Layout", "NameDecl", ExternalComponentType.Native) zwraca FALSE ,
New("AddIn.NameDecl.CNameDecl", Undefined) = (()): Typ niezdefiniowany (AddIn.NameDecl.NameDecl)

Pytanie: Natywna biblioteka dll nie jest podłączona do 1s 8.1 (fptrwin32_fz54_9_11_0_5549.dll)


Cześć.
1C zaktualizował bibliotekę dll dla atolu kas fiskalnych online do fdd 1.05 (zawarta w przetwarzaniu konserwacji fptrwin32_fz54_9_11_0_5549.dll).
Mam stary 1C 8.1. W przeciwieństwie do 8.2 nie obsługuje pracy ze sprzętem zewnętrznym w taki sam sposób jak 8.2, więc najpierw musisz zarejestrować bibliotekę dll w systemie Windows, a następnie podłączyć ją tylko do 1C?

ProgID = "AddIn.IntegrationComponent.ATOL_KKT_1C83_V9"; LoadExternalComponent("C:\fptrwin32_fz54_9_11_0_5549.dll"); ConnectExternalComponent (ProgID); Sterownik = Nowy(ProgID);

Jednak stare przetwarzanie zostało napisane w "technology" com, a nowe natywne. W związku z tym podczas rejestracji regsvr32 wyświetla błąd:
Moduł został załadowany, ale nie znaleziono punktu wejścia DllRegisterServer. I sugeruje sprawdzenie, czy ten plik jest poprawnym plikiem dll lub OCX.
Kto stanął w podobnej sytuacji, jak się wydostałeś? Rozumiem, że podobny problem będzie w 7.7.
Kod 8.2:

Układ = GetLayout("IntegrationComponent"); Adres = PlaceInTempStorage(Układ); ConnectExternalComponent(Adres, "IntegrationComponent", ExternalComponentType.Native); Driver = New("AddIn.IntegrationComponent.ATOL_KKT_1C83_V9");

1C 8.2:
Podłącz komponent zewnętrzny (<Местоположение>, <Имя>, <Тип>)
1C 8.1:
Podłącz komponent zewnętrzny (<Идентификатор объекта>)
Opcje:
<Идентификатор объекта>(wymagany)
Typ: ciąg. ProgID (identyfikator programowy) obiektu komponentu zewnętrznego. Musi być zgodny z informacjami w bazie danych rejestracji systemu (Rejestr).
Opis:
Łączy obiekty komponentów zewnętrznych z 1C:Enterprise.
Niedostępne na serwerze 1C:Enterprise. Nie używany w zewnętrznym module połączeniowym.
Notatka:
Komponenty zewnętrzne są kompatybilne z komponentami 1C:Enterprise 7.7.
Przykład:
Próba
ConnectExternalComponent("AddinObject.Scanner");
alert("Załadowano komponent skanera kodów kreskowych");
Wyjątek
alert("Komponent skanera kodów kreskowych nie został załadowany");
Próby zakończenia

Czy jest jakiś sposób na podłączenie tej dll do 8.1, czy nie?

Dziękuję Ci!

Odpowiadać:

Ja też ostatnio miałem ten problem. Nie można było przekonwertować na nowszą wersję 1s. dll z którym działa ta konfiguracja po prostu przestała działać i wypadł 1c z błędem.
Problem został rozwiązany w następujący sposób:
Stworzyłem pustą bazę danych 8.3, w której dokonałem inicjalizacji komponentu, a następnie od wersji 8.1 poprzez połączenie COM uzyskałem dostęp do utworzonej wcześniej bazy danych i tam zainicjalizowałem komponent. Następnie, już w 8.1, wywołałem metody tego komponentu.
Oczywiście jest to kula, ale nie znalazłem jeszcze innego wyjścia (

Przykład kodu 8.3:
Eksport sterowników Rem;
Funkcja PołączenieKomponentyCCP() Eksport
Próba

Układ = GetLayout("IntegrationComponent");
Adres = PlaceInTempStorage(Układ);
ConnectExternalComponent(Adres, "IntegrationComponent", ExternalComponentType.Native);
Driver = New("AddIn.IntegrationComponent.SMDrvFR1C20");
wynik = prawda;​

Wyjątek

wynik = fałsz;​

Koniec próby;
Zwróć wynik
Funkcje końcowe

Przykład kodu 8.1

Funkcja CreateDriverObject(sterownik) Export

wynik = prawda;

Próba

ConnectionString="Plik="""Ścieżka do bazy danych""";
ComObject= Nowy COMObject("V83.ComConnector");
Połącz = ComObject.Połącz(StringPołączenia);

Przetwarzanie = Connect.Processing.ConnectingExternalComponent.Create();
ConnectionResult = Processing.ConnectingKKT Components();
Jeśli wynik się zgadza, to
Sterownik = Przetwarzanie.Sterownik;
EndIf;​

Wyjątek
Wszystkim, którzy to zrobili lub doświadczyli podobnych problemów, prosimy o wyjaśnienie. prosty przykład sama zasada. Wydaje się, że wszystko jest jasne z podłączeniem komponentów zewnętrznych.

// Przykład wypełnienia tabeli wartości TK.Wyczyść(); Żądanie = Nowe żądanie; Query.Text = "WYBIERZ | Nomenklatura Link JAK Nomenklatura | OD | Directory.Nomenclature AS Nomenclature"; QueryResult = Query.Execute(); Sampling = QueryResult.Select(); While Sampling.Next() Loop Str = TK.Add(); FillPropertyValues(Pr, Sampling); EndCycle;
Czy mógłbyś wyjaśnić na tym przykładzie, jaka część kodu jest zwykle usuwana. Logiczne byłoby wyjęcie części z żądaniem, ale w jaki sposób możemy uzyskać dostęp do bazy danych z komponentu zewnętrznego z komponentu zewnętrznego, z pominięciem platformy? Tekst nie ma sensu. Lub wyjmij samą formację części tabelarycznej. Podziel się z tym swoim doświadczeniem.

Odpowiadać: I że słowo „Niezgodny” zawsze oznacza słowo „Zły”? Tak, wydaje mi się, że jeśli nazwać swój styl „1C: Najgorsze programowanie na tym silniku skryptowym, jakie istnieje w naturze (przetłumaczone na język literacki)!” i wtedy na pewno znajdą się tacy, którzy będą chcieli sprawdzić tę bestię. I wygląda jak klasyk: „Nie czytałem Pasternaka, ale kompletnie się z nim nie zgadzam!” :)

Pytanie: Podłączanie zewnętrznego komponentu w 1s 8.3.6 i Win8


Niezbędne jest podłączenie zewnętrznego komponentu vk_rs232.dll do własnej konfiguracji. Jak zarejestrowany przez regsvr32.exe. „Wygląda na to”, ponieważ otrzymałem komunikat, że „składnik jest zarejestrowany, ale coś jest nie tak z zaporą sieciową”. Opierając się na pierwszej połowie wiadomości, piszę kod w 1s
AfterConnection = New NotificationDescription("AfterConnectionVK",ThisForm); StartExternalComponentInstallation(,"C:\Controller\vk_rs232.dll"); StartConnectingExternalComponent(Po połączeniu,"C:\Controller\vk_rs232.dll","DLL_Scales");
i otrzymuję błąd, że
"Instalacja komponentu zewnętrznego nie powiodła się! Może brakować komponentu dla używanej aplikacji klienckiej!".

A teraz nie rozumiem
1. Może składnik nie jest zarejestrowany w rejestrze - jak mogę to tam sprawdzić?
2. Może jego „wersja” nie działa pod Win8, chociaż mam ją 32-bitową.
3. Może samo 1s jest za nowe, tj. w związku z tym nie może pracować z tym dll?
4. No to banalne - coś źle piszę.

Odpowiadać: I to wszystko doprowadziło mnie do kolejnego problemu. Zainstalowany VneshComp, teraz musisz go podłączyć. A oto obie opcje.
ConnectExternalComponent("C:\Controller\vk_rs232.dll", "Wagi")
ConnectExternalComponent("GeneralLayout.Layout","Skale")

Opcja składni: Według nazwy i lokalizacji

Składnia:

Podłącz komponent zewnętrzny (<Местоположение>, <Имя>, <Тип>)
Opcje:

<Местоположение>(wymagany)

Typ: ciąg.
Lokalizacja komponentu zewnętrznego.
Lokalizacja może być używana:
ścieżka do pliku komponentu zewnętrznego w systemie plików (niedostępna w kliencie sieciowym), a nie archiwum ZIP;
pełne imię i nazwisko układ przechowujący dane binarne lub archiwum ZIP;
Adres URL komponentu zewnętrznego w postaci danych binarnych lub archiwum ZIP w formacie , podobnym do GetNaviLink.
<Имя>(wymagany)

Typ: ciąg.
Symboliczna nazwa podłączanego komponentu zewnętrznego.
Nazwa musi być zgodna z konwencjami nazewnictwa języka wbudowanego.
<Тип>(opcjonalny)

Typ: Typ komponentu zewnętrznego.
Typ podłączanego komponentu zewnętrznego.
Nie używane, jeśli komponent jest spakowany w archiwum ZIP.
Opis wariantu metody:

Łączy komponenty wykonane w technologii Native i COM.
Komponent może być przechowywany w infobazie lub układzie konfiguracyjnym jako dane binarne lub w archiwum ZIP.
W przypadku trybów uruchamiania „Cienki klient” i „Klient sieci Web” składnik musi być wcześniej zainstalowany przy użyciu metody Zainstaluj komponent zewnętrzny.
Opcja składni: Według ID

Składnia:

Podłącz komponent zewnętrzny (<ИдентификаторОбъекта>)
Opcje:

<ИдентификаторОбъекта>(wymagany)

Typ: ciąg.
Identyfikator obiektu komponentu zewnętrznego w postaci ProgID (Programmatic Identifier) ​​rejestru MS Windows (na przykład: „AddIn.Scanner”).
Musi być zgodny z informacjami w bazie danych rejestracji systemu (Rejestr).
Opis wariantu metody:

Komponent musi być zaimplementowany w technologii COM i zarejestrowany w rejestrze MS Windows.
Te komponenty są kompatybilne z komponentami 1C:Enterprise 7.7.
Uwaga! Wariant metody nie działa na serwerze iw połączeniu zewnętrznym.
Wartość zwrotu:

Typ: logiczny.
Prawda - połączenie powiodło się.
Opis:

Łączy komponent zewnętrzny z 1C:Enterprise.
Komponenty zewnętrzne mogą być przechowywane w infobazie lub układach konfiguracyjnych jako archiwum ZIP lub jako dane binarne lub w pliku systemu plików.
Podczas pracy na cienkim kliencie i kliencie sieciowym składnik musi być wstępnie zainstalowany.

Dostępność:

Cienki klient, klient sieciowy, serwer, połączenie zewnętrzne.
Notatka:

Komponenty zewnętrzne można zaimplementować przy użyciu technologii Native API lub COM. Komponenty wykonane w technologii COM są kompatybilne z komponentami 1C:Enterprise 7.7.
Klient sieciowy może pracować tylko z komponentami w infobazie, które są spakowane do archiwum.
Cienki klient może pracować z komponentami w infobazie, spakowanymi w archiwum, oraz komponentami znajdującymi się w systemie plików.
Gruby klient może pracować ze wszystkimi opcjami przechowywania komponentów. W takim przypadku, jeśli składnik jest instalowany przy użyciu metody InstallExternalComponent, wówczas używany jest zainstalowany składnik, a jeśli nie jest zainstalowany, składnik zostanie odebrany w momencie połączenia.
Serwer może współpracować ze wszystkimi komponentami. Składnik jest buforowany na potrzeby sesji serwera.
Przykład:

Jeśli ConnectExternalComponent("AddinObject.Scanner") Wtedy
alert("Załadowano komponent skanera kodów kreskowych");
W przeciwnym razie
alert("Komponent skanera kodów kreskowych nie został załadowany");
EndIf;

  • instruktaż

Wstęp

Ten artykuł daje wyobrażenie o działaniu komponentów zewnętrznych w systemie 1C:Enterprise.
Zostanie pokazany proces opracowywania zewnętrznego komponentu dla systemu 1C:Enterprise w wersji 8.2 działającego w systemie operacyjnym Windows z wersją pliku pracy. Ta opcja jest używana w większości rozwiązań przeznaczonych dla małych firm. VC zostanie zaimplementowany w języku programowania C++.

Komponenty zewnętrzne „1C: Enterprise”

„1C: Enterprise” to system rozszerzalny. Do ekspansji funkcjonalność system wykorzystuje komponenty zewnętrzne (VC). Z punktu widzenia programisty VC to obiekt zewnętrzny, który ma właściwości i metody, a także może generować zdarzenia do przetworzenia przez system 1C:Enterprise.
Komponenty zewnętrzne można wykorzystać do rozwiązania klasy zadań, które są trudne lub nawet niemożliwe do zrealizowania za pomocą języka programowania wbudowanego w 1C: Enterprise. W szczególności ta klasa obejmuje zadania, które wymagają interakcji niskiego poziomu z systemem operacyjnym, na przykład do pracy z określonym sprzętem.
System 1C:Enterprise wykorzystuje dwie technologie do tworzenia komponentów zewnętrznych:
  • przy użyciu natywnego API
  • przy użyciu technologii COM
Biorąc pod uwagę ograniczenia między dwiema powyższymi technologiami, różnica jest nieznaczna, dlatego rozważymy rozwój VK przy użyciu Native API. W razie potrzeby wdrożone opracowania można zastosować do rozwoju VC przy użyciu technologii COM, a także, z niewielkimi modyfikacjami, zastosować do użytku w systemie 1C: Enterprise z innymi opcjami operacyjnymi niż tryb pracy z plikami.
Struktura VK
Zewnętrzny składnik systemu 1C:Enterprise jest prezentowany jako biblioteka DLL. Kod biblioteki opisuje klasę pochodną IComponentBase. W tworzonej klasie należy zdefiniować metody odpowiedzialne za implementację funkcji komponentu zewnętrznego. Pominięte metody zostaną szczegółowo opisane w dalszej części prezentacji materiału.

Uruchomienie demo VK

Zadanie:
  1. Złóż komponent zewnętrzny dostarczony z subskrypcją ITS i zaprojektowany w celu zademonstrowania głównych możliwości mechanizmu komponentu zewnętrznego w 1C
  2. Podłącz komponent demonstracyjny do konfiguracji 1C
  3. Upewnij się, że zadeklarowane funkcje działają poprawnie
Kompilacja
Demo VC znajduje się na dysku subskrypcji ITS w katalogu "/VNCOMP82/example/NativeAPI".
Do złożenia demonstracyjnej wersji VK użyjemy programu Microsoft Visual Studio 2008. Inne wersje tego produktu nie obsługują używanego formatu projektu Visual Studio.


Otwórz projekt AddInNative. W ustawieniach projektu łączymy katalog z plikami nagłówkowymi niezbędnymi do zbudowania projektu. Domyślnie znajdują się na dysku ITS w katalogu /VNCOMP82/zawiera.
Wynikiem kompilacji jest plik /bind/AddInNative.dll. To jest skompilowana biblioteka do łączenia się z konfiguracją 1C.
Podłączanie konfiguracji VK do 1C
Stwórzmy pustą konfigurację 1C.
Poniżej znajduje się kod modułu aplikacji zarządzanej.
var DemoComp; Procedura SystemStartup() ConnectExternalComponent("...\bind\AddInNative.dll", "DemoVK", ExternalComponentType.Native); DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); Koniec procedury
Jeśli podczas uruchamiania konfiguracji 1C nie zgłoszono żadnego błędu, oznacza to, że VK został pomyślnie podłączony.
W wyniku wykonania powyższego kodu w globalnej widoczności konfiguracji pojawia się obiekt DemoComp Posiada właściwości i metody zdefiniowane w kodzie komponentu bean zewnętrznego.
Demonstracja wbudowanej funkcjonalności
Sprawdźmy wydajność demo VK. Aby to zrobić, spróbujmy ustawić i odczytać niektóre właściwości, wywołać niektóre metody VK, a także odebrać i przetworzyć wiadomość VK.
Dokumentacja dostarczona na dysku ITS określa następującą funkcjonalność demo VC:
  1. Zarządzanie stanem obiektów składowych
    Metody: Włączyć, Wyłączyć
    Nieruchomości: Dołączony
  2. Sterowanie czasowe
    Co sekundę komponent wysyła wiadomość do systemu 1C: Enterprise z parametrami Składnik, regulator czasowy oraz ciąg licznika zegara systemowego.
    Metody: StartTimer, StopTimer
    Nieruchomości: Jest zegar
  3. metoda PokażInStatusLine, który wyświetla w pasku stanu tekst przekazany do metody jako parametry
  4. metoda Załaduj obrazek. Ładuje obraz z określonego pliku i przesyła go do systemu 1C:Enterprise jako dane binarne.
Upewnijmy się, że te funkcje działają. W tym celu wykonamy następujący kod:
var DemoComp; SystemStart() Procedura ConnectExternalComponent(...); DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); DemoComp.Disable(); Powiadom (Komp. Demo włączone); DemoComp.Enable(); Powiadom (Komp. Demo włączone); DemoComp.StartTimer(); EndProcedure ProcedureExternalEventHandler(Źródło, Zdarzenie, Dane) Report(Źródło + " " + Zdarzenie + " " + Dane); Koniec procedury
Wynik uruchomienia konfiguracji jest pokazany na obrazku


Wyniki wywołań metod są wyświetlane w panelu „Wiadomości” DemoComp.Disable() oraz Demo.Comp.Enable(). Kolejne wiersze na tym samym panelu zawierają wyniki przetwarzania wiadomości otrzymanych z VK - Źródło, Wydarzenie oraz Dane odpowiednio.

Dowolna nazwa komponentu zewnętrznego

Zadanie: Zmień nazwę komponentu zewnętrznego na dowolną.
W poprzedniej sekcji użyto identyfikatora AddInNativeExtension, którego znaczenie nie zostało wyjaśnione. W tym przypadku AddInNativeExtension to nazwa rozszerzenia.
Kod VC definiuje metodę Zarejestruj rozszerzenie jako, który zwraca nazwę do systemu 1C: Enterprise, który jest niezbędny do późniejszej rejestracji VC w systemie. Zaleca się podanie identyfikatora, który w pewnym stopniu odsłania istotę komponentu zewnętrznego.
Oto pełny kod metody Zarejestruj rozszerzenie jako ze zmienioną nazwą rozszerzenia:
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- ((void**)wsExtensionName, iActualSize * sizeof(WCHAR_T))) ::convToShortWchar(wsExtensionName, wsExtension, iActualSize); return true; ) return false; )
W powyższym przykładzie nazwa VK została zmieniona na Niektóre nazwy. Następnie, łącząc VK, musisz podać nową nazwę:
DemoComp = New("AddIn.DemoVK.SomeName");

Rozszerzenie listy nieruchomości VK

Zadanie:
  1. Przestudiuj wdrożenie właściwości VC
  2. Dodaj właściwość do odczytu i zapisu typu string
  3. Dodaj właściwość typu ciągu do odczytu/zapisu, która przechowuje typ danych ostatniego zestawu właściwości. Podczas ustawiania wartości właściwości nie są podejmowane żadne działania

Aby zdefiniować właściwości tworzonego komponentu, programista musi zaimplementować w kodzie biblioteki AddInNative.cpp następujące metody:
GetNPros
Zwraca liczbę właściwości dla tego rozszerzenia, 0, jeśli nie ma żadnych właściwości
ZnajdźProp
Zwraca numer porządkowy właściwości, której nazwa jest przekazywana w parametrach
GetPropName
Zwraca nazwę właściwości według liczby porządkowej i przekazanego identyfikatora języka
PobierzPropVal
Zwraca wartość właściwości o określonej liczbie porządkowej
SetPropVal
Ustawia wartość właściwości o określonej liczbie porządkowej
Czy jest czytelny?
Zwraca flagę czytelności właściwości o określonej liczbie porządkowej
Czy można zapisywać?
Zwraca flagę zapisu właściwości z określonym numerem sekwencji


Rozważ implementację powyższych metod klas CADdInNative.
Demo VC definiuje 2 właściwości: Dołączony oraz Jest zegar (Jest włączony oraz IsTimerPresent).
W globalnym zakresie kodu biblioteki zdefiniowane są dwie tablice:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent"); static wchar_t *g_PropNamesRu = (L"Włączone", L"Jest Timer");
które przechowują rosyjskie i angielskie nazwy nieruchomości. W pliku nagłówkowym AddInNative.h wyliczenie jest zdefiniowane:
wyliczenie Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropLast // Zawsze ostatni );
ePropIsEnabled oraz ePropIsTimerObecny, odpowiednio o wartości 0 i 1, służą do zastępowania liczb porządkowych właściwości znaczącymi identyfikatorami. ePropLast, który ma wartość 2, służy do pobrania liczby właściwości (za pomocą metody GetNProps). Te nazwy są używane tylko w kodzie komponentu i nie są dostępne z zewnątrz.
Metody FindProp i GetPropName przeszukują tablice g_PropNames oraz g_PropNames.
Aby przechowywać wartość pól w module biblioteki, klasa CAddInNative posiada właściwości, które przechowują wartość właściwości składnika. Metody PobierzPropVal oraz SetPropVal odpowiednio zwróć i ustaw wartość tych właściwości.
Metody Czy jest czytelny? oraz Czy można zapisywać? i wracaj PRAWDA lub fałszywy, w zależności od przekazanej liczby porządkowej właściwości zgodnie z logiką aplikacji.
Aby dodać właściwość niestandardową:

  1. Dodaj nazwę właściwości, która ma zostać dodana do tablic g_PropNames oraz g_PropNames(plik AddInNative.cpp)
  2. Do wyliczenia rekwizyty(plik AddInNative.h) zanim ePropOstatnia dodaj nazwę, która jednoznacznie identyfikuje dodawaną właściwość
  3. Uporządkuj pamięć do przechowywania wartości właściwości (utwórz pola modułu komponentów, które przechowują odpowiednie wartości)
  4. Wprowadź zmiany w metodach PobierzPropVal oraz SetPropVal do interakcji z pamięcią przydzieloną w poprzednim kroku
  5. Zgodnie z logiką aplikacji wprowadź zmiany w metodach Czy jest czytelny? oraz Czy można zapisywać?
Pozycje 1, 2, 5 nie wymagają wyjaśnienia. Szczegóły realizacji tych kroków znajdują się w załączniku do artykułu.
Nazwijmy właściwości testowe Test oraz Sprawdź typ odpowiednio. Następnie, w wyniku ust. 1, mamy:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent", L"Test", L"TestType"); static wchar_t *g_PropNamesRu = (L"Włączone", L"HasTimer", L"Test", L"CheckType");
Wyliczenie rekwizyty będzie wyglądać jak:
wyliczenie Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropTest1, ePropTest2, ePropLast // Zawsze ostatni );
Aby znacznie uprościć kod, użyjemy STL C++. W szczególności do pracy ze strunami WCHAR, podłącz bibliotekę sznurek.
Aby przechowywać wartość metody Test, zdefiniuj w klasie CADdInNative w zakresie pole prywatne:
test strunowy1;
Do przesyłania parametrów ciągu między 1C:Enterprise a komponentem zewnętrznym używany jest menedżer pamięci 1C:Enterprise. Przyjrzyjmy się bliżej jego pracy. Aby odpowiednio przydzielić i zwolnić pamięć, użyj funkcji AllocMemory oraz Wolna pamięć, zdefiniowane w pliku Menedżer pamięci.h. Jeśli konieczne jest przekazanie parametru ciągu do systemu 1C: Enterprise, komponent zewnętrzny musi przydzielić mu pamięć, wywołując funkcję AllocMemory. Jego prototyp wygląda tak:
virtual bool ADDIN_API AllocMemory (void** pMemory, unsigned long ulCountByte) = 0;
gdzie pPamięć- adres wskaźnika, w którym zostanie umieszczony adres przydzielonej pamięci,
ulCountByte- wielkość przydzielonego obszaru pamięci.
Przykład alokacji pamięci dla ciągu:
WCHAR_T *t1 = NULL, *test = L"TEST_STRING"; int iRzeczywistyRozmiar = wcslen(test1)+1; m_iMemory->AllocMemory((void**)&t1, iActualSize * sizeof(WCHAR_T)); ::convToShortWchar(&t1, test1, iActualSize);
Dla wygody pracy z łańcuchowymi typami danych opisujemy funkcję wstring_to_p. Jako parametr przyjmuje ciąg wstringu. Wynikiem funkcji jest wypełniona struktura tWariant. Kod funkcji:
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(); zwróć prawdę; )
Następnie odpowiednia sekcja case instrukcji switch metody PobierzPropVal przyjmie formę:
przypadek ePropTest1: wstring_to_p(test1, pvarPropVal); przerwanie;
metoda SetPropVal:
case ePropTest1: if (TV_VT(varPropVal) != VTYPE_PWSTR) return false; test1 = std::wstring((wchar_t*)(varPropVal -> pstrVal)); przerwanie;
Aby zaimplementować drugą właściwość, definiujemy pole klasy CaddInNative
uint8_t last_type;
w którym będziemy przechowywać typ ostatniej przekazanej wartości. Aby to zrobić, dodaj następujące polecenie do metody CaddInNative::SetPropVal:
last_type = TV_VT(varPropVal);
Teraz, żądając odczytania wartości drugiej właściwości, zwrócimy wartość ostatni_typ, co jest wymagane przez wyznaczone zadanie.
Sprawdźmy wydajność wprowadzonych zmian.
W tym celu przedstawiamy wygląd zewnętrzny konfiguracja 1C do widoku:
var DemoComp; Procedura SystemStartup() ConnectExternalComponent("...", "DemoVK", ExternalComponentType.Native); DemoComp = New("AddIn.DemoVK.SomeName"); DemoComp.CheckType = 1; Report(String(DemoComp.TypeCheck)); DemoComp.Test = "Wasia"; Report(String(DemoComp.Test)); DemoComp.Test = "Petya"; Report(String(DemoComp.Test)); Report(String(DemoComp.TypeCheck)); Koniec procedury
W wyniku uruchomienia otrzymujemy sekwencję komunikatów:
3
Wasiasz
Petya
22

Druga i trzecia wiadomość są wynikiem odczytania właściwości ustawionej w poprzednim kroku. Pierwsza i druga wiadomość zawierają kod typu ostatniego zestawu właściwości. 3 odpowiada wartości całkowitej, 22 - wartości łańcuchowej. Zgodność typów i ich kodów ustalana jest w aktach typy.h, który znajduje się na dysku ITS.

Rozszerzanie listy metod

Zadanie:
  1. Rozszerz funkcjonalność komponentu zewnętrznego o następującą funkcjonalność:
  2. Dowiedz się, jak wdrożyć metody komponentów zewnętrznych
  3. Dodaj funkcję-metody Funkcja1, który przyjmuje dwa ciągi ("Parametr1" i "Parametr2") jako parametr. W efekcie zwracany jest ciąg formularza: „Sprawdź. Parametr1, Parametr2"
  4. Sprawdź, czy wprowadzone zmiany działają.

Aby zdefiniować metody tworzonego komponentu, deweloper musi zaimplementować w kodzie biblioteki AddInNative następujące metody:
GetNMethods, Znajdźmetodę, Pobierz nazwę metody
Zaprojektowany, aby uzyskać odpowiednio liczbę metod, wyszukaj numer i nazwę metody. Podobne do odpowiednich metod dla właściwości
GetNParams
Zwraca liczbę parametrów metody o określonym numerze sekwencji; jeśli nie ma metody o tym numerze lub nie ma parametrów, zwraca 0
GetParamDefValue
Zwraca domyślną wartość określonego parametru określonej metody
HasRetVal
Zwraca flagę, którą ma metoda z określoną wartością porządkową zwracanej wartości: true dla metod ze zwracaną wartością oraz fałszywy Inaczej
CallAsProc
fałszywy, pojawia się błąd w czasie wykonywania i wykonywanie modułu 1C: Enterprise zostaje zatrzymane. Pamięć dla tablicy parametrów jest przydzielana i zwalniana przez 1C: Enterprise.
CallAsFunc
Wykonuje metodę z określoną liczbą porządkową. Jeśli metoda zwróci fałszywy, pojawia się błąd w czasie wykonywania i wykonywanie modułu 1C: Enterprise zostaje zatrzymane. Pamięć dla tablicy parametrów jest przydzielana przez 1C: Enterprise. Jeśli zwracana wartość jest typu string lub dane binarne, komponent alokuje pamięć za pomocą funkcji AllocMemory menedżera pamięci, zapisuje tam dane i przechowuje ten adres w odpowiednim polu struktury. 1С: Przedsiębiorstwo uwolni tę pamięć, dzwoniąc Wolna pamięć.
Pełny opis metod wraz z listą parametrów jest szczegółowo opisany w dokumentacji dostarczonej na dysku ITS.
Rozważ wdrożenie metod opisanych powyżej.
W kodzie komponentu zdefiniowane są dwie tablice:
static wchar_t *g_MethodNames = (L"Włącz", L"Wyłącz", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture"); static wchar_t *g_MethodNamesRu = (L"Włącz", L"Wyłącz", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadImage");
i wylicz:
wyliczenie Metody ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethLast // Zawsze ostatni );
Są używane w funkcjach GetNMethods, Znajdźmetodę oraz Pobierz nazwę metody, przez analogię z opisem właściwości.
Metody GetNParams, GetParamDefValue, HasRetVal implementacja przełącznika, w zależności od przekazanych parametrów i logiki aplikacji, zwraca wymaganą wartość. metoda HasRetVal w swoim kodzie zawiera listę tylko metod, które mogą zwrócić wynik. Dla nich to powraca PRAWDA. Dla wszystkich metod stalowych zwraca fałszywy.
Metody CallAsProc oraz CallAsFunc zawierają bezpośrednio wykonywalny kod metody.
Aby dodać metodę, która może być wywołana tylko jako funkcja, musisz wprowadzić następujące zmiany w kodzie źródłowym komponentu zewnętrznego:
  1. Dodaj nazwę metody do tablic g_Nazwy metod oraz g_Nazwy metod(plik AddInNative.cpp)
  2. Dodaj znaczący identyfikator metody do wyliczenia Metody (plik AddInNative.h)
  3. Wprowadź zmiany w kodzie funkcji GetNParams zgodnie z logiką programu
  4. W razie potrzeby wprowadź zmiany w kodzie metody GetParamDefValue jeśli chcesz użyć domyślnych wartości parametrów metody.
  5. Wprowadź zmiany w funkcji HasRetVal
  6. Wprowadź zmiany w logice funkcji CallAsProc lub CallAsFunc, umieszczając tam bezpośrednio wykonywalny kod metody
Przynieśmy tablice g_Nazwy metod oraz g_Nazwy metod, a także wyliczenie metody do widoku:
static wchar_t *g_MethodNames = (L"Włącz", L"Wyłącz", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture", L"Test"); static wchar_t *g_MethodNamesRu = (L"Włącz", L"Wyłącz", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadImage", L"Test");

Metody wyliczania ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethTest, eMethLast // Zawsze ostatni );
Edytujmy funkcję GetNPros aby zwracała liczbę parametrów metody „Test”:
long CAddInNative::GetNParams(const long lMethodNum) ( switch(lMethodNum) ( case eMethShowInStatusLine: zwróć 1; case eMethLoadPicture: zwróć 1; case eMethTest: zwróć 2; domyślnie: zwróć 0; ) zwróć 0; )
Wprowadźmy zmiany w funkcji:
bool CAddInNative::GetParamDefValue(const long lMethodNum, const long lParamNum, tVariant *pvarParamDefValue) ( ​​TV_VT(pvarParamDefValue)= VTYPE_EMPTY; switch(lMethodNum) ( case : case / domyślnie brak wartości parametrów break; default: return false; ) return false; )
Dzięki dodanej linii
eMethTest przypadku:
w przypadku braku jednego lub więcej argumentów odpowiednie parametry będą miały pustą wartość ( VTYPE_EMPTY). Jeśli potrzebujesz wartości domyślnej dla parametru, musisz ją określić w sekcji eMethTest instrukcja przełącznika funkcji CAddInNative::GetParamDefValue.
Ponieważ metoda „Test” może zwrócić wartość, musisz wprowadzić zmiany w kodzie funkcji HasRetVal:
bool CAddInNative::HasRetVal(const long lMethodNum) ( switch(lMethodNum) ( case eMethLoadPicture: case eMethTest: return true; default: return false; ) return false; )
I dodaj kod wykonywalny metody do funkcji CallAsFunc:
bool CAddInNative::CallAsFunc(const long lMethodNum, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) ( ... std::wstring s1, s2; switch(lMethodNum) ( case eMeth:LoadPic: Case if (!lSizeArray || !paParams) return false; s1 = (paParams) -> pwstrVal; s2 = (paParams+1) -> pwstrVal; wstring_to_p(std::wstring(s1+s2), pvarRetValue);ret = true ; przerwa; ) powrót ret; )
Skompilujmy komponent i przenieśmy kod konfiguracyjny do postaci:
var DemoComp; Procedura SystemStartup() ConnectExternalComponent("...", "DemoVK", ExternalComponentType.Native); DemoComp = New("AddIn.DemoVK.SomeName"); lane = DemoComp.Test("Cześć, ", "Świat!"); Powiadom(trans); Koniec procedury
Po uruchomieniu konfiguracji otrzymamy komunikat: „Hello, World!”, co oznacza, że ​​metoda zadziałała pomyślnie.

Regulator czasowy

Zadanie:
  1. Przestudiuj implementację timera w wersji demo VK
  2. Zmodyfikuj metodę "StartTimer" dodając możliwość przekazywania w parametrach interwału timera (w milisekundach)
  3. Sprawdź, czy wprowadzone zmiany działają.

W WinAPI do pracy z czasem możesz użyć wiadomości WM_TIMER. Ta wiadomość zostanie wysłana do twojego programu w odstępie czasu określonym podczas tworzenia timera.
Aby utworzyć timer, użyj funkcji Ustaw minutnik:
UINT SetTimer(HWND hWnd, // uchwyt okna UINT nIDevent, // identyfikator timera (liczba) UINT nElapse, // opóźnienie TIMERPROC lpTimerFunc); // wskaźnik funkcji
System operacyjny wyśle ​​wiadomość WM_TIMER do programu z interwałem określonym w argumencie nElapse(w milisekundach). W ostatnim parametrze możesz określić funkcję, która będzie wykonywana przy każdym uruchomieniu timera. Nagłówek tej funkcji powinien wyglądać tak (nazwa może być dowolna):
void __stdcall TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Rozważ implementację timera w wersji demonstracyjnej VK.
Ponieważ rozważamy proces tworzenia zewnętrznego komponentu dla rodziny Windows OS, nie będziemy rozważać implementacji timera w innych system operacyjny. W szczególności dla systemu GNU/Linux OS implementacja będzie się różnić składnią funkcji Ustaw minutnik oraz TimerProc.
Metoda jest wywoływana w kodzie wykonywalnym Ustaw minutnik, do którego przekazywana jest funkcja MyTimerProc:
m_uiTimer = ::SetTimer(NULL,0,100,(TIMERPROC)MyTimerProc);
Identyfikator utworzonego timera jest umieszczony w zmiennej m_uiTimer tak, że możesz go później wyłączyć.
Funkcjonować MyTimerProc następująco:
VOID CALLBACK MyTimerProc(HWND hwnd, // uchwyt okna dla wiadomości timera UINT uMsg, // wiadomość WM_TIMER UINT idEvent, // identyfikator timera DWORD dwTime // aktualny czas systemowy) ( 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 , co, wstime); usuń wstime; ) )
Istotą funkcji jest to, że metoda nazywa się Zdarzenie zewnętrzne, który wysyła wiadomość do systemu 1C: Enterprise.
Aby rozszerzyć funkcjonalność metody StartTimer zróbmy co następuje:
Modyfikowanie kodu metody GetNParams aby to było dla metody eMethStartTimer zwracana wartość 1:
case eMethStartTimer: return 1;
Oto kod metody CallAsProc do widoku:
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;
Sprawdźmy teraz funkcjonalność. W tym celu w module zarządzanej aplikacji konfiguracji napiszemy kod:
var DemoComp; Procedura SystemStartup() ConnectExternalComponent("...", "DemoVK", ExternalComponentType.Native); DemoComp = New("AddIn.DemoVK.SomeName"); DemoComp.StartTimer(2000); Koniec procedury
Po uruchomieniu konfiguracji program będzie otrzymywał komunikaty w odstępie 2 sekund, co wskazuje na poprawną pracę timera.

Interakcja z systemem 1C: Enterprise

Aby współdziałać między komponentem zewnętrznym a systemem 1C:Enterprise, metody klasy IAddInDefBase opisane w pliku AddInDefBase.h. Wymieniamy najczęściej używane:
Generowanie komunikatu o błędzie
virtual bool ADDIN_API AddError(unsigned short wcode, const WCHAR_T* source, const WCHAR_T* descr, long scode)
kod, kod- kody błędów (lista kodów błędów wraz z opisem znajduje się na dysku ITS)
źródło- źródło błędu
opis- opis błędu
Wysyłanie wiadomości do systemu 1C: Enterprise
virtual bool ADDIN_API ExternalEvent(WCHAR_T* wszSource, WCHAR_T* wszMessage, WCHAR_T* wszData) = 0;
wszŹródło- źródło wiadomości
wszMessage- Wiadomość tekstowa
wszData- przesyłane dane
Przechwycenie wiadomości odbywa się za pomocą procedury HandlingExternalEvent
Rejestracja komponentu zewnętrznego w systemie 1C:Enterprise
virtual bool ADDIN_API RegisterProfileAs(WCHAR_T* wszProfileName)
wszNazwaProfilu- nazwa komponentu.
Te metody są wystarczające do pełnej interakcji VK i 1C. Aby odebrać dane przez komponent zewnętrzny z systemu 1C:Enterprise i odwrotnie, komponent zewnętrzny wysyła specjalną wiadomość, która z kolei jest przechwytywana przez system 1C i, jeśli to konieczne, wywołuje metody komponentu zewnętrznego do wysłania wstecz dane.

tWariant typ danych

Podczas wymiany danych między komponentem zewnętrznym a systemem 1C:Enterprise używany jest typ danych tVariant. Jest to opisane w pliku types.h, który znajduje się na dysku ITS:
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 uintV32_ultVal _intVal; h bVal; char chVal; wchar_t wchVal; DATE data; IID IDVal; struct _tVariant *pvarVal; struct tm tmVal; _ANONYMOUS_STRUCT struct ( void* pInterfaceVal; IID InterfaceID; ) __VARIANT_NAME_2/_S_CTMO/ struct __VARIANT_NAME_2/_S_CTMO/ /liczba bajtów ) __VARIANT_NAME_3/*str*/; _ANONYMOUS_STRUCT struct ( WCHAR_T* pwstrVal; uint32_t wstrLen; //liczba symboli ) __VARIANT_NAME_4/*wstr*/; ) __VARIANT_NAME_1; w pvarVal TYPEVAR vt; );
Typ tWariant to struktura, która obejmuje:
  • mieszanina (związek) przeznaczona bezpośrednio do przechowywania danych
  • identyfikator typu danych
Ogólnie praca ze zmiennymi typu tWariant odbywa się według następującego algorytmu:
  1. Określanie typu danych aktualnie przechowywanych w zmiennej
  2. Dostęp do odpowiedniego pola mieszaniny w celu bezpośredniego dostępu do danych
Typ użycia tWariant znacznie upraszcza interakcję systemu 1C: Enterprise i komponentu zewnętrznego

Aplikacja

Katalog "przykłady" zawiera przykłady do artykułu
example/1 – uruchom komponent demo
example/2 - demo rozszerzenia listy nieruchomości
przykłady/3 - demonstracja rozszerzenia listy metod
Każdy katalog zawiera projekt VS 2008 i wstępnie zbudowaną konfigurację 1C.

Często programiści mają problemy z podłączeniem komponentów zewnętrznych (na przykład sterowników sprzętu komercyjnego), gdy użytkownicy pracują z 1C, łącząc się z serwerem przez terminal.

W tym samym czasie użytkownicy widzą np. obrazek prezentowany w ogłoszeniu artykułu.

Podczas pracy z komputerów lokalnych nie ma problemów z podłączeniem komponentów zewnętrznych.

Z czym to się wiąże? Dzieje się tak, ponieważ użytkownicy pracujący za pośrednictwem serwera terminali mają mniej uprawnień niż wtedy, gdy pracują na komputerze lokalnym.

Łatwo to sprawdzić, jeśli logujesz się do serwera terminali na konto z uprawnieniami administratora.

Powodem tej różnicy jest to, że 1C nie może zarejestrować zewnętrznego komponentu w rejestrze, gdy użytkownik pracuje w terminalu na normalnych prawach, ponieważ zwykły użytkownik nie ma uprawnień do zapisu w gałęzi rejestru systemu HKEY_CLASSES_ROOT.

W publikacjach na temat łączenia elementów zewnętrznych w terminalu proponowane są różne metody rozwiązania tego problemu.

Na przykład te:

1. Uruchom 1C po raz pierwszy na prawach administracyjnych.

Ta opcja nie zawsze działa. Poniżej wyjaśnię dlaczego.

2. Przyznaj zwykłym użytkownikom terminala prawo zapisu do gałęzi rejestru systemu HKEY_CLASSES_ROOT.

Niedostatecznie „zaawansowani” użytkownicy nie powinni tego robić, w przeciwnym razie mogą wystąpić problemy.

3. Za pomocą różnych „gadżetów” zarejestruj VK w imieniu użytkownika z pełnymi prawami.

Jedzenie też nie jest dobre.

Jaki jest więc najlepszy sposób na wyjście z tej sytuacji?

Oferuję swoje rozwiązanie tego problemu. Moim zdaniem - proste i piękne, nie oferowane wcześniej na infostart.

Badając ten problem, zastanawiałem się - dlaczego 1C w ogóle próbuje zarejestrować VK na nowej ścieżce? W końcu jest już zarejestrowany w systemie.

Okazało się, że w typowych konfiguracjach 1C (np. „Zarządzanie handlem”) używana jest następująca składnia metody kontekstu globalnego ConnectExternalComponent() :

ConnectExternalComponent("Reference.ConnectedEquipment.Layout.DriverATOLBarcodeScanner", "ATOLScanner");

Jak widać, sterownik VK jest podłączony z układu „DriverATOLScannerBarcode” katalogu „Podłączony sprzęt”.

Co się wtedy dzieje?

1C zapisuje komponent w tymczasowym folderze użytkownika, na przykład „C:\Documents and Settings\User\Local Settings\Temp\1032\v8_4_12.tmp”

i próbuje zarejestrować go w gałęzi rejestru HKEY_CLASSES_ROOT wzdłuż tej ścieżki.

Na terminalu zwykli użytkownicy nie mają uprawnień do zmiany tej gałęzi rejestru, więc komponent nie jest dla nich podłączony.

Teraz o tym, jak wyjść z tej sytuacji.

Metoda globalnego kontekstu ConnectExternalComponent() ma kilka opcji składni. Właśnie tego użyjemy.

Tak więc krok po kroku:

1. Zarejestruj komponent zewnętrzny za pomocą narzędzia regsvr32.exe na serwerze terminali w folderze C:\WINDOWS\SYSTEM32 dla 32-bitowego systemu operacyjnego lub w folderze C:\WINDOWS\SYSWOW64 dla 64-bitowego systemu operacyjnego.

2. Użyj jednej z dwóch dodatkowych opcji składni dla metody ConnectExternalComponent():

Opcja 1:

ConnectExternalComponent("C:\WINDOWS\SysWOW64\Scaner1C.dll", "ATOLScanner", ExternalComponentType.COM);

DriverObject = New("AddIn.ATOLScanner.Scanner45");

Opcja 2:

ProgID = "AddIn.Scanner45";

Podłącz komponent zewnętrzny (ProgID);

DriverObject = Nowy(ProgID);

Moim zdaniem opcja nr 2 jest lepsza.

Jednocześnie 1C nie próbuje ponownie zarejestrować VC wzdłuż nowej ścieżki w rejestrze, a tym samym wszystkie problemy zostaną rozwiązane.

Cóż, to wszystko. Powodzenia w pracy!

Na przykład nie będzie możliwe przepisanie komponentu, jeśli nie jesteś jego autorem i po prostu nie ma kodów źródłowych. Lub jeśli najprostsze typy obsługiwane przez technologię Native API (number, string, boolean, date) nie wystarczą do jego działania.

Nie ma specjalnych problemów podczas pracy z bazą plików. Zaplanowane zadanie jest wywoływane w tle zwykłego użytkownika. Dzięki temu telefony od klientów są dla niego dostępne. Gdy uruchamiane jest zaplanowane zadanie, w bazie danych serwera nie ma kontekstu klienta, więc wywołanie ConnectExternalComponent() niedostępne.

W takim przypadku możesz wywołać komponent na kliencie. Aby to zrobić, wystarczy uruchomić kolejną sesję 1C z zaplanowanego zadania na serwerze, w którym wykonać niezbędne czynności na kliencie. Cóż, nie zapomnij o zakończeniu sesji biegowej później.

Załóżmy, że w naszym zaplanowanym zadaniu generujemy i zapisujemy raport, który używa zewnętrznego składnika COM NameDeclension.dll do odrzucenia pełnej nazwy. Na bazie plików takie zaplanowane zadanie będzie działać poprawnie, ale nie będzie działać na komponencie serwera.

Aby rozwiązać ten problem, dodajmy do modułu zadań zaplanowanych procedurę, która uruchomi kolejną sesję w trybie serwera i wykona w nim wywołanie generowania raportu na kliencie z przetwarzania zewnętrznego.

#If Client Then Procedura ExecuteFormationAndSavingReport() Eksportuj If ConnectExternalComponent("CommonLayout.NAMEDECL","Cl",ExternalComponentType.COM) Then Component = New ("AddIn.Cl.NameDeclension"); //Oto kod do generowania i zapisywania raportu ElseJoinLogRecord("RegTask", LogLogLevel.Error, "Nie udało się połączyć zewnętrznego komponentu na kliencie"); EndIf; Koniec procedury #Otherwise Procedura ExecuteFormationAndSavingReport() Eksportuj ExecuteOperationOnClient("RegularTasks.ExecuteFormationAndSavingReport()"); EndProcedure Procedura PerformOperationOnClient(ParameterToExecute) ExportUserName = ""; Hasło Użytkownika = ""; PathToExternalProcessing = "c:/temp/Autostart.epf"; Cytat = """"; KatalogBIN = KatalogProgram(); PathToConfiguration = InfoBase ConnectionString(); ŚcieżkaKonfiguracji = StrReplace(ŚcieżkaKonfiguracji, Cytat, Cytat + Cytat); StartString = Cytat + Katalog Bin + "1cv8.exe" + Cytat + " PRZEDSIĘBIORSTWO" + " /IBConnectionString " + Cytat + ŚcieżkaKonfiguracji + Cytat + " /N " + Cytat + Nazwa użytkownika + Cytat + " /P " + Cytat + Hasło użytkownika + Cytat + "/Execute" + Cytat + ŚcieżkaDoPrzetwarzania Zewnętrznego + Cytat + "/C" + Cytat + ParametrDoWykonywania + Cytat; StartAplikacja(StartString); EndProcedure #EndIf

Kod przetwarzania zewnętrznego, który po prostu powoduje, że kontekst klienta drukuje wymagany raport z modułu zaplanowanych zadań i kończy sesję po wygenerowaniu raportu.

Próba wykonania (Parametr startowy); Wyjątek EndTry; System zamykania (fałsz);

Wygoda rozwiązania polega na tym, że podczas konfigurowania zaplanowanych zadań nie ma znaczenia, w jakim trybie zadanie zostanie uruchomione. Jeżeli baza danych jest plikiem plikowym, to niezbędna procedura rozpocznie się natychmiast. Jeśli baza danych znajduje się po stronie serwera i podczas uruchamiania nie ma kontekstu klienta, zostanie zainicjowana nowa sesja i procedura będzie działać poprawnie w kontekście klienta.

Kod dla typowej aplikacji. Teoretycznie będzie działał w zupełnie podobny sposób w zarządzanym.

p.s. Podejście to można również wykorzystać do wykonania dowolnych procedur klienta w zaplanowanych zadaniach.

DZWON

Są tacy, którzy czytają tę wiadomość przed tobą.
Subskrybuj, aby otrzymywać najnowsze artykuły.
E-mail
Nazwa
Nazwisko
Jak chciałbyś przeczytać The Bell?
Bez spamu