Išorinių komponentų technologija (). Išorinių komponentų technologija () Duomenų tipas tVariant

ansmirnovas 2013 m. rugpjūčio 22 d., 14.12 val

Išoriniai komponentai, nurodyti 1C 8.2

  • Programavimas,
  • C++
  • Pamoka

Įvadas

Šiame straipsnyje pateikiama idėja, kaip išoriniai komponentai veikia sistemoje 1C: Enterprise.
Bus parodytas išorinio komponento kūrimo procesas, skirtas 1C: Enterprise sistemos versijai 8.2, veikiančiai Windows OS su failo veikimo režimu. Ši parinktis naudojama daugelyje sprendimų, skirtų mažoms įmonėms. VK bus įdiegtas C++ programavimo kalba.

Išoriniai komponentai „1C: Enterprise“

„1C: Enterprise“ yra išplečiama sistema. Sistemos funkcionalumui išplėsti naudojami išoriniai komponentai (EC). Kūrėjo požiūriu, VC yra išorinis objektas, turintis savybių ir metodų, taip pat galintis generuoti įvykius, kuriuos apdoroja „1C: Enterprise“ sistema.
Išoriniai komponentai gali būti naudojami sprendžiant daugybę problemų, kurias sunku ar net neįmanoma įgyvendinti programavimo kalba, integruota į 1C: Enterprise. Visų pirma, ši klasė apima užduotis, kurioms reikalinga žemo lygio sąveika su operacine sistema, pavyzdžiui, norint dirbti su konkrečia įranga.
Sistema 1C: Enterprise išoriniams komponentams kurti naudoja dvi technologijas:
  • naudojant Native API
  • naudojant COM technologiją
Atsižvelgiant į pateiktus apribojimus, skirtumas tarp dviejų aukščiau paminėtų technologijų yra nereikšmingas, todėl svarstysime vaizdo žaidimų kūrimą naudojant Native API. Jei reikia, įgyvendintus patobulinimus galima pritaikyti kuriant kompiuterių programinę įrangą naudojant COM technologiją, o taip pat su nedideliais pakeitimais pritaikyti naudoti sistemoje 1C: Enterprise su kitomis veikimo galimybėmis, išskyrus failo veikimo režimą.
VK struktūra
Išorinis 1C: Enterprise sistemos komponentas pateikiamas DLL bibliotekos pavidalu. Bibliotekos kodas apibūdina palikuonių klasę IComponentBase. Sukurta klasė turi apibrėžti metodus, atsakingus už išorinio komponento funkcijų įgyvendinimą. Nepaisyti metodai bus išsamiau aprašyti toliau, kai pateikiama medžiaga.

Demonstracinio VK paleidimas

Užduotis:
  1. Surinkite išorinį komponentą, tiekiamą su ITS prenumerata ir skirtą parodyti pagrindines išorinio komponento mechanizmo galimybes 1C.
  2. Prijunkite demonstracinį komponentą prie 1C konfigūracijos
  3. Įsitikinkite, kad deklaruotos funkcijos veikia tinkamai
Kompiliacija
Demonstracinė VK yra ITS prenumeratos diske „/VNCOMP82/example/NativeAPI“ kataloge.
Norėdami sukurti demonstracinį VC, naudosime Microsoft Visual Studio 2008. Kitos šio produkto versijos nepalaiko naudojamo Visual Studio projekto formato.


Atidarykite projektą AddInNative. Į projekto nustatymus įtraukiame katalogą su antraščių failais, reikalingais projektui sukurti. Pagal numatytuosius nustatymus jie yra ITS diske, esančiame kataloge /VNCOMP82/įtraukti.
Konstravimo rezultatas yra failas /bind/AddInNative.dll. Tai yra sudaryta biblioteka, skirta prisijungti prie 1C konfigūracijos.
VK prijungimas prie 1C konfigūracijos
Sukurkime tuščią 1C konfigūraciją.
Toliau pateikiamas valdomos programos modulio kodas.
kintamasis DemoComp; Procedūra, kai sistema paleidžiama () Prijunkite išorinį komponentą ("...\bind\AddInNative.dll", "DemoVK", išorinio komponento tipas. Native); DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); Procedūros pabaiga
Jei paleidžiant 1C konfigūraciją nebuvo pranešta apie klaidą, VK buvo sėkmingai prijungtas.
Vykdant aukščiau pateiktą kodą, konfigūracijos visuotiniame matomumo lange atsiranda objektas DemoComp, kurios savybės ir metodai yra apibrėžti išorinio komponento kode.
Integruoto funkcionalumo demonstravimas
Patikrinkime demonstracinės VK funkcionalumą. Norėdami tai padaryti, pabandykime nustatyti ir perskaityti kai kurias ypatybes, iškviesti kai kuriuos VK metodus, taip pat gauti ir apdoroti VK pranešimą.
ITS diske pateiktoje dokumentacijoje nurodomos šios demonstracinės VC funkcijos:
  1. Valdymo komponento objekto būsena
    Metodai: Įjungti, Išjungti
    Savybės: Įskaitant
  2. Laikmačio valdymas
    Kas sekundę komponentas siunčia pranešimą „1C: Enterprise“ sistemai su parametrais Komponentas, Laikmatis ir sistemos laikrodžio skaitiklio linija.
    Metodai: StartTimer, StopTimer
    Savybės: Yra laikmatis
  3. Metodas ShowInStatusLine, kuri būsenos eilutėje rodo metodui perduotą tekstą kaip parametrus
  4. Metodas Įkelti paveikslėlį. Įkelia vaizdą iš nurodyto failo ir perkelia jį į 1C: Enterprise sistemą dvejetainių duomenų pavidalu.
Įsitikinkite, kad šios funkcijos veikia. Norėdami tai padaryti, paleiskite šį kodą:
kintamasis DemoComp; Procedūra, kai sistema paleidžiama() ConnectExternalComponent(...); DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); DemoComp.Disable(); Report(DemoComp.Enabled); DemoComp.Enable(); Report(DemoComp.Enabled); DemoComp.StartTimer(); Procedūros pabaigos procedūra Išorinio įvykio apdorojimo (šaltinis, įvykis, duomenys) ataskaita (šaltinis + " " + įvykis + " " + duomenys); Procedūros pabaiga
Konfigūracijos vykdymo rezultatas parodytas paveikslėlyje


Skydelyje „Pranešimai“ rodomi metodų iškvietimų rezultatai DemoComp.Disable() Ir Demo.Comp.Enable(). Tolesnėse to paties skydelio eilutėse pateikiami iš VK gautų pranešimų apdorojimo rezultatai - Šaltinis, Renginys Ir Duomenys atitinkamai.

Pasirinktinis išorinio komponento pavadinimas

Užduotis: pakeiskite išorinio komponento pavadinimą į savavališką.
Ankstesnėje dalyje buvo naudojamas identifikatorius AddInNativeExtension, kurios reikšmė nebuvo paaiškinta. Tokiu atveju AddInNativeExtension– tai plėtinio pavadinimas.
VK kodas apibrėžia metodą RegistruotisPlėtinysAs, grąžindamas pavadinimą į sistemą 1C: Enterprise, kuris reikalingas vėlesniam VK registravimui sistemoje. Rekomenduojama nurodyti identifikatorių, kuris tam tikru mastu atskleidžia išorinio komponento esmę.
Čia yra visas metodo kodas RegistruotisPlėtinysAs su pakeistu plėtinio pavadinimu:
bool CAddInNative::RegisterExtensionAs(WCHAR_T** wsExtensionName) ( wchar_t *wsExtension = L"SomeName"; int iActualSize = ::wcslen(wsExtension) + 1; WCHAR_T* tikslas = 0; if (m_m_Memory_Memory ((void**)wsExtensionName, iActualSize * sizeof(WCHAR_T))) ::convToShortWchar(wsExtensionName, iActualSize) return false;
Pateiktame pavyzdyje VK pavadinimas pakeistas į SomeName. Tada prisijungdami prie VK turite nurodyti naują pavadinimą:
DemoComp = New("AddIn.DemoVK.SomeName");

Išplečiamas VK savybių sąrašas

Užduotis:
  1. Ištirti VK savybių įgyvendinimą
  2. Pridėkite eilutės tipo skaitymo / rašymo ypatybę
  3. Pridėkite skaitymo / rašymo eilutės ypatybę, kurioje saugomas paskutinio ypatybių rinkinio duomenų tipas. Nustatant nuosavybės vertę neatliekama jokių veiksmų

Kad nustatytų kuriamo komponento ypatybes, kūrėjas AddInNative.cpp bibliotekos kode turi įdiegti šiuos metodus:
GetNprops
Grąžina šio plėtinio ypatybių skaičių, 0, jei ypatybių nėra
FindProp
Grąžina nuosavybės, kurios pavadinimas perduotas parametruose, serijos numerį
GetPropName
Grąžina nuosavybės pavadinimą pagal serijos numerį ir perduotą kalbos identifikatorių
GetPropVal
Grąžina turto vertę nurodytu eilės numeriu
SetPropVal
Nurodo turto vertę nurodytu eilės numeriu
IsPropReadable
Grąžina nuosavybės skaitomumo vėliavėlę su nurodytu eilės numeriu
IsPropWritable
Grąžina nuosavybės įrašymo vėliavėlę su nurodytu eilės numeriu


Panagrinėkime aukščiau pateiktų klasės metodų įgyvendinimą CAddInNative.
Demonstracinėje VC apibrėžiamos 2 savybės: Įskaitant Ir Yra laikmatis (Įjungta Ir IsTimerPresent).
Visuotinėje bibliotekos kodo apimtyje yra apibrėžti du masyvai:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent"); static wchar_t *g_PropNamesRu = (L"Įjungta", L"Yra laikmatis");
kuriuose saugomi rusiški ir angliški nuosavybės pavadinimai. Antraštės faile AddInNative.h sąrašas yra apibrėžtas:
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropLast // Visada paskutinis );
ePropIsEnabled Ir ePropIsTimerPresent, turinčios atitinkamai reikšmes 0 ir 1, naudojami savybių serijos numeriams pakeisti reikšmingais identifikatoriais. ePropLast, kurio reikšmė yra 2, naudojama ypatybių skaičiui gauti (naudojant GetNprops metodą). Šie pavadinimai naudojami tik komponento kode ir nepasiekiami išorėje.
Metodai FindProp ir GetPropName atlieka masyvo paieškas g_PropNames Ir g_PropNamesRu.
Norėdami išsaugoti bibliotekos modulio laukų reikšmes, CAddInNative klasėje yra ypatybių, kuriose saugoma komponento ypatybių reikšmė. Metodai GetPropVal Ir SetPropVal grąžinti ir atitinkamai nustatyti šių savybių vertę.
Metodai IsPropReadable Ir IsPropWritable ir grįžti tiesa arba klaidinga, priklausomai nuo perduodamo turto eilės numerio pagal taikymo logiką.
Norėdami pridėti pasirinktinę nuosavybę, turite:

  1. Pridėkite prie masyvų pridedamos nuosavybės pavadinimą g_PropNames Ir g_PropNamesRu(failas AddInNative.cpp)
  2. Išvardinti Rekvizitas(failas AddInNative.h) anksčiau ePropLast pridėkite pavadinimą, kuris vienareikšmiškai identifikuoja pridedamą nuosavybę
  3. Tvarkykite atmintį savybių reikšmėms saugoti (sukurkite modulio komponentų laukus, kuriuose saugomos atitinkamos reikšmės)
  4. Pakeiskite metodus GetPropVal Ir SetPropVal sąveikauti su atmintimi, skirta ankstesniame veiksme
  5. Vadovaudamiesi taikymo logika, pakeiskite metodus IsPropReadable Ir IsPropWritable
1, 2, 5 punktų paaiškinti nereikia. Išsamią informaciją apie šių žingsnių įgyvendinimą galite rasti perskaitę straipsnio priedą.
Pavadinkime testo savybes Testas Ir Tipo patikrinimas atitinkamai. Tada, atlikdami 1 veiksmą, turime:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent", L"Test", L"TestType"); static wchar_t *g_PropNamesRu = (L"Įjungta", L"Yra laikmatis", L"Test", L"Tipo patikra");
Perdavimas Rekvizitas atrodys taip:
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropTest1, ePropTest2, ePropLast // Visada paskutinis );
Norėdami žymiai supaprastinti kodą, naudosime STL C++. Ypač darbui su stygomis WCHAR, prijungkime biblioteką wstring.
Norėdami išsaugoti metodo reikšmę Testas, mes apibrėžiame klasėje CAddInNative privačioje srityje:
stygos testas1;
Norėdami perkelti eilutės parametrus tarp 1C: Enterprise ir išorinių komponentų, naudojama 1C: Enterprise atminties tvarkyklė. Pažvelkime į jo darbus atidžiau. Funkcijos naudojamos atitinkamai paskirstyti ir atlaisvinti atmintį AllocMemory Ir Laisva atmintis apibrėžta faile „ImemoryManager.h“. Jei reikia perduoti eilutės parametrą 1C: Enterprise sistemai, išorinis komponentas turi skirti jam atmintį iškviesdamas funkciją AllocMemory. Jo prototipas atrodo taip:
virtualus bool ADDIN_API AllocMemory (tuščia** pAtmintis, nepasirašytas ilgas ulCountByte) = 0;
Kur pAtmintis- rodyklės, į kurią bus patalpintas paskirtos atminties srities adresas, adresas,
ulCountByte- skirtos atminties srities dydis.
Eilutės atminties paskirstymo pavyzdys:
WCHAR_T *t1 = NULL, *testas = L"TEST_STRING"; int iActualus dydis = wcslen(test1)+1; m_iMemory->AllocMemory((void**)&t1, iActualSize * sizeof(WCHAR_T)); ::convToShortWchar(&t1, test1, iActualSize);
Kad būtų patogiau dirbti su eilučių duomenų tipais, apibūdinsime funkciją wstring_to_p. Jis kaip parametras gauna wstring eilutę. Funkcijos rezultatas yra užpildyta struktūra tVariantas. Funkcijos kodas:
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; grąžinti tiesa)
Tada atitinkamas atvejis skirsnis jungiklis pareiškimo metodas GetPropVal bus tokia forma:
atvejis ePropTest1: wstring_to_p(test1, pvarPropVal); pertrauka;
Metodas SetPropVal:
case ePropTest1: if (TV_VT(varPropVal) != VTYPE_PWSTR) return false; testas1 = std::wstring((wchar_t*)(varPropVal -> pstrVal)); pertrauka;
Norėdami įgyvendinti antrąją savybę, apibrėžiame klasės lauką „CaddInNative“.
uint8_t last_type;
kuriame išsaugosime paskutinės perduotos reikšmės tipą. Norėdami tai padaryti, pridėkite komandą prie CaddInNative::SetPropVal metodo:
paskutinis_tipas = TV_VT(varPropVal);
Dabar, kai prašome perskaityti antrojo turto vertę, mes grąžinsime vertę paskutinis_tipas, ko reikalauja paskirta užduotis.
Patikrinkime atliktų pakeitimų funkcionalumą.
Norėdami tai padaryti, pateiksime 1C konfigūracijos išvaizdą taip:
kintamasis DemoComp; Procedūra, kai sistema paleidžiama () Prijunkite išorinį komponentą ("...", "DemoVK", išorinio komponento tipas. Native); DemoComp = New("AddIn.DemoVK.SomeName"); DemoComp.TypeCheck = 1; Report(String(DemoComp.TypeCheck)); DemoComp.Test = "Vasya"; Report(String(DemoComp.Test)); DemoComp.Test = "Petya"; Report(String(DemoComp.Test)); Report(String(DemoComp.TypeCheck)); Procedūros pabaiga
Po paleidimo gausime pranešimų seką:
3
Vasja
Petras
22

Antrasis ir trečiasis pranešimai yra ankstesniame veiksme nustatytos nuosavybės nuskaitymo rezultatas. Pirmame ir antrame pranešimuose yra paskutinio ypatybių rinkinio tipo kodas. 3 atitinka sveikojo skaičiaus reikšmę, 22 – eilutės reikšmę. Byloje nustatytas tipų ir jų kodų atitikimas tipai.h, kuris yra ITS diske.

Metodų sąrašo išplėtimas

Užduotis:
  1. Išplėskite išorinio komponento funkcionalumą šiomis funkcijomis:
  2. Ištirkite išorinių komponentų metodų diegimo būdus
  3. Pridėkite funkcijos metodą Funkcija1, kuris kaip parametras naudoja dvi eilutes („Parameter1“ ir „Parameter2“). Rezultatas yra tokia eilutė: „Tikrinimas. 1 parametras, 2 parametras
  4. Įsitikinkite, kad atlikti pakeitimai veikia.

Norėdami apibrėžti kuriamo komponento metodus, kūrėjas AddInNative bibliotekos kode turi įdiegti šiuos metodus:
GetNMethods, FindMethod, GetMethodName
Sukurta gauti atitinkamą metodų skaičių, ieškokite metodo numerio ir pavadinimo. Panašus į atitinkamus savybių metodus
GetNParams
Grąžina metodo parametrų skaičių su nurodytu eilės numeriu; jei metodo su šiuo numeriu nėra arba jis neturi parametrų, grąžina 0
GetParamDefValue
Grąžina numatytąją nurodyto metodo nurodyto parametro reikšmę
HasRetVal
Grąžina vėliavėlę, kad egzistuoja metodas su nurodyta eiline grąžinimo verte: teisinga metodams su grąžinimo reikšme ir klaidinga kitaip
CallAsProc
klaidinga, įvyksta vykdymo klaida ir 1C: Enterprise modulio vykdymas nutraukiamas. Atmintį parametrų masyvei skiria ir išleidžia 1C: Enterprise.
CallAsFunc
Vykdo metodą su nurodytu eilės numeriu. Jei metodas grįžta klaidinga, įvyksta vykdymo klaida ir 1C: Enterprise modulio vykdymas nutraukiamas. Atmintį parametrų masyvei skiria 1C: Enterprise. Jei grąžinama reikšmė yra eilutė arba dvejetainis duomenų tipas, komponentas priskiria atmintį funkcijai AllocMemory atminties tvarkyklę, įrašo ten duomenis ir išsaugo šį adresą atitinkamame struktūros laukelyje. 1C: Įmonė atlaisvins šią atmintį paskambinusi Laisva atmintis.
Išsamus metodų aprašymas, įskaitant parametrų sąrašą, yra išsamiai aprašytas dokumentacijoje, pateiktoje ITS diske.
Panagrinėkime aukščiau aprašytų metodų įgyvendinimą.
Komponento kode yra apibrėžti du masyvai:
static wchar_t *g_MethodNames = (L"Įgalinti", L"Išjungti", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture"); static wchar_t *g_MethodNamesRu = (L "Įgalinti", L "Išjungti", L "ShowInStatusLine", L "StartTimer", L "StopTimer", L "LoadImage");
ir išvardijimas:
enum Methods ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethLast // Visada paskutinis );
Jie naudojami funkcijose GetNMethods, FindMethod Ir GetMethodName, pagal analogiją su savybių aprašymu.
Metodai GetNParams, GetParamDefValue, HasRetVal padargo jungiklis, priklausomai nuo perduodamų parametrų ir programos logikos, grąžina reikiamą reikšmę. Metodas HasRetVal jo kode yra tik metodų, galinčių grąžinti rezultatą, sąrašas. Už juos jis grįžta tiesa. Visiems plieno metodams grąžinama klaidinga.
Metodai CallAsProc Ir CallAsFunc yra tiesiogiai vykdomas metodo kodas.
Norėdami pridėti metodą, kurį galima iškviesti tik kaip funkciją, turite atlikti šiuos išorinio komponento šaltinio kodo pakeitimus:
  1. Pridėkite metodo pavadinimą prie masyvų g_MethodNames Ir g_MethodNamesRu(failas AddInNative.cpp)
  2. Pridėkite reikšmingą metodo identifikatorių prie Metodų sąrašo (failas AddInNative.h)
  3. Pakeiskite funkcijos kodą GetNParams pagal programos logiką
  4. Jei reikia, pakeiskite metodo kodą GetParamDefValue, jei norite naudoti numatytąsias metodo parametrų reikšmes.
  5. Atlikite funkcijos pakeitimus HasRetVal
  6. Pakeiskite funkcijų logiką CallAsProc arba CallAsFunc, įdėdami ten tiesiogiai vykdomą metodo kodą
Pateikiame masyvus g_MethodNames Ir g_MethodNamesRu, taip pat sąrašas Metodaiį formą:
static wchar_t *g_MethodNames = (L"Įgalinti", L"Išjungti", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture", L"Test"); static wchar_t *g_MethodNamesRu = (L "Įgalinti", L "Išjungti", L "ShowInStatusLine", L "StartTimer", L "StopTimer", L "LoadPicture", L "Test");

Enum metodai ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethTest, eMethLast // Visada paskutinis );
Redaguojame funkciją GetNprops kad būtų pateiktas „Test“ metodo parametrų skaičius:
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; )
Pakeiskime funkciją:
bool CAddInNative::GetParamDefValue(const long lMethodNum, const long lParamNum, tVariant *pvarParamDefValue) (TV_VT(pvarParamDefValue)= VTYPE_EMPTY; switch(lMethodNum) (case: eMethIntuseLcase: MethStartTimer: atvejis eMethStopTimer: atvejis eMethTest : / / Pagal numatytuosius nustatymus nėra parametrų reikšmių: return false;
Dėl pridėtos linijos
atvejis eMethTest:
jei trūksta vieno ar daugiau argumentų, atitinkami parametrai turės tuščią reikšmę ( VTYPE_EMPTY). Jei jums reikia numatytosios parametro reikšmės, turėtumėte ją nustatyti skyriuje eMethTest funkcijų jungiklio teiginys CAddInNative::GetParamDefValue.
Kadangi bandymo metodas gali grąžinti reikšmę, turite pakeisti funkcijos kodą HasRetVal:
bool CAddInNative::HasRetVal(const long lMethodNum) ( switch(lMethodNum) ( case eMethLoadPicture: case eMethTest: return true; default: return false; ) return false; )
Ir pridėkite vykdomąjį metodo kodą prie funkcijos CallAsFunc:
bool CAddInNative::CallAsFunc(const long lMethodNum, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) ( ... std::wstring s1, s2; switch(lMethodNum) ( case eMethLoadTesticture:MethLoadT; if (!lSizeArray || !paParams) return s1 = (paParams) -> pwstrVal (paParams+1) -> pwstring_to_p(std::wstring(s1+s2), pvarRetValue; ;
Sukompiliuokime komponentą ir perkelkime konfigūracijos kodą į formą:
kintamasis DemoComp; Procedūra, kai sistema paleidžiama() Connect External Component("...", "DemoVK", External Component Type.Native); DemoComp = New("AddIn.DemoVK.SomeName"); juosta = DemoComp.Test("Sveiki", "Pasaulis!"); Ataskaita(per); Procedūros pabaiga
Paleidę konfigūraciją, gausime pranešimą: "Sveikas, pasauli!", kuris rodo, kad metodas sėkmingai veikė.

Laikmatis

Užduotis:
  1. Išstudijuokite laikmačio įgyvendinimą demonstraciniame VK
  2. Modifikuokite „StartTimer“ metodą, įtraukdami į parametrus galimybę perduoti laikmačio atsako intervalą (milisekundėmis)
  3. Įsitikinkite, kad atlikti pakeitimai veikia.

WinAPI galite naudoti pranešimą, kad galėtumėte dirbti su laiku WM_TIMER. Šis pranešimas bus išsiųstas jūsų programai tokiu laiko intervalu, kurį nustatėte kurdami laikmatį.
Norėdami sukurti laikmatį, naudokite funkciją Nustatyti laikmatį:
UINT SetTimer(HWND hWnd, // lango aprašas UINT nIDevent, // laikmačio identifikatorius (skaičius) UINT nElapse, // delsa TIMERPROC lpTimerFunc); // rodyklė į funkciją
Operacinė sistema išsiųs pranešimą WM_TIMERį programą su argumente nurodytu intervalu nElapse(milisekundėmis). Paskutiniame parametre galite nurodyti funkciją, kuri bus vykdoma kiekvieną kartą, kai suveikia laikmatis. Šios funkcijos antraštė turėtų atrodyti taip (pavadinimas gali būti bet koks):
negalioja __stdcall TimerProc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Panagrinėkime laikmačio įgyvendinimą demonstraciniame VC.
Kadangi svarstome išorinio komponento Windows OS šeimai kūrimo procesą, laikmačio įdiegimo kitose operacinėse sistemose nesvarstysime. Visų pirma GNU/Linux OS diegimas skirsis funkcijos sintaksė Nustatyti laikmatį Ir TimerProc.
Vykdomasis kodas iškviečia metodą Nustatyti laikmatį, kuriai perduodama funkcija MyTimerProc:
m_uiTimer = ::SetTimer(NULL,0,100,(TIMERPROC)MyTimerProc);
Sukurto laikmačio ID dedamas į kintamąjį m_uiTimer kad vėliau būtų galima jį išjungti.
Funkcija MyTimerProc taip:
VOID CALLBACK MyTimerProc(HWND hwnd, // laikmačio pranešimų lango rankena UINT uMsg, // WM_TIMER pranešimas UINT idEvent, // laikmačio identifikatorius DWORD dwTime // dabartinis sistemos laikas) (jei (!pAsyncEvent) grįžta; wchar_t *who "ComponentNative", *what = L"Laikmatis"; wchar_t *wstime = naujas wchar_t; jei , what, wstime);
Funkcijos esmė ta, kad metodas vadinamas Išorinis įvykis, kuris siunčia pranešimą į 1C: Enterprise sistemą.
Norėdami išplėsti metodo funkcionalumą StartTimer Atlikime šiuos veiksmus:
Metodo kodo keitimas GetNParams kad tai būtų skirta metodui „eMethStartTimer“. grąžinta 1 vertė:
atvejis eMethStartTimer: grįžti 1;
Čia yra metodo kodas CallAsProcį formą:
atvejis 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;
Dabar patikrinkime funkcionalumą. Norėdami tai padaryti, parašysime kodą konfigūracijos valdomame programos modulyje:
kintamasis DemoComp; Procedūra, kai sistema paleidžiama() Connect External Component("...", "DemoVK", External Component Type.Native); DemoComp = New("AddIn.DemoVK.SomeName"); DemoComp.StartTimer(2000); Procedūros pabaiga
Pradėjus konfigūraciją, programa kas 2 sekundes gaus pranešimus, kurie rodo, kad laikmatis veikia tinkamai.

Sąveika su 1C: Enterprise sistema

Norėdami sąveikauti tarp išorinio komponento ir 1C: Enterprise sistemos, IAddInDefBase klasės metodai, aprašyti faile AddInDefBase.h. Mes išvardijame dažniausiai naudojamus:
Klaidos pranešimo generavimas
virtualus bool ADDIN_API AddError (nepasirašytas trumpas wkodas, pastovus WCHAR_T* šaltinis, const WCHAR_T* aprašas, ilgas kodas)
wcode, kodą- klaidų kodai (klaidų kodų sąrašą su aprašymais galite rasti ITS diske)
šaltinis- klaidos šaltinis
descr- klaidos aprašymas
Pranešimo siuntimas į „1C: Enterprise“ sistemą
virtualus bool ADDIN_API išorinis įvykis(WCHAR_T* wszSource, WCHAR_T* wszMessage, WCHAR_T* wszData) = 0;
wszŠaltinis- pranešimo šaltinis
wszMessage- Pranešimo tekstas
wszData- perduoti duomenys
Pranešimų perėmimas atliekamas naudojant išorinio įvykių apdorojimo procedūrą
Išorinio komponento registracija sistemoje 1C: Enterprise
virtualus bool ADDIN_API RegisterProfileAs(WCHAR_T* wszProfileName)
wszProfileName- komponento pavadinimas.
Šių metodų pakanka pilnai VK ir 1C sąveikai. Norėdami gauti duomenis iš išorinio komponento iš 1C: Enterprise sistemos ir atvirkščiai, išorinis komponentas siunčia specialų pranešimą, kurį savo ruožtu perima 1C sistema ir, jei reikia, iškviečia išorinio komponento metodus duomenims perduoti atgal. .

tVarianto duomenų tipas

Keičiant duomenis tarp išorinio komponento ir 1C: Enterprise sistemos, naudojamas duomenų tipas tVariant. Jis aprašytas type.h faile, kurį galima rasti ITS diske:
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 uintt.3; uint16_t uintt2; _t errCode bVal; struct tmVal; pInterfaceVal __VARIANT_NAME_2/*iface*/; ) __VARIANT_NAME_1 matmenų masyvas pvarVal TYPEVAR vt);
Tipas tVariantas yra struktūra, kurią sudaro:
  • mišinys (sąjunga), skirtas tiesiogiai duomenims saugoti
  • duomenų tipo identifikatorius
Apskritai, darbas su tipo kintamaisiais tVariantas vyksta pagal šį algoritmą:
  1. Šiuo metu kintamajame saugomų duomenų tipo nustatymas
  2. Norėdami tiesiogiai pasiekti duomenis, eikite į atitinkamą mišinio lauką
Naudojant tipą tVariantasžymiai supaprastina 1C: Enterprise sistemos ir išorinių komponentų sąveiką

Taikymas

Kataloge „pavyzdžiai“ yra straipsnio pavyzdžių
examples/1 – paleiskite demonstracinį komponentą
pavyzdžiai/2 - nuosavybės sąrašo išplėtimo demonstravimas
pavyzdžiai/3 - metodų sąrašo išplėtimo demonstravimas
Kiekviename kataloge yra VS 2008 projektas ir paruošta 1C konfigūracija.

Straipsnio pavadinime yra frazė „manekenams“. Arbatinuku pirmiausia turėjau omenyje save. Visos mano žinios apie C++ išliko 3-4 metų universiteto lygyje, kai išėjau į kreivąjį 1C kelią. Ir viskas būtų gerai, bet neseniai iškilo užduotis, kuriai reikėjo parašyti išorinį komponentą. Turėjau prisiminti savo prisiminimus ir nuvalyti C++ žinias. Pasirodo, viskas nėra taip baisu. Noriu jums pasiūlyti trumpą išorinių komponentų rašymo įvadą.

Šablono komponentai ITS

ITS diske yra visa dokumentacija apie išorinių komponentų mechanizmą, papildyta projekto pavyzdžiu ir šablonu jūsų pačių plėtrai. Medžiaga vadinama „Išorinių komponentų technologija“. Dokumentacija puiki, bet vis tiek reikia ją suprasti, o laiko, kaip įprasta, mažai. Tiesą sakant, yra tik keli pagrindiniai dalykai, į kuriuos verta atkreipti dėmesį, o visa kita yra nykimas ir tuštybė :)

Reikalingos medžiagos

Norėdami sukurti išorinį komponentą, mums reikės:

  1. Medžiaga „Išorinių komponentų kūrimo technologija“, esanti ITS
  2. Prie medžiagos pridedamas tuščias išorinio komponento šablonas
  3. MS Visual Studio. „Express“ versija yra nemokama ir daugiau nei pakankama mūsų poreikiams.
  4. Turėti pagrindines C++ sintaksės žinias, būtent:
  • Gebėjimas atskirti kintamojo deklaraciją nuo ciklo ar sąlygos
  • Suprasdami, kad grynos formos eilutės C++ neegzistuoja, yra masyvų, kuriems aiškiai reikia rūpintis atmintimi
  • Na, žinoma, reikia mokėti užduotį įgyvendinti nurodyta kalba. Bent jau galimybė iš C++ iškviesti kokią nors trečiosios šalies biblioteką, kuri viską padarys pati.

Pradėkime kasti

Native API dokumentacija yra gana išsami. Apibendrinant tai sakoma taip:

  1. Išorinis komponentas leidžia išplėsti integruotą kalbą nauju objektu (ar keliais). Tie. sukursime klasę, kurią galėsime sukurti naudodami operatorių „Naujas“ ir iškviesime šio objekto metodus iš integruotos kalbos.
  2. Kad mūsų objektas veiktų, platforma su juo „bendraus“ tam tikru protokolu, kurį mes privalome pateikti.
  3. Pats komponento kodas tradiciškai susideda iš dviejų dalių: pirmoji yra paties komponento registracija sistemoje, antroji – naujos klasės veikimas ir sąveika su platforma.

Mes nesigilinsime į įgyvendinimo specifiką, baigiame terminus ir neturime pakankamai kompetencijos. Turime greitai suprasti, kur turime įvesti savo eilutes, kad komponentas veiktų. Norėdami tai padaryti, paimkite komponento šabloną su ITS ir atidarykite jį „Visual Studio“. Šablonas yra išpakuoto archyvo šablonų aplanke. Pažiūrėkime, ką čia turime.

Mus domina failas AddInNative.cpp. Visas suvokimas slypi joje. Jame yra visų būtinų metodų šablonai, kuriuos tereikia šiek tiek pritaikyti. Tačiau paaiškėjo, kad lengviau nenaudoti tuščio šablono kaip pagrindo, o nagrinėti veikiantį pavyzdį. Jame yra keletas naudingų varpelių ir švilpukų, kurie neįtraukti į tuščią šabloną. Kai ateis supratimas, turėsite paimti tuščią šabloną ir patobulinti jį žinant reikalą. Veikiančio komponento pavyzdys yra aplanke example\NativeAPI, o tuščias šablonas yra šablono aplanke.

Atidarykime projektą iš pavyzdinio aplanko ir jame – failą AddInNative.cpp

Pačioje failo pradžioje yra konstantų ir pagalbinių funkcijų deklaracijos. Mus domina šios eilutės:

Mūsų objektas, kaip „tikras“, palaikys metodus, parašytus tiek rusų, tiek anglų kalbomis. Šiuo tikslu rašytiniai savybių ir metodų pavadinimai deklaruojami dviem kalbomis. Mėlynas rėmas skirtas angliškoms, raudonas rusiškoms. Paveikslėlyje parodyta, kad pavyzdyje jau įdiegta daugybė metodų ir savybių. Mūsų užduotis yra juos pašalinti ir įdėti savo.

Eilutė, kurioje deklaruojamas klasės pavadinimas, paryškinta žaliu rėmeliu. Jei atvirai, aš nesupratau, ką tai reiškia. Jei pakeisite, niekas neveiks. Kadangi jie iš pradžių padarė išlygą, kad aš esu „manekenė“, man gali būti atleista. :)

Taigi, jei mūsų objekte yra metodas „RunCalculation“ ir ypatybė „Adresatas“, šį pavadinimą turime apibūdinti atitinkamai g_MethodNamesRu ir g_PropNamesRu masyvuose.

Skambučiai iš 1C kalbos

Taigi, mūsų objekte bus vienas metodas ir skaitymo-rašymo savybė.

Turėkime tokį naudojimo scenarijų:

OurObject = Naujas ("AddIn. MyComponent. DataSender"); MūsųObjektas. Paskirtis = "somemail@server. com“;
MūsųObjektas. RunCalculation(PaymentAmount, "Už komunalines paslaugas");

Yra eilutės savybė ir metodas su skaitiniu ir eilutės parametru. Kad visa tai veiktų, 1C su komponentu atlieka maždaug tokį ryšio protokolą:

Platforma iškviečia iš anksto nustatytas funkcijas mūsų objekte, ji reaguoja į tai ir vykdo jo komandas. Panaši situacija ir su metodais, tik ten, be metodo numerio, prašoma ir parametrų skaičiaus, grąžinamos reikšmės buvimo bei pasirenkamų parametrų buvimo.

Grįžkime prie savo kodo. Siekiant išvengti „stebuklingų skaičių“, „CAddInNative“ klasėje deklaruojami du sąrašai, kurie yra atsakingi už metodų ir savybių skaičių nustatymą. Atidarykime failą CAddInNative.h ir pamatykime juos pačioje pradžioje:

Tuščiame šablone šių sąrašų nėra, taip pat nėra pavyzdžio, kaip atskirti skambučius rusų kalba nuo skambučių ne rusų kalba. Šis metodas yra neprivalomas. Svarbu sekti sąsają, o ar bus pervedimų, ar ne, spręskite jūs.

Unikodo eilutės

Daugelis žmonių tikriausiai žino, kad platforma veikia su dvibaičiais simboliais Unicode formatu. Šablonas šiam tikslui deklaruoja specialų WCHAR_T tipą. Šis tipas yra kelių platformų įvynioklis ir užtikrina tą patį simbolių dydį „Windows“ ir „Linux“. Standartinis wchar_t tipas skirtingose ​​sistemose gali skirtis. Taip pat atkreipkite dėmesį, kad visi eilučių literalai deklaruojami su raidės L priešdėliu. Tai reiškia, kad tokia eilutė yra wchar_t tipo.

Yra paprasta taisyklė: viduje eilutės komponentai apdorojami kaip wchar_t („Linux“ gali būti 4 baitai, „Windows“ - 2), tačiau kai tik perkeliame eilutę į 1C arba gauname iš ten, mums reikia WCHAR_T (griežtai 2 baitai visose sistemose).

Norint konvertuoti vieno tipo eilutę į kitą, šablone pateikiamos pagalbinės funkcijos:

Pirmasis formuoja WCHAR_T iš standartinio wchar_t:

uint32_t convToShortWchar(WCHAR_T** Paskirtis, const wchar_t* Šaltinis, uint32_t len ​​= 0);

Antrasis yra priešingas. Formos wchar_t iš WCHAR_T.

uint32_t convFromShortWchar(wchar_t** Dest, const WCHAR_T* Šaltinis, uint32_t len ​​​​= 0);

Bendraujant su platforma visada naudojamas tik WCHAR_T.

Varianto tipas

Kitas įdomus dalykas yra bendrasis Variant duomenų tipas. Tai leidžia mums bendrauti su 1C kalba, kuri, kaip žinote, nėra įvesta ir kiekvienas jos kintamasis gali turėti bet ką. Šis tipas naudojamas keičiantis reikšmėmis. Į RunCalculation metodą perduodame du parametrus - skaičių ir eilutę. Komponentas gaus dvi Varianto reikšmes. Mūsų pareiga patikrinti tikrąjį jų tipą. Niekas netrukdys komponentui perduoti ne skaičių, o, tarkime, reikšmių lentelę.

Nors, atrodo, aš klystu. Man atrodo, kad vis tiek nepavyks perkelti verčių lentelės į NativeAPI, nes... jo nėra leidžiamų tipų sąraše, tačiau vis dėlto galite perduoti datą, o ne eilutę. Tai taip pat nėra gerai. Turime patikrinti tikrąjį kintamojo, gauto iš 1C, tipą.

Varianto tipas yra paprastas. Tai struktūra, kurios savybės yra skirtingų tipų vertės. Yra tokių savybių kaip DATE, wchar_t, int ir kt. Pagrindinė varianto dalis yra savybė „vt“, kurioje saugomas tikrasis kintamojo tipas ir iš kurios galite tiksliai suprasti, kaip interpretuoti šį variantą. Be to, buvo paskelbta keletas pagalbinių makrokomandų, kurios supaprastina darbą su variantu.

Eikite į esmę

Atrodo, kad viskas su įžanga. Siūlau apsvarstyti išorinio komponento įgyvendinimo pavyzdį. TK bus komponento iš ITS disko pavyzdys. Šiame pavyzdyje aprašomos šios funkcijos:

  • Teksto rodymas pagrindinio lango būsenos juostoje;
  • Išorinio laikmačio įvykio siuntimas;
  • Dvejetainių duomenų perkėlimas į 1C:Enterprise;
  • Savybių įgyvendinimas;
  • Procedūrų įgyvendinimas;
  • Funkcijų įgyvendinimas;

Komponentas turi šią API:

  • Savybės:
    • Įjungta / Įjungta;
    • IsTimer / IsTimerPresent;
    • Metodai:
      • Įjungti;
      • Išjungti/Išjungti;
      • ShowInStatusLine;
      • EnableTimer/StartTimer;
      • Išjungti laikmatį/StopTimer;
      • LoadPicture/LoadPicture;

Išorinis įvykis įvyksta laikmatyje, kurį galima užsiprenumeruoti iš 1C kodo.

Vadovaudamiesi turimomis žiniomis, pažvelkime į komponentą nuo pat pradžių.

Registracijos komponentai

Mūsų objektas yra įgyvendintas kaip atskira C++ klasė, šiuo atveju CAddInNative. Kad 1C matytų mūsų klasę, dll biblioteka turi eksportuoti 3 funkcijas:

  • GetClassObject
  • DestroyObject
  • GaukClassNames

Šiuos eksportuotus duomenis galima pamatyti faile AddInNative.def VisualStudio projekto medyje. Pažvelkime į šių funkcijų kodą:

Paprasčiausias – funkcija GetClassNames – nurodo 1C platformai, kokios klasės yra mūsų komponente. Tegu pataiso C++ guru, man atrodo, kad čia platforma turi atsakyti su C++ klasių pavadinimais, kad galėtų jas importuoti. Būtent tam naudojamas masyvas g_kClassNames, tas, kurio žalias „rėmas“. Specialiai to netikrinau, bet jei jums tiesiog reikia, kad komponentas veiktų, turėtumėte palikti viską taip, kaip yra pavyzdyje. Jau veikia, kol kas nereikia su juo krapštytis.

Taigi, GetClassNames grąžina į platformą klasių pavadinimų masyvą, kuris įgyvendina naudingus išorinio komponento objektus. Mūsų pavyzdyje komponentas grąžins į platformą vieno elemento masyvą, kurio klasės pavadinimas CAddInNative.

Atminkite, kad platforma gaus WCHAR_T tipo reikšmę, o klasės pavadinimas g_kClassNames masyve yra wchar_t tipo. Todėl gipsas atliekamas naudojant aukščiau aptartą pagalbininko funkciją.

Kita funkcija yra GetClassObject. Skambinama, kai įmonės kode įrašėme „Naujas“. Platforma reikalauja, kad sukurtume naują klasės egzempliorių ir grąžintume žymeklį į naują objektą.

Vėlgi, atkreipkite dėmesį, kad pirmasis parametras, kurį platforma mums nurodo, yra tai, kurią klasę sukurti (iš tų, kurias jai suteikė GetClassNames metodas). Kadangi turime tik vieną klasę, šis pavadinimas čia visai nepažymėtas, objektas tiesiog sukuriamas per naują ir grąžinamas per išvesties parametrą pInterface.

Ir paskutinė reikalinga eksporto funkcija yra DestroyObject. Pavadinimas kalba pats už save. Kai objektas platformai nebereikalingas, jį reikia ištrinti. Mums pateikiamas rodyklė į anksčiau sukurtą objektą. Atlaisviname jį naudodami ištrinti ir iš naujo nustatyti nereikalingas nuorodas.

Aprašyti įgyvendinimai yra gana universalūs. Jei mūsų komponentas įgyvendina tik vieną klasę (kaip pavyzdyje), tada šias funkcijas reikia tiesiog nukopijuoti į save. Vienintelė sąlyga – funkcijoje GetClassObject sukurti tinkamą klasę, jei jūsų vardas yra ne CAddInObject, o kažkas kita.

Komponento inicijavimas / nutraukimas

Sukūrus klasę, kuri įgyvendina komponentą, platforma iškviečia šios klasės metodus. Prieš pradedant darbą, platforma mums pasakys „savęs“ objektą, su kuriuo galime pavadinti tam tikrus pačios platformos metodus. Tai atsitinka naudojant Init metodą. Pavyzdyje platformos objektas saugomas m_iConnect kintamajame.

Kitas svarbus metodas yra setMemManager. Leidžia paskirstyti atminties blokus, kuriuos pati platforma atlaisvins. Jis įgyvendinamas taip:

Tiesiog išsaugome žymeklį į atminties tvarkyklę, kurią platforma mums perduoda. Tada su šiuo valdytoju paskirsime atmintį, kurią atlaisvino pati platforma.

Ir vėlgi, kaip ir eksporto funkcijų atveju, inicijavimo būdai yra gana universalūs, juos galima tiesiog nukopijuoti į save ir nesijaudinti dėl jų „užbaigimo“, kol to tikrai reikia.

Naudinga apkrova. Komponentinio objekto metodai ir savybės

Registracija

Na, žinoma, komponentą sukūrėme ne dėl jo inicijavimo, o dėl naudingų funkcijų. Atėjo laikas pažiūrėti, kaip tai įgyvendinama.

Pirmiausia turime užregistruoti objektą, kurį galima sukurti ir iškviesti iš 1C kalbos. Šis objektas užregistruotas RegistrExtensionAs metodu.

Šiuo metodu platformai pranešame savo klasės pavadinimą, nes jis bus matomas iš 1C kalbos. Būtent šiuo pavadinimu mes jį sukursime per „Naujas“. Tokiu atveju objektas bus kuriamas naudojant šį kodą:

ConnectExternalComponent (Failas, "Mano komponentas", Išorinis komponento tipas. Gimtasis);
ObjectComponents = Naujas( „AddIn.MyComponent.AddInNativeExtension“);

Remiantis dokumentacija, atmintį eilutei su klasės pavadinimu skiria atminties tvarkyklė, o pavadinimas įrašomas šiuo adresu - „AddInNativeExtension“. Čia galite neskausmingai parašyti savo vardą. Atkreipkite dėmesį, kad vėl vyksta konversija iš wchar_t į platformą WCHAR_T.

Naudojimas

Kaip jau rašiau aukščiau, platforma ieško komponento įvairių kalbos funkcijų. Ar nurodyta ypatybė egzistuoja, ar ją galima rašyti, ar funkcijos parametras turi numatytąją reikšmę, ar turi grąžinamąją reikšmę ir pan. Jei paimsime anksčiau pateiktą kodo pavyzdį:

OurObject = Naujas( "AddIn.MyComponent.DataSender"); // DataSender yra funkcijos RegisterExtensionAs pavadinimas (aptarta toliau).
MūsųObjektas. Adresatas = " [apsaugotas el. paštas]" ;
MūsųObjektas. Atlikti apskaičiavimą (mokėjimo suma, „Dėl komunalinių paslaugų“);

tada bus atlikta tokia apklausa:

  1. Ar yra turtas „Paskirties vieta“?
  2. Ar palaiko įrašymą?
  3. Ar yra metodas, vadinamas RunCalculation?
  4. Kiek jis turi parametrų?
  5. Ar jis turi grąžinimo vertę
  6. Kokie numatytieji pasirenkamų parametrų nustatymai (jei yra)

Čia naudingiausia pažvelgti į pavyzdį ir patikrinti dokumentaciją. Visų šių apklausų įgyvendinimas yra gana paprastas. Už sąveiką atsakingas visas zoologijos sodas metodų. Visko nenagrinėsiu, jie gana gerai dokumentuoti, be to, juos lengva įgyvendinti. Bus svarstomi tik patys reikšmingiausi momentai, į kuriuos mums, manekenams, reikės sukišti į rankas :). Pagrindinis metodas yra toks: pirmą kartą paminėjus nuosavybę ar metodą, platforma paprašys mūsų ieškoti jo pagal pavadinimą. Turėsime atsakyti unikaliu šios nuosavybės (būdo) numeriu. Visas tolimesnis bendravimas vyks tik skaičiais. Čia padės minėti sąrašai, kuriuose saugomi šie skaičiai.

Savybės

Pirmiausia reikia atsižvelgti į nekilnojamojo turto infrastruktūrą. Platforma prašo nuosavybės egzistavimo naudojant FindProp metodą

Platforma perduoda mums ieškomos nuosavybės pavadinimą WCHAR_T forma. Jis konvertuojamas į wchar_t naudojant pagalbinį metodą, o šio teksto pirmiausia ieškoma anglų kalbos terminais, o tada rusų kalba. Turime grąžinti nuosavybės numerį. Atkreipkite dėmesį, kad čia naudojama funkcija findName pagalbinė priemonė. Jo įgyvendinimas pateiktas pavyzdyje, bet komponento nėra tuščiame šablone. Atrodo tikslinga vilkti jį link savęs, jei planuojate, kad jūsų komponente būtų dvikalbių terminų.

Tada metodas GetPropName atlieka atvirkštinę užduotį, gaudamas nuosavybės pavadinimą pagal jo numerį. Vardo eilutė taip pat priskiriama per įmonės atminties tvarkyklę. Įtariu, kad metodas GetPropName kartu su GetNprops naudojamas, kai derinimo priemonėje plečiame objekto savybes pliuso ženklu. Tada platforma gaus bendrą nuosavybių skaičių ir paprašys pavadinti kiekvieną iš jų.

Kita metodų pora yra IsPropReadable/IsPropWritable. Čia viskas paprasta, prie nurodyto turto numerio turime pasakyti, ar jį galima skaityti/rašyti.

Vertės gaunamos ir įrašomos naudojant GetPropVal/SetPropVal metodus. Čia verta panagrinėti išsamiau. Pradedame dirbti su 1C:Enterprise tipais, o tai reiškia, kad Variant ateina į sceną.

Komponento šablonas apibrėžia pagalbinių makrokomandų rinkinį, kad būtų supaprastintas darbas su variantu. Pirmasis yra vertės tipo patikrinimas. Pavyzdžiui, makrokomandoje TV_VT galite patikrinti / nustatyti reikšmės tipą. Įvardintos konstantos taip pat yra apibrėžtos kiekvienam palaikomam tipui. Šios konstantos ir jų atitiktis 1C:Enterprise tipams yra išvardytos dokumentacijoje.

TV_BOOL makrokomanda gauna Būlio reikšmę iš varianto, su kuriuo galite dirbti. Pagal analogiją gaunamos sveikųjų skaičių reikšmės (TV_INT), eilutės (TV_WSTR) ir kt. Tikslios reikšmės yra kode, jas visada galite pamatyti.

Svarbu tai, kad variantui neužtenka priskirti reikšmę, reikia priskirti ir tikrąjį tipą. Atkreipkite dėmesį į GetPropVal. Be TV_BOOL = tikrosios priskyrimo, yra ir tipo priskyrimas: TV_VT = VTYPE_BOOL. Jei tipas nepriskirtas, platforma nežinos, kokio tipo vertė jai buvo grąžinta. Žinoma, galite sujaukti ir nustatyti netinkamą tipą. Tai dažnai lydi platformos kritimas.

Apibendrinkime tai, kas išdėstyta aukščiau:

Vertę gauname iš parinkties:

bool someKintamasis = TV_BOOL(pVariant);

Įrašykite parametro reikšmę:

TV_VT(pVariantas) = ​​VTYPE_BOOL; // galiojantis duomenų tipas

TV_BOOL(pVariant) = tam tikras Būlio kintamasis; // nustatykite pačią reikšmę

O dabar – kuprotų metodai!

Metodai yra šiek tiek sudėtingesni, tačiau iš esmės jie panašūs į savybes. Pirma, yra lygiai ta pati funkcija ieškoti metodo pagal pavadinimą, gauti bendrą metodų skaičių, gauti pavadinimą pagal skaičių. Tačiau, be aukščiau išvardytų, pridedamos šios funkcijos:

  • Jei metodas gali grąžinti reikšmę, jis gali būti naudojamas „Apskaičiuoti“ ir parašytas priskyrimo operacijos dešinėje 1C kalba. Jei ne, tai yra procedūra, ir tokie dalykai padarys išimtį „Procedūros kaip funkcijos naudojimas“.
  • Metodas turi parametrus. Platforma turi žinoti jų numerį. Jei iškvietimas nurodo daugiau argumentų, nei nurodyta metodo paraše, atsiranda klaida „Per daug parametrų“.
  • Jei metodui perduodama nepakankamai argumentų, kai kurie iš jų gali būti neprivalomi, o jei pasirenkamų parametrų nėra, atsiranda klaida „Nepakankamų parametrų“.
  • Kai iškviečiama, jei tai yra procedūra, tada negali būti grąžinimo vertės. Jei tai funkcija, tada yra grąžinimo reikšmė. Jį taip pat reikia apdoroti.

Yra keletas paprastų metodų, kurių tikslas aiškus iš jų pavadinimų ir iš dokumentacijos. Tai apima HasRetVal, GetNParams, GetParamDefValue. Siūlau jų nesvarstyti, yra daugiau nei pakankamai. Mūsų susidomėjimas bus nukreiptas į tiesioginį naudingosios apkrovos įgyvendinimą. Jis įgyvendinamas CallAsProc ir CallAsFunc metodais. Pirmasis yra atsakingas už skambinimo procedūras, antrasis yra atsakingas už skambinimo funkcijas. Jie skiriasi tuo, kad CallAsFunc turi papildomą išvesties parametrą, kuriame platformai perduosime grąžinamą funkcijos reikšmę.

Skambutis vykdomas taip: platforma perduoda mums iškviesto metodo numerį, faktinių parametrų masyvą ir jų skaičių. Turime išanalizuoti metodo numerį ir pateikti jam pateiktus parametrus. Funkcijos atveju taip pat turime ką nors įrašyti į grąžinamąją reikšmę.

Pavyzdyje metodo numeris analizuojamas jungikliu/atveju ir, priklausomai nuo skaičiaus, vykdoma metodo logika. Norėdami įjungti / išjungti metodus, tiesiog pažymėkite žymimąjį laukelį. „ShowInStatusLine“ metodas yra įdomus. Tai rodo, kas jam buvo perduota 1C:Enterprise lango būsenos juostoje. Norėdami tai padaryti, naudojame m_iConnect platformos ryšio objektą, tą, kuris mums buvo „išduotas“ registruojant komponentą. Visas jo galimybių sąrašas aprašytas dokumentacijoje.

Įdomus momentas. Čia, pavyzdyje, nėra tikrinamas iš 1C gaunamos reikšmės tipas, bet SetStatusLine tiesiog iškviečiama su eilutės dalimi Variant. Įtariu, kad jei iškviesite komponentų metodą iš 1C kalbos, pervesdami ten skaičių ar datą (vietoj eilutės), tada niekas neveiks... Vėlgi, tegul guru pataiso, bet atrodo, kad pwstrVal rodyklė parodys Dievas žino iš kur, jei tai atėjo iš įmonės, tarkime, skaičius, o ne sąžininga eilutė. Skambinus SetStatusLine platforma bandys nuskaityti eilutę iš nežinomo adreso ir greičiausiai sugenda. Geriau visada patikrinti laukiamą tipą. Niekada nežinai.

Pavyzdyje esanti funkcija LoadImage įgyvendinta įdomiau, joje atsižvelgiama į galimybę keistis eilutėmis ir dvejetainiais duomenimis su platforma.

Pirmiausia čia patikrinamas perduotų parametrų skaičius. Jei jų nėra, skambutis laikomas nesėkmingu. Grąžina false, kurią platforma interpretuoja kaip skambučio klaidą.

Toliau čia patikrinamas perduoto parametro tipas. Jei tai siaura eilutė (VTYPE_PSTR), tada naudojama varianto dalis char. Pavyzdyje parašyta paParam->pstrVal, bet galite naudoti TV_STR makrokomandą, ji bus tokia pati, tačiau taip pat bus išlaikytas darbo su parinktimi vienodumas.

Jei tai plati eilutė (VTYPE_PWSTR), tada pirmiausia konvertuojama į wchar_t ir tada į char. Faktas yra tas, kad kelias į failą perduodamas iš 1C kalbos į šį metodą, kuris vėliau naudojamas fopen(char*) funkcijoje. Šiai funkcijai reikalingas char* tipas kaip įvestis, o WCHAR_T bus atsiųstas mums iš platformos. Norint tinkamai veikti, atliekamos eilučių konversijos.

Ir galiausiai, jei tai visai ne eilutė, skambutis laikomas nesėkmingu ir grąžinamas klaidingas.

Atmintį dvejetainiams duomenims skiriame naudodami atminties tvarkyklę. Tai logiška; dvejetainiai duomenys platformoje taps visaverčiu objektu, ir jie turi būti valdomi. Atmintis yra skirta pvarRetValue variantui, kuris yra išorinio komponento funkcijos grąžinama reikšmė.

Be to, visas failas nuskaitomas į paskirtą buferį; Būtinai baito dydis nurodytas strLen parinkties ypatybėje ir VTYPE_BLOB parinkties duomenų tipas. Jei atmintis paskirstyta sėkmingai, mes grąžiname true kaip sėkmingo iškvietimo ženklą visai funkcijai.

Taigi, kai 1C kalba parašyta:

BinaryData = komponentas. Įkelti paveikslėlį(„C:\pic.jpg“);

Bus iškviestas komponento objekto metodas CallAsFunc, perduodamas kelią ir grąžinant dvejetainius duomenis, kaip aprašyta aukščiau.

Jei pavyks, BinaryData kintamajame bus pilnavertis 1C kalbos objektas. Kai ji išeis į taikymo sritį, platforma išlaisvins visą jo užimtą atmintį. Štai kodėl jis buvo paskirstytas per atminties tvarkyklę.

Išvada

Istoriją parašė arbatinukas manekenams, todėl greičiausiai joje gausu terminologinių netikslumų. Tačiau šio straipsnio tikslas yra greitai supažindinti su išoriniais komponentais. Jei jums reikia greitai pagaminti komponentą per trumpą laiką, be nereikalingų rūpesčių, be ilgų diskusijų, tikiuosi, kad šis straipsnis jums padės. Jei dėl kokių nors mano klaidų jaučiatės blogai, kaip C++ guru, praneškite man komentaruose ir mes jas ištaisysime.

Ačiū už dėmesį.

  • Pamoka

Įvadas

Šiame straipsnyje pateikiama idėja, kaip išoriniai komponentai veikia sistemoje 1C: Enterprise.
Bus parodytas išorinio komponento kūrimo procesas, skirtas 1C: Enterprise sistemos versijai 8.2, veikiančiai Windows OS su failo veikimo režimu. Ši parinktis naudojama daugelyje sprendimų, skirtų mažoms įmonėms. VK bus įdiegtas C++ programavimo kalba.

Išoriniai komponentai „1C: Enterprise“

„1C: Enterprise“ yra išplečiama sistema. Sistemos funkcionalumui išplėsti naudojami išoriniai komponentai (EC). Kūrėjo požiūriu, VC yra išorinis objektas, turintis savybių ir metodų, taip pat galintis generuoti įvykius, kuriuos apdoroja „1C: Enterprise“ sistema.
Išoriniai komponentai gali būti naudojami sprendžiant daugybę problemų, kurias sunku ar net neįmanoma įgyvendinti programavimo kalba, integruota į 1C: Enterprise. Visų pirma, ši klasė apima užduotis, kurioms reikalinga žemo lygio sąveika su operacine sistema, pavyzdžiui, norint dirbti su konkrečia įranga.
Sistema 1C: Enterprise išoriniams komponentams kurti naudoja dvi technologijas:
  • naudojant Native API
  • naudojant COM technologiją
Atsižvelgiant į pateiktus apribojimus, skirtumas tarp dviejų aukščiau paminėtų technologijų yra nereikšmingas, todėl svarstysime vaizdo žaidimų kūrimą naudojant Native API. Jei reikia, įgyvendintus patobulinimus galima pritaikyti kuriant kompiuterių programinę įrangą naudojant COM technologiją, o taip pat su nedideliais pakeitimais pritaikyti naudoti sistemoje 1C: Enterprise su kitomis veikimo galimybėmis, išskyrus failo veikimo režimą.
VK struktūra
Išorinis 1C: Enterprise sistemos komponentas pateikiamas DLL bibliotekos pavidalu. Bibliotekos kodas apibūdina palikuonių klasę IComponentBase. Sukurta klasė turi apibrėžti metodus, atsakingus už išorinio komponento funkcijų įgyvendinimą. Nepaisyti metodai bus išsamiau aprašyti toliau, kai pateikiama medžiaga.

Demonstracinio VK paleidimas

Užduotis:
  1. Surinkite išorinį komponentą, tiekiamą su ITS prenumerata ir skirtą parodyti pagrindines išorinio komponento mechanizmo galimybes 1C.
  2. Prijunkite demonstracinį komponentą prie 1C konfigūracijos
  3. Įsitikinkite, kad deklaruotos funkcijos veikia tinkamai
Kompiliacija
Demonstracinė VK yra ITS prenumeratos diske „/VNCOMP82/example/NativeAPI“ kataloge.
Norėdami sukurti demonstracinį VC, naudosime Microsoft Visual Studio 2008. Kitos šio produkto versijos nepalaiko naudojamo Visual Studio projekto formato.


Atidarykite projektą AddInNative. Į projekto nustatymus įtraukiame katalogą su antraščių failais, reikalingais projektui sukurti. Pagal numatytuosius nustatymus jie yra ITS diske, esančiame kataloge /VNCOMP82/įtraukti.
Konstravimo rezultatas yra failas /bind/AddInNative.dll. Tai yra sudaryta biblioteka, skirta prisijungti prie 1C konfigūracijos.
VK prijungimas prie 1C konfigūracijos
Sukurkime tuščią 1C konfigūraciją.
Toliau pateikiamas valdomos programos modulio kodas.
kintamasis DemoComp; Procedūra, kai sistema paleidžiama () Prijunkite išorinį komponentą ("...\bind\AddInNative.dll", "DemoVK", išorinio komponento tipas. Native); DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); Procedūros pabaiga
Jei paleidžiant 1C konfigūraciją nebuvo pranešta apie klaidą, VK buvo sėkmingai prijungtas.
Vykdant aukščiau pateiktą kodą, konfigūracijos visuotiniame matomumo lange atsiranda objektas DemoComp, kurios savybės ir metodai yra apibrėžti išorinio komponento kode.
Integruoto funkcionalumo demonstravimas
Patikrinkime demonstracinės VK funkcionalumą. Norėdami tai padaryti, pabandykime nustatyti ir perskaityti kai kurias ypatybes, iškviesti kai kuriuos VK metodus, taip pat gauti ir apdoroti VK pranešimą.
ITS diske pateiktoje dokumentacijoje nurodomos šios demonstracinės VC funkcijos:
  1. Valdymo komponento objekto būsena
    Metodai: Įjungti, Išjungti
    Savybės: Įskaitant
  2. Laikmačio valdymas
    Kas sekundę komponentas siunčia pranešimą „1C: Enterprise“ sistemai su parametrais Komponentas, Laikmatis ir sistemos laikrodžio skaitiklio linija.
    Metodai: StartTimer, StopTimer
    Savybės: Yra laikmatis
  3. Metodas ShowInStatusLine, kuri būsenos eilutėje rodo metodui perduotą tekstą kaip parametrus
  4. Metodas Įkelti paveikslėlį. Įkelia vaizdą iš nurodyto failo ir perkelia jį į 1C: Enterprise sistemą dvejetainių duomenų pavidalu.
Įsitikinkite, kad šios funkcijos veikia. Norėdami tai padaryti, paleiskite šį kodą:
kintamasis DemoComp; Procedūra, kai sistema paleidžiama() ConnectExternalComponent(...); DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); DemoComp.Disable(); Report(DemoComp.Enabled); DemoComp.Enable(); Report(DemoComp.Enabled); DemoComp.StartTimer(); Procedūros pabaigos procedūra Išorinio įvykio apdorojimo (šaltinis, įvykis, duomenys) ataskaita (šaltinis + " " + įvykis + " " + duomenys); Procedūros pabaiga
Konfigūracijos vykdymo rezultatas parodytas paveikslėlyje


Skydelyje „Pranešimai“ rodomi metodų iškvietimų rezultatai DemoComp.Disable() Ir Demo.Comp.Enable(). Tolesnėse to paties skydelio eilutėse pateikiami iš VK gautų pranešimų apdorojimo rezultatai - Šaltinis, Renginys Ir Duomenys atitinkamai.

Pasirinktinis išorinio komponento pavadinimas

Užduotis: pakeiskite išorinio komponento pavadinimą į savavališką.
Ankstesnėje dalyje buvo naudojamas identifikatorius AddInNativeExtension, kurios reikšmė nebuvo paaiškinta. Tokiu atveju AddInNativeExtension– tai plėtinio pavadinimas.
VK kodas apibrėžia metodą RegistruotisPlėtinysAs, grąžindamas pavadinimą į sistemą 1C: Enterprise, kuris reikalingas vėlesniam VK registravimui sistemoje. Rekomenduojama nurodyti identifikatorių, kuris tam tikru mastu atskleidžia išorinio komponento esmę.
Čia yra visas metodo kodas RegistruotisPlėtinysAs su pakeistu plėtinio pavadinimu:
bool CAddInNative::RegisterExtensionAs(WCHAR_T** wsExtensionName) ( wchar_t *wsExtension = L"SomeName"; int iActualSize = ::wcslen(wsExtension) + 1; WCHAR_T* tikslas = 0; if (m_m_Memory_Memory ((void**)wsExtensionName, iActualSize * sizeof(WCHAR_T))) ::convToShortWchar(wsExtensionName, iActualSize) return false;
Pateiktame pavyzdyje VK pavadinimas pakeistas į SomeName. Tada prisijungdami prie VK turite nurodyti naują pavadinimą:
DemoComp = New("AddIn.DemoVK.SomeName");

Išplečiamas VK savybių sąrašas

Užduotis:
  1. Ištirti VK savybių įgyvendinimą
  2. Pridėkite eilutės tipo skaitymo / rašymo ypatybę
  3. Pridėkite skaitymo / rašymo eilutės ypatybę, kurioje saugomas paskutinio ypatybių rinkinio duomenų tipas. Nustatant nuosavybės vertę neatliekama jokių veiksmų

Kad nustatytų kuriamo komponento ypatybes, kūrėjas AddInNative.cpp bibliotekos kode turi įdiegti šiuos metodus:
GetNprops
Grąžina šio plėtinio ypatybių skaičių, 0, jei ypatybių nėra
FindProp
Grąžina nuosavybės, kurios pavadinimas perduotas parametruose, serijos numerį
GetPropName
Grąžina nuosavybės pavadinimą pagal serijos numerį ir perduotą kalbos identifikatorių
GetPropVal
Grąžina turto vertę nurodytu eilės numeriu
SetPropVal
Nurodo turto vertę nurodytu eilės numeriu
IsPropReadable
Grąžina nuosavybės skaitomumo vėliavėlę su nurodytu eilės numeriu
IsPropWritable
Grąžina nuosavybės įrašymo vėliavėlę su nurodytu eilės numeriu


Panagrinėkime aukščiau pateiktų klasės metodų įgyvendinimą CAddInNative.
Demonstracinėje VC apibrėžiamos 2 savybės: Įskaitant Ir Yra laikmatis (Įjungta Ir IsTimerPresent).
Visuotinėje bibliotekos kodo apimtyje yra apibrėžti du masyvai:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent"); static wchar_t *g_PropNamesRu = (L"Įjungta", L"Yra laikmatis");
kuriuose saugomi rusiški ir angliški nuosavybės pavadinimai. Antraštės faile AddInNative.h sąrašas yra apibrėžtas:
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropLast // Visada paskutinis );
ePropIsEnabled Ir ePropIsTimerPresent, turinčios atitinkamai reikšmes 0 ir 1, naudojami savybių serijos numeriams pakeisti reikšmingais identifikatoriais. ePropLast, kurio reikšmė yra 2, naudojama ypatybių skaičiui gauti (naudojant GetNprops metodą). Šie pavadinimai naudojami tik komponento kode ir nepasiekiami išorėje.
Metodai FindProp ir GetPropName atlieka masyvo paieškas g_PropNames Ir g_PropNamesRu.
Norėdami išsaugoti bibliotekos modulio laukų reikšmes, CAddInNative klasėje yra ypatybių, kuriose saugoma komponento ypatybių reikšmė. Metodai GetPropVal Ir SetPropVal grąžinti ir atitinkamai nustatyti šių savybių vertę.
Metodai IsPropReadable Ir IsPropWritable ir grįžti tiesa arba klaidinga, priklausomai nuo perduodamo turto eilės numerio pagal taikymo logiką.
Norėdami pridėti pasirinktinę nuosavybę, turite:

  1. Pridėkite prie masyvų pridedamos nuosavybės pavadinimą g_PropNames Ir g_PropNamesRu(failas AddInNative.cpp)
  2. Išvardinti Rekvizitas(failas AddInNative.h) anksčiau ePropLast pridėkite pavadinimą, kuris vienareikšmiškai identifikuoja pridedamą nuosavybę
  3. Tvarkykite atmintį savybių reikšmėms saugoti (sukurkite modulio komponentų laukus, kuriuose saugomos atitinkamos reikšmės)
  4. Pakeiskite metodus GetPropVal Ir SetPropVal sąveikauti su atmintimi, skirta ankstesniame veiksme
  5. Vadovaudamiesi taikymo logika, pakeiskite metodus IsPropReadable Ir IsPropWritable
1, 2, 5 punktų paaiškinti nereikia. Išsamią informaciją apie šių žingsnių įgyvendinimą galite rasti perskaitę straipsnio priedą.
Pavadinkime testo savybes Testas Ir Tipo patikrinimas atitinkamai. Tada, atlikdami 1 veiksmą, turime:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent", L"Test", L"TestType"); static wchar_t *g_PropNamesRu = (L"Įjungta", L"Yra laikmatis", L"Test", L"Tipo patikra");
Perdavimas Rekvizitas atrodys taip:
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropTest1, ePropTest2, ePropLast // Visada paskutinis );
Norėdami žymiai supaprastinti kodą, naudosime STL C++. Ypač darbui su stygomis WCHAR, prijungkime biblioteką wstring.
Norėdami išsaugoti metodo reikšmę Testas, mes apibrėžiame klasėje CAddInNative privačioje srityje:
stygos testas1;
Norėdami perkelti eilutės parametrus tarp 1C: Enterprise ir išorinių komponentų, naudojama 1C: Enterprise atminties tvarkyklė. Pažvelkime į jo darbus atidžiau. Funkcijos naudojamos atitinkamai paskirstyti ir atlaisvinti atmintį AllocMemory Ir Laisva atmintis apibrėžta faile „ImemoryManager.h“. Jei reikia perduoti eilutės parametrą 1C: Enterprise sistemai, išorinis komponentas turi skirti jam atmintį iškviesdamas funkciją AllocMemory. Jo prototipas atrodo taip:
virtualus bool ADDIN_API AllocMemory (tuščia** pAtmintis, nepasirašytas ilgas ulCountByte) = 0;
Kur pAtmintis- rodyklės, į kurią bus patalpintas paskirtos atminties srities adresas, adresas,
ulCountByte- skirtos atminties srities dydis.
Eilutės atminties paskirstymo pavyzdys:
WCHAR_T *t1 = NULL, *testas = L"TEST_STRING"; int iActualus dydis = wcslen(test1)+1; m_iMemory->AllocMemory((void**)&t1, iActualSize * sizeof(WCHAR_T)); ::convToShortWchar(&t1, test1, iActualSize);
Kad būtų patogiau dirbti su eilučių duomenų tipais, apibūdinsime funkciją wstring_to_p. Jis kaip parametras gauna wstring eilutę. Funkcijos rezultatas yra užpildyta struktūra tVariantas. Funkcijos kodas:
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; grąžinti tiesa)
Tada atitinkamas atvejis skirsnis jungiklis pareiškimo metodas GetPropVal bus tokia forma:
atvejis ePropTest1: wstring_to_p(test1, pvarPropVal); pertrauka;
Metodas SetPropVal:
case ePropTest1: if (TV_VT(varPropVal) != VTYPE_PWSTR) return false; testas1 = std::wstring((wchar_t*)(varPropVal -> pstrVal)); pertrauka;
Norėdami įgyvendinti antrąją savybę, apibrėžiame klasės lauką „CaddInNative“.
uint8_t last_type;
kuriame išsaugosime paskutinės perduotos reikšmės tipą. Norėdami tai padaryti, pridėkite komandą prie CaddInNative::SetPropVal metodo:
paskutinis_tipas = TV_VT(varPropVal);
Dabar, kai prašome perskaityti antrojo turto vertę, mes grąžinsime vertę paskutinis_tipas, ko reikalauja paskirta užduotis.
Patikrinkime atliktų pakeitimų funkcionalumą.
Norėdami tai padaryti, pateiksime 1C konfigūracijos išvaizdą taip:
kintamasis DemoComp; Procedūra, kai sistema paleidžiama () Prijunkite išorinį komponentą ("...", "DemoVK", išorinio komponento tipas. Native); DemoComp = New("AddIn.DemoVK.SomeName"); DemoComp.TypeCheck = 1; Report(String(DemoComp.TypeCheck)); DemoComp.Test = "Vasya"; Report(String(DemoComp.Test)); DemoComp.Test = "Petya"; Report(String(DemoComp.Test)); Report(String(DemoComp.TypeCheck)); Procedūros pabaiga
Po paleidimo gausime pranešimų seką:
3
Vasja
Petras
22

Antrasis ir trečiasis pranešimai yra ankstesniame veiksme nustatytos nuosavybės nuskaitymo rezultatas. Pirmame ir antrame pranešimuose yra paskutinio ypatybių rinkinio tipo kodas. 3 atitinka sveikojo skaičiaus reikšmę, 22 – eilutės reikšmę. Byloje nustatytas tipų ir jų kodų atitikimas tipai.h, kuris yra ITS diske.

Metodų sąrašo išplėtimas

Užduotis:
  1. Išplėskite išorinio komponento funkcionalumą šiomis funkcijomis:
  2. Ištirkite išorinių komponentų metodų diegimo būdus
  3. Pridėkite funkcijos metodą Funkcija1, kuris kaip parametras naudoja dvi eilutes („Parameter1“ ir „Parameter2“). Rezultatas yra tokia eilutė: „Tikrinimas. 1 parametras, 2 parametras
  4. Įsitikinkite, kad atlikti pakeitimai veikia.

Norėdami apibrėžti kuriamo komponento metodus, kūrėjas AddInNative bibliotekos kode turi įdiegti šiuos metodus:
GetNMethods, FindMethod, GetMethodName
Sukurta gauti atitinkamą metodų skaičių, ieškokite metodo numerio ir pavadinimo. Panašus į atitinkamus savybių metodus
GetNParams
Grąžina metodo parametrų skaičių su nurodytu eilės numeriu; jei metodo su šiuo numeriu nėra arba jis neturi parametrų, grąžina 0
GetParamDefValue
Grąžina numatytąją nurodyto metodo nurodyto parametro reikšmę
HasRetVal
Grąžina vėliavėlę, kad egzistuoja metodas su nurodyta eiline grąžinimo verte: teisinga metodams su grąžinimo reikšme ir klaidinga kitaip
CallAsProc
klaidinga, įvyksta vykdymo klaida ir 1C: Enterprise modulio vykdymas nutraukiamas. Atmintį parametrų masyvei skiria ir išleidžia 1C: Enterprise.
CallAsFunc
Vykdo metodą su nurodytu eilės numeriu. Jei metodas grįžta klaidinga, įvyksta vykdymo klaida ir 1C: Enterprise modulio vykdymas nutraukiamas. Atmintį parametrų masyvei skiria 1C: Enterprise. Jei grąžinama reikšmė yra eilutė arba dvejetainis duomenų tipas, komponentas priskiria atmintį funkcijai AllocMemory atminties tvarkyklę, įrašo ten duomenis ir išsaugo šį adresą atitinkamame struktūros laukelyje. 1C: Įmonė atlaisvins šią atmintį paskambinusi Laisva atmintis.
Išsamus metodų aprašymas, įskaitant parametrų sąrašą, yra išsamiai aprašytas dokumentacijoje, pateiktoje ITS diske.
Panagrinėkime aukščiau aprašytų metodų įgyvendinimą.
Komponento kode yra apibrėžti du masyvai:
static wchar_t *g_MethodNames = (L"Įgalinti", L"Išjungti", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture"); static wchar_t *g_MethodNamesRu = (L "Įgalinti", L "Išjungti", L "ShowInStatusLine", L "StartTimer", L "StopTimer", L "LoadImage");
ir išvardijimas:
enum Methods ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethLast // Visada paskutinis );
Jie naudojami funkcijose GetNMethods, FindMethod Ir GetMethodName, pagal analogiją su savybių aprašymu.
Metodai GetNParams, GetParamDefValue, HasRetVal padargo jungiklis, priklausomai nuo perduodamų parametrų ir programos logikos, grąžina reikiamą reikšmę. Metodas HasRetVal jo kode yra tik metodų, galinčių grąžinti rezultatą, sąrašas. Už juos jis grįžta tiesa. Visiems plieno metodams grąžinama klaidinga.
Metodai CallAsProc Ir CallAsFunc yra tiesiogiai vykdomas metodo kodas.
Norėdami pridėti metodą, kurį galima iškviesti tik kaip funkciją, turite atlikti šiuos išorinio komponento šaltinio kodo pakeitimus:
  1. Pridėkite metodo pavadinimą prie masyvų g_MethodNames Ir g_MethodNamesRu(failas AddInNative.cpp)
  2. Pridėkite reikšmingą metodo identifikatorių prie Metodų sąrašo (failas AddInNative.h)
  3. Pakeiskite funkcijos kodą GetNParams pagal programos logiką
  4. Jei reikia, pakeiskite metodo kodą GetParamDefValue, jei norite naudoti numatytąsias metodo parametrų reikšmes.
  5. Atlikite funkcijos pakeitimus HasRetVal
  6. Pakeiskite funkcijų logiką CallAsProc arba CallAsFunc, įdėdami ten tiesiogiai vykdomą metodo kodą
Pateikiame masyvus g_MethodNames Ir g_MethodNamesRu, taip pat sąrašas Metodaiį formą:
static wchar_t *g_MethodNames = (L"Įgalinti", L"Išjungti", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture", L"Test"); static wchar_t *g_MethodNamesRu = (L "Įgalinti", L "Išjungti", L "ShowInStatusLine", L "StartTimer", L "StopTimer", L "LoadPicture", L "Test");

Enum metodai ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethTest, eMethLast // Visada paskutinis );
Redaguojame funkciją GetNprops kad būtų pateiktas „Test“ metodo parametrų skaičius:
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; )
Pakeiskime funkciją:
bool CAddInNative::GetParamDefValue(const long lMethodNum, const long lParamNum, tVariant *pvarParamDefValue) (TV_VT(pvarParamDefValue)= VTYPE_EMPTY; switch(lMethodNum) (case: eMethIntuseLcase: MethStartTimer: atvejis eMethStopTimer: atvejis eMethTest : / / Pagal numatytuosius nustatymus nėra parametrų reikšmių: return false;
Dėl pridėtos linijos
atvejis eMethTest:
jei trūksta vieno ar daugiau argumentų, atitinkami parametrai turės tuščią reikšmę ( VTYPE_EMPTY). Jei jums reikia numatytosios parametro reikšmės, turėtumėte ją nustatyti skyriuje eMethTest funkcijų jungiklio teiginys CAddInNative::GetParamDefValue.
Kadangi bandymo metodas gali grąžinti reikšmę, turite pakeisti funkcijos kodą HasRetVal:
bool CAddInNative::HasRetVal(const long lMethodNum) ( switch(lMethodNum) ( case eMethLoadPicture: case eMethTest: return true; default: return false; ) return false; )
Ir pridėkite vykdomąjį metodo kodą prie funkcijos CallAsFunc:
bool CAddInNative::CallAsFunc(const long lMethodNum, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) ( ... std::wstring s1, s2; switch(lMethodNum) ( case eMethLoadTesticture:MethLoadT; if (!lSizeArray || !paParams) return s1 = (paParams) -> pwstrVal (paParams+1) -> pwstring_to_p(std::wstring(s1+s2), pvarRetValue; ;
Sukompiliuokime komponentą ir perkelkime konfigūracijos kodą į formą:
kintamasis DemoComp; Procedūra, kai sistema paleidžiama() Connect External Component("...", "DemoVK", External Component Type.Native); DemoComp = New("AddIn.DemoVK.SomeName"); juosta = DemoComp.Test("Sveiki", "Pasaulis!"); Ataskaita(per); Procedūros pabaiga
Paleidę konfigūraciją, gausime pranešimą: "Sveikas, pasauli!", kuris rodo, kad metodas sėkmingai veikė.

Laikmatis

Užduotis:
  1. Išstudijuokite laikmačio įgyvendinimą demonstraciniame VK
  2. Modifikuokite „StartTimer“ metodą, įtraukdami į parametrus galimybę perduoti laikmačio atsako intervalą (milisekundėmis)
  3. Įsitikinkite, kad atlikti pakeitimai veikia.

WinAPI galite naudoti pranešimą, kad galėtumėte dirbti su laiku WM_TIMER. Šis pranešimas bus išsiųstas jūsų programai tokiu laiko intervalu, kurį nustatėte kurdami laikmatį.
Norėdami sukurti laikmatį, naudokite funkciją Nustatyti laikmatį:
UINT SetTimer(HWND hWnd, // lango aprašas UINT nIDevent, // laikmačio identifikatorius (skaičius) UINT nElapse, // delsa TIMERPROC lpTimerFunc); // rodyklė į funkciją
Operacinė sistema išsiųs pranešimą WM_TIMERį programą su argumente nurodytu intervalu nElapse(milisekundėmis). Paskutiniame parametre galite nurodyti funkciją, kuri bus vykdoma kiekvieną kartą, kai suveikia laikmatis. Šios funkcijos antraštė turėtų atrodyti taip (pavadinimas gali būti bet koks):
negalioja __stdcall TimerProc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Panagrinėkime laikmačio įgyvendinimą demonstraciniame VC.
Kadangi svarstome išorinio komponento Windows OS šeimai kūrimo procesą, laikmačio įdiegimo kitose operacinėse sistemose nesvarstysime. Visų pirma GNU/Linux OS diegimas skirsis funkcijos sintaksė Nustatyti laikmatį Ir TimerProc.
Vykdomasis kodas iškviečia metodą Nustatyti laikmatį, kuriai perduodama funkcija MyTimerProc:
m_uiTimer = ::SetTimer(NULL,0,100,(TIMERPROC)MyTimerProc);
Sukurto laikmačio ID dedamas į kintamąjį m_uiTimer kad vėliau būtų galima jį išjungti.
Funkcija MyTimerProc taip:
VOID CALLBACK MyTimerProc(HWND hwnd, // laikmačio pranešimų lango rankena UINT uMsg, // WM_TIMER pranešimas UINT idEvent, // laikmačio identifikatorius DWORD dwTime // dabartinis sistemos laikas) (jei (!pAsyncEvent) grįžta; wchar_t *who "ComponentNative", *what = L"Laikmatis"; wchar_t *wstime = naujas wchar_t; jei , what, wstime);
Funkcijos esmė ta, kad metodas vadinamas Išorinis įvykis, kuris siunčia pranešimą į 1C: Enterprise sistemą.
Norėdami išplėsti metodo funkcionalumą StartTimer Atlikime šiuos veiksmus:
Metodo kodo keitimas GetNParams kad tai būtų skirta metodui „eMethStartTimer“. grąžinta 1 vertė:
atvejis eMethStartTimer: grįžti 1;
Čia yra metodo kodas CallAsProcį formą:
atvejis 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;
Dabar patikrinkime funkcionalumą. Norėdami tai padaryti, parašysime kodą konfigūracijos valdomame programos modulyje:
kintamasis DemoComp; Procedūra, kai sistema paleidžiama() Connect External Component("...", "DemoVK", External Component Type.Native); DemoComp = New("AddIn.DemoVK.SomeName"); DemoComp.StartTimer(2000); Procedūros pabaiga
Pradėjus konfigūraciją, programa kas 2 sekundes gaus pranešimus, kurie rodo, kad laikmatis veikia tinkamai.

Sąveika su 1C: Enterprise sistema

Norėdami sąveikauti tarp išorinio komponento ir 1C: Enterprise sistemos, IAddInDefBase klasės metodai, aprašyti faile AddInDefBase.h. Mes išvardijame dažniausiai naudojamus:
Klaidos pranešimo generavimas
virtualus bool ADDIN_API AddError (nepasirašytas trumpas wkodas, pastovus WCHAR_T* šaltinis, const WCHAR_T* aprašas, ilgas kodas)
wcode, kodą- klaidų kodai (klaidų kodų sąrašą su aprašymais galite rasti ITS diske)
šaltinis- klaidos šaltinis
descr- klaidos aprašymas
Pranešimo siuntimas į „1C: Enterprise“ sistemą
virtualus bool ADDIN_API išorinis įvykis(WCHAR_T* wszSource, WCHAR_T* wszMessage, WCHAR_T* wszData) = 0;
wszŠaltinis- pranešimo šaltinis
wszMessage- Pranešimo tekstas
wszData- perduoti duomenys
Pranešimų perėmimas atliekamas naudojant išorinio įvykių apdorojimo procedūrą
Išorinio komponento registracija sistemoje 1C: Enterprise
virtualus bool ADDIN_API RegisterProfileAs(WCHAR_T* wszProfileName)
wszProfileName- komponento pavadinimas.
Šių metodų pakanka pilnai VK ir 1C sąveikai. Norėdami gauti duomenis iš išorinio komponento iš 1C: Enterprise sistemos ir atvirkščiai, išorinis komponentas siunčia specialų pranešimą, kurį savo ruožtu perima 1C sistema ir, jei reikia, iškviečia išorinio komponento metodus duomenims perduoti atgal. .

tVarianto duomenų tipas

Keičiant duomenis tarp išorinio komponento ir 1C: Enterprise sistemos, naudojamas duomenų tipas tVariant. Jis aprašytas type.h faile, kurį galima rasti ITS diske:
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 uintt.3; uint16_t uintt2; _t errCode bVal; struct tmVal; pInterfaceVal __VARIANT_NAME_2/*iface*/; ) __VARIANT_NAME_1 matmenų masyvas pvarVal TYPEVAR vt);
Tipas tVariantas yra struktūra, kurią sudaro:
  • mišinys (sąjunga), skirtas tiesiogiai duomenims saugoti
  • duomenų tipo identifikatorius
Apskritai, darbas su tipo kintamaisiais tVariantas vyksta pagal šį algoritmą:
  1. Šiuo metu kintamajame saugomų duomenų tipo nustatymas
  2. Norėdami tiesiogiai pasiekti duomenis, eikite į atitinkamą mišinio lauką
Naudojant tipą tVariantasžymiai supaprastina 1C: Enterprise sistemos ir išorinių komponentų sąveiką

Taikymas

Kataloge „pavyzdžiai“ yra straipsnio pavyzdžių
examples/1 – paleiskite demonstracinį komponentą
pavyzdžiai/2 - nuosavybės sąrašo išplėtimo demonstravimas
pavyzdžiai/3 - metodų sąrašo išplėtimo demonstravimas
Kiekviename kataloge yra VS 2008 projektas ir paruošta 1C konfigūracija.

Šis straipsnis skirtas darbui su išoriniais komponentais, būtent jų prijungimui. Šiuo metu, siekiant išplėsti „1C Enterprise“ galimybes, naudojamos dvi išorinių komponentų technologijos:

  • 1 Native API naudojimas
  • 2 Naudojant COM technologiją
Šiame straipsnyje nusprendžiau pabrėžti darbą su Native API komponentais.
Taigi, pradėkime nuo paprastų iki sudėtingų:
Ištrauka iš ITS

1. Tarkime, kad mūsų VK yra tam tikrame disko kataloge:

Galima naudoti „Tirkiame kliente (įprasta taikymas)“;

Tai paprasčiausias darbo su Native komponentu pavyzdys. Atkreipkite dėmesį, kad tokio tipo komponentams nereikia registruotis sistemoje, o tai labai supaprastina administravimą.

2. Aukščiau aptartas pavyzdys visai nerealus. Dažniausiai komponentas dedamas į maketą. Makete turi būti ZIP archyvas su komponentų failais ir MANIFEST.xml failas
Aprašo failo pavyzdys:

3. Dirbdami su plonu ir žiniatinklio klientu, būtinai naudokite metodą.
Citata iš ITS:

Paaiškinimas:
%APPDATA%\1C\1Cv82\ExtCompT- Thick ir Thin klientų komponentų diegimo katalogas.
%APPDATA%\Roaming\Mozilla\Extensions- katalogo (mano atveju) plėtiniai, skirti Mozilla FF/
Naudojant metodą Nustatyti išorinį komponentą (), priklausomai nuo naudojamo kliento, plėtiniai bus išpakuoti į atitinkamą katalogą.

Išorinio komponento diegimo procedūros pavyzdys:

Įdiekite išorinį komponentą- metodas turėtų būti iškviestas tik pradinio komponento diegimo metu ir tuo atveju, kai reikia atnaujinti įdiegtą komponento versiją.

Esant plonam ir storam klientui:
Pakanka iš naujo atlikti išorinio komponento diegimo operaciją naudojant metodą Įdiekite išorinį komponentą().

Jei žiniatinklio klientas atnaujina komponentą:

  • Būtina pašalinti papildinį naudojant darbo su žiniatinklio naršyklės priedais mechanizmą (Mozilla FF)
  • Naudokite metodą Įdiekite išorinį komponentą
Norėdami prijungti VK, galite atlikti šią procedūrą:

Jei komponentas nebuvo įdiegtas, bus taikoma išimtis.

2. Pasitaiko atvejų, kai komponentą reikia įdiegti iš laikinosios saugyklos (failas gautas iš trečiosios šalies šaltinio, išorinis apdorojimas), tokiu atveju pirmieji parametrai metoduose Prijungti išorinį komponentą ir įdiegti išorinį komponentą yra laikinai saugomo archyvo adresas. Žemiau pateikiamas galimas pavyzdys, kaip tai veikia:

&OnClient VariableAddressArchiveComponent; &OnClient kintamasis komponentas; &OnClient procedūra OnOpen(Failure) // adresas, yra eilutė (navigacijos nuoroda į dvejetainius ZIP archyvo duomenis // laikinojoje saugykloje) ComponentArchiveAddress = GetArchiveAddressInTemporaryStorage(); EndProcedure // WhenOpen() &OnServer // metodai ConnectExternalComponent, SetExternalComponent kaip // kaip pirmąjį parametrą gali priimti eilutę formatu "navigation link" // (URL į išorinį komponentą, supakuotą ZIP archyve, formatu, panašiu į // GetNavigationLink ). Funkcija GetArchiveAddressInTemporaryStorage()ProcessingObject = FormAttributesValue("ProcessingObject"); Archyvo nuoroda = PlaceInTemporaryStorage(ProcessingObject.GetLayout("MIKO_phone_IP"), naujas unikalus identifikatorius); ReturnLinkToArchive; EndFunction // GetArchiveAddressInTemporaryStorage() &OnClient // Procedūra turėtų būti iškviesta tik vieną kartą, jei komponentas dar neįdiegtas // arba jį reikia atnaujinti Procedūra InstallComponent(Command) Bandymas įdiegtiExternalComponent(ArchiveComponentAddress); Išimčių ataskaita ("Nepavyko įdiegti išorinio komponento."); EndAttempt; Procedūros pabaiga // InstallComponent() &OnClient // pagrindinė komponento inicijavimo procedūra Procedūra Initialize(Command) Bandymas prijungti išorinį komponentą(ComponentArchiveAddress,"Comp",ExternalComponentType.Native); Komponentas = New("AddIn.Comp.MIKO_phone_IP"); Exception Report ("Inicijuojimo išimtis. Komponentas gali būti dar neįdiegtas."); EndAttempt; Procedūros pabaiga