Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2006.05.07;
Скачать: [xml.tar.bz2];

Вниз

Как правильно зарегить плагин к 1С ?   Найти похожие ветки 

 
ANB ©   (2006-04-12 17:45) [0]

На основе заготовки MASTER и SAMPLE ничего не работало.
Взял SAMPLE2 (который ролики крутит), переделал для себя - работает.
Запустил на другом компе - не находит CLSID.
Все понятно - не зарегился COM сервер.
Снес у себя ветки в реестре - воспризвел ошибку.
Начал ломать кусочками.
Исправил GUID класса TAddInVideo - работает.
Снес проигрыватель и все, что его касается - работает.
Изменяю строку :
initialization
 TComObjectFactory.Create(ComServer, TAddInOfficeReport, Class_AddInOfficeReport,
   "AddInVideo", "", ciMultiInstance, tmApartment);
на на
 TComObjectFactory.Create(ComServer, TAddInOfficeReport, Class_AddInOfficeReport,
   "AddInMyPluggin", "", ciMultiInstance, tmApartment);
еще работает, но если после этого сменить GUID - вопит, что нет интерфейса IInitDone.
Меняю GUID, ставлю на место AddInVideo - снова все работает.
Вывод - где то ломаю регистрацию. Еще зачем то тащится форма AddInDoc, которая мне совсем не нужна (со своей регистрацией и TLB).

Кто знает - какие минимальные телодвижения нужно сделать, чтобы плагин в 1С нормально регистрился и загружался ?


 
sniknik ©   (2006-04-12 17:53) [1]

а он у тебя по правилам 1С (для 7ки там муторно както) или простой COM обьект?
если простой то regsvr32 AddInVideo.dll (ну или что у тебя за dll там получилась)

если по правилам, то ничего не надо, 1С сама умеет такие регистрить (только не помню функцию ;)


 
sniknik ©   (2006-04-12 17:56) [2]

> только не помню функцию
может эти LoadAddIn и CreateObject (похожи ;)


 
ANB ©   (2006-04-12 17:58) [3]


> sniknik ©   (12.04.06 17:53) [1]

По правилам 1С. Действительно, очень мутно, но как сделать просто и при этом получать от 1С ссылку на ее экземпляр (в Init приезжает) ?
1С не регистрит, она заружает плагин :
ЗагрузитьВнешнююКомпоненту(Файл_Компоненты)
А компонента при этом должна сама регистряться.


 
ANB ©   (2006-04-12 17:59) [4]

Если плохо регистряется - то потом ничего не работает.


 
sniknik ©   (2006-04-12 18:34) [5]

> при этом получать от 1С ссылку на ее экземпляр
просто не знаю, только по 1C-овски "парится"

> 1С не регистрит, она заружает плагин :
а по моему то же самое и делает, регистрит... (убрать все, "загрузить" и посмотреть в реестре...)

> ЗагрузитьВнешнююКомпоненту
LoadAddIn это она и есть, "по иностранному" ;)

> Если плохо регистряется - то потом ничего не работает.
значит чегото не так... скачай нормальный, сторонний пример, 1С-совские (с книжкой "технология создания внешних компонент") у меня ни один нормально не работал... во всех глюки какиенибудь да были. (на hare.ru (вроде), раньше неплохие лежали... сейчас сайт не открывается... почемуто, толи название подзабыл толи сайту каюк ;)


 
ANB ©   (2006-04-13 09:07) [6]


> скачай нормальный, сторонний пример, 1С-совские

Сейчас поищу в яндексе. И у наших поспрошаю.
У меня из родных 1С-ских примеров завелся только тот, что с роликами. Но стоит его чуток изменить - и он ломается.

Реестр я смотрел - регится класс по имени и гуиду, трешь ветки - все ломается.


 
tesseract ©   (2006-04-13 10:39) [7]

anb - мой
класс нужен. Там кое-что даже документировано :-)


> если по правилам, то ничего не надо, 1С сама умеет такие
> регистрить (только не помню функцию ;)


Из моей возможно будущей статьи :-)

Описание процессов, происходящих при загрузке компоненты

Загрузка компоненты :
ЗагрузитьВнешнююКомпонету - загружает и инициализирует компоненту из библиотеки
1 -  Регистрируется HKCR "имя сервера.Имя класса". Имя сервера указанное в ComServer.SetServerName.
    и предположительно должно быть AddIn. Имя  класса(ов)  - указанное в ID 100 ресурсов файла.
2 - Попытка создания  Com-объекта;
  -> Если ID 100 отсутсвует/ неправилен, вы получите "отсутсвует CLSID".
Регстрация компонеты закончена, начиная с этого шага можно использовать ПодключитьВнешнююКомпоненту
{создаётся оъект интерфейса iInitDone}
3 - Вызывается init(pConn:IDispatch).
    Происходит инициализация объекта, инициализация используемых интерфейсов.
    -> Вызовом RegisterProfileAs(const bstrProfileName: WideString) происходит регистрация ключа реестра, где храняться наши настройки.
    -> По умолчанию они -> Имя нашего модуля + "_profile"
    -> Происходит вызов метода moduleinit .
4 - Вызывается GetInfo(var pInfo: PSafeArray) - выяcняется версия OLE
{создаётся объект интефейса IlanguageExtender}
5 - Вызывается RegisterExtensionAs(var bstrExtensionName: WideString)
 Компонета регистрируется как "Имя класса" в 1с.
6 - Вызывается создание Com-объекта уже как "addin.Имя класса", проверяется возможность создания зарегистрированного объекта
 -> Если RegisterExtensionAs указан не тот объект, вы получите "отсутсвует CLSID".
{создаётся объект интерфеса ISpecifyPropertyPage }
7 - вызывается GetPages(out Pages: TCAGUID) (при использовании ISpecifyPropertyPage)
   выясняется наличие страниц свойств.
 -> При регистрации компоненты, как торгового оборудования, вы увидите сообщение о том, что страница свойств объекта доступна
 -> В меню "сервис" -> "параметры".

ПодключитьВнешнююКомпоненту("Addin.имя Класса")
 загружает и инициализирует компоненту с CLSID переданным, как параметр. Есть предположение, что ЗагрузитьВнешнююКомпоненту вызывает эту
 функцию начиная с шага 3.

 СоздатьОбъект("Addin.имя Класса")
 практически равносильно ЗагрузитьВнешнююКомпоненту.
  Но выполняются только шаги  2,3,5,7.

 Конец инициализации

 При выгрузке компоненты вызывается метод DONE.
 Вызывается он при закрытии обработке в которой использован СоздатьОбъект, и при закрытии 1с (ИМХО только если использован ILanguageExtender)
  -> вызывается ModuleDone.

 Вызов Функции/процедуры :
  Данная последовательность вызывается каждый раз при вызове процедуры!
  -> Из чего следует наличие почти полноценного "RTTI".

 1 - Вызов FindMethod(const bstrMethodName: WideString;  var plMethodNum: Integer) с именем метода.
   Метод может быть, как русским так и английским.
 2 - Вызов GetNParams(lMethodNum: Integer;  var plParams: Integer)
   Выяснение кол-ва аргументов процедуры/функции.
 3 - Вызов HasRetVal(lMethodNum: Integer;  var pboolRetValue: Integer)
   Выяснение - процедура или функция это у нас.
 4 - Вызов GetParamDefValue(lMethodNum, lParamNum: Integer;  var pvarParamDefValue: OleVariant);
    Функция вызывается, если в функцию передали меньше значений, чем вернула GetNParams.
    Функция вызывается по разу за каждый неуказанный параметр.
 5. CallAsFunc или CallAsProc соотвественно.

 Получение/запись свойства объекта
1. Вызов FindProp(const bstrPropName: WideString;  var plPropNum: Integer) с именем свойства.
   Метод может быть, как русским так и английским.
2. Если свойство присваивается, то вызывается    IsPropWritable(lPropNum: Integer;  var pboolPropWrite: Integer)
   -> Если свойство считывается, то НИЧЕГО не вызвается, прошу обратить внимание!!!!!
   -> Все свойства по умолчанию являются "Для чтения".
   -> Если вы хотите иметь его только для чтения в TcustomAddin  имеется заглушка на сей счёт.
3. Вызывается GetPropVal(lPropNum: Integer;  var pvarPropVal: OleVariant)
     или SetPropVal(lPropNum: Integer;  var varPropVal: OleVariant)

Работа с асинхронным событием
 1. Компонета вызовом ExternalEvent помещает событие в очередь ожидания
 2. Если в текущей (активной!) обработке/документе/отчёте модуле  присутсвует функция ОбработкаВнешнегоСобытия
    то ей передаётся управление.
 3. Выполянется интерпритация события


 
ANB ©   (2006-04-14 11:08) [8]


> tesseract ©   (13.04.06 10:39) [7]

Текс. Собрал всю доку, плюс эту рекомендацию.
Взял пустой шаблон MASTER и начал делать.

Что сделал :
1. Сохранил проект под новым именем
2. Это же имя объявил константой.
3. Заменил GUID в unit PropPage
4. Заменил GUID в unit AddInObj;
5. Запихнул константу с именем в :
- раздел initialization
- метод RegisterExtensionAs
- метод Init в регистрацию профиля (ничего про него не понял)
6. В ресурс проекта добавил строку с ID = 100 и именем проекта.

Исходники запостю ниже.

Что получил :

В 1С вызываю :


           Файл_Компоненты = "OfficeReport.dll";
Сообщить (Файл_Компоненты);
Если ЗагрузитьВнешнююКомпоненту(Файл_Компоненты) = 0 Тогда
 Сообщить("ошибка загрузки");
 Возврат;
КонецЕсли;


По всем методам плагина повтыкал отладочные сообщения (отладчик потом подрублю, когда надо будет логику отлаживать).

Вижу :
1. Вызван раздел инициализации (прошла регистрация, в нем менял имя в
TComObjectFactory.Create(ComServer,TAddInObject,CLSID_AddInObject,
                        AddIn_Name, "V7 AddIn 2.0", ciMultiInstance);
)
2. Вызван Init (в нем менял только имя профиля)
3. Вызван GetInfo (только вставил ShowMessage)
4. Вызван Done
1С вываливает ошибку :
Ошибка при инициализации объекта из компоненты C:\Program Files\1Cv77\1SBDemo\OfficeReport.dll

Ничего не понимаю - что я делаю не так ?


 
ANB ©   (2006-04-14 11:12) [9]

Постю куски исходника :

Объявление констант :



// Здесь нужно описать строки, которые станут рассширением языка в 1С

resourcestring
    strWordReport         = "Word_Report,Отчет_В_Ворд";

const

    // Этот GUID нужно обязательно перегенерить
    CLSID_AddInObject : TGUID = "{E3FB6F4A-11AD-4B3C-954F-9EAA72B9D4D6}";

    // В эту константу нужно записать имя плагина
    // Проще, если оно будет совпадать с именем проекта
    AddIn_Name = "OfficeReport";
    // Это же имя нужно еще записать в ресурс проекта в строку с ID = 100.

type

// Номера свойств
TProperties = ( LastProp );

// Номера методов
TMethods = ( methWordReport, LastMethod );



 
ANB ©   (2006-04-14 11:13) [10]

Метод Init :



function TAddInObject.Init(pConnection: IDispatch): HResult; stdcall;
var iRes : Integer;
begin

ShowMessage("Init");

    // pConnect := pConnection;

    pErrorLog := nil;
    pConnection.QueryInterface(IID_IErrorLog,pErrorLog);

    pEvent := nil;
    pConnection.QueryInterface(IID_IAsyncEvent,pEvent);

    pProfile := nil;
    iRes := pConnection.QueryInterface(IID_IPropertyProfile,pProfile);
    if (iRes = S_OK) then
       begin
            pProfile.RegisterProfileAs(AddIn_Name + "_Profile");
            if (LoadProperties() <> True) then
              begin
                Init := E_FAIL;
                Exit;
              end;
       end;

    pStatusLine := nil;
    pConnection.QueryInterface(IID_IStatusLine,pStatusLine);

    Init := S_OK;
end;



 
ANB ©   (2006-04-14 11:13) [11]

Метод GetInfo :



function TAddInObject.GetInfo(var pInfo: PSafeArray{(OleVariant)}): HResult; stdcall;
var  varInfo : OleVariant;
begin
    ShowMessage("GetInfo");
    varInfo := "2000";
    PutNParam(pInfo, 0, varInfo);
    GetInfo := S_OK;
end;



 
ANB ©   (2006-04-14 11:14) [12]

Раздел инициализации :



initialization

ShowMessage("Регистрация");

ComServer.SetServerName("AddIn");

TComObjectFactory.Create(ComServer,TAddInObject,CLSID_AddInObject,
                        AddIn_Name, "V7 AddIn 2.0", ciMultiInstance);

end.



 
ANB ©   (2006-04-14 11:29) [13]

Такс. Попробовал запустить DLL на другом компе - срабатывает только раздел инициализации, потом ругнулась, что не найден интерфейс IInitDone. Убил ветку в реестре - начала ругаться, что не найден CLSID.


 
ANB ©   (2006-04-14 11:30) [14]

Убил ветку AddIn.OfficeReport у себя на компе - тоже пошла ошибка "отсутствует CLSID"


 
ANB ©   (2006-04-14 12:21) [15]

Убил дополнительно в реестре ветку с GUID плагина - вернуалсь первоначальная ситуация. Ща закиплю.


 
ANB ©   (2006-04-14 13:53) [16]

Укоротил имя плагина - не помогло.


 
ANB ©   (2006-04-17 09:49) [17]


> tesseract ©   (13.04.06 10:39) [7]

Помоги !!!


 
ANB ©   (2006-04-17 12:05) [18]

Внимательно читал исходник и трассировал выполнение - выяснил, что 1С сама не выполняет регистрацию. DLL регит сама себя при выполнении раздела инициализации.


 
Сергей М. ©   (2006-04-17 13:34) [19]


> читал исходник


Неужели исходник 1С ?!


 
tesseract ©   (2006-04-17 15:39) [20]


> Помоги !!!


А в мэйл слабо????


iRes := pConnection.QueryInterface(IID_IPropertyProfile,pProfile);
   if (iRes = S_OK) then
      begin
           pProfile.RegisterProfileAs(AddIn_Name + "_Profile");
           if (LoadProperties() <> True) then
             begin
               Init := E_FAIL;
               Exit;
             end;
      end;


Выруби это или хотя-бы E_FAIL не возвращай.


> Убил ветку AddIn.OfficeReport у себя на компе - тоже пошла
> ошибка "отсутствует CLSID"


Такое бывает при отсутсвии SetServerName. или id100.

Рабочий код инициализации:

ComServer.SetServerName("AddIn");
 TComObjectFactory.Create(ComServer,tInterBase,   Class_InterbaseAddin,
   "InterBase", "interbase addin class", ciSingleInstance, tmApartment);


 
ANB ©   (2006-04-17 16:37) [21]


> Сергей М. ©   (17.04.06 13:34) [19]

Не, примеров.


> tesseract ©   (17.04.06 15:39) [20]

Я вообще коментил все получение интерфейсов.

Короче, кое как получилось.
1. Взял рабочий плагин (был на работе)
2. Аккуратно вытер все чужое и добавил свое
3. Переименовал проект в имя плагина
4. Изменил имена плагина в 2-х местах - инициализации и RegisterExtensionAs
5. Изменил имя профиля
6. Сменил GUID
7. Скопировал под новым именем ресурс проекта и строку с ID 100 исправил на имя плагина.
8. Перекомпилял все
9. Почистил реестр (пришлось с утра прожку написать для почистки)
И все заработало. Сравнил работающий проект с примером 1С - разницы не нашел.

Единственное - таки нарвался на граблю, при которой 1С остается в списке задач.


 
ANB ©   (2006-04-17 16:37) [22]


> tesseract ©   (17.04.06 15:39) [20]

Выслать рабочий код для анализа (для статьи) ?


 
tesseract ©   (2006-04-17 17:10) [23]


> Выслать рабочий код для анализа (для статьи) ?

У меня примеров ~ 10-20. рабочих :-)


> Единственное - таки нарвался на граблю, при которой 1С остается
> в списке задач.


Не правильно задан DONE. Наверно не освободил какие-нибудь ресурсы.


 
ANB ©   (2006-04-17 17:40) [24]


> Не правильно задан DONE. Наверно не освободил какие-нибудь
> ресурсы.

Не. Это я в своем обработчике намутил, дергая AppDispatch. Надо разбираться и чинить.
Отключаешь - все работает как надо.


 
ANB ©   (2006-04-17 17:41) [25]


> tesseract ©   (17.04.06 17:10) [23]

Кстати, как правильно достать и освободить AppDispatch ?


 
tesseract ©   (2006-04-18 09:55) [26]


> Кстати, как правильно достать и освободить AppDispatch ?

В смысле как избавится от интерфейса который тебе 1c вернул? в null его :-)


 
ANB ©   (2006-04-18 12:25) [27]


> tesseract ©   (18.04.06 09:55) [26]

Просто нулл не помогал.

Короче - вот так работает :

Application_1C : Variant;

....
try
       Application_1C := Null;
       Application_1C := Variant(pConnect).AppDispatch;
// pConnect я заранее сохранил в Init как IDispatch
       IDispatch(Application_1C)._AddRef;

....
     finally
      Application_1C := Null;
     end;

Методы Init и Done такие :



function TAddInObject.Init(pConnection : IDispatch): HResult; stdcall;
var iRes : Integer;
begin

    pConnect := pConnection;

    pErrorLog := nil;
    pConnect.QueryInterface(IID_IErrorLog,pErrorLog);

    pEvent := nil;
    pConnect.QueryInterface(IID_IAsyncEvent,pEvent);

    pProfile := nil;
    iRes := pConnect.QueryInterface(IID_IPropertyProfile,pProfile);
    if (iRes = S_OK) then
       begin
            pProfile.RegisterProfileAs("OfficeReport_Profile");
            if (LoadProperties() <> True) then
              begin
                Init := E_FAIL;
                Exit;
              end;
       end;

    pStatusLine := nil;
    pConnect.QueryInterface(IID_IStatusLine,pStatusLine);

    Init := S_OK;
end;

function TAddInObject.Done: HResult; stdcall;
var n : Integer;
begin

    SaveProperties();

    if (pErrorLog <> nil) then begin
      pErrorLog._Release();
      pErrorLog := nil;
    end;

    if (pEvent <> nil) then begin
      pEvent._Release();
      pEvent := nil;
    end;

    if (pProfile <> nil) then begin
      pProfile._Release();
      pProfile := nil;
    end;

    if (pStatusLine <> nil) then begin
      pStatusLine._Release();
      pStatusLine := nil;
    end;

    if (pConnect <> nil) then begin
     n := pConnect._Release();
     pConnect := nil;
     // ShowMessage("Done = " + IntToStr(n));
     if (n > 0) then begin
      ShowMessage("Ошибка : Не произошло освобождение интерфейса 1С. Осталось ссылок : "
      + IntToStr(n));
     end;
    end;

    Done := S_OK;
end;



Ну и Application_1C передаю внутрь своих процедур только по ссылке (через var).



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2006.05.07;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.01 c
2-1145031684
KygECHuK
2006-04-14 20:21
2006.05.07
Освобождение памяти


2-1145540171
cardexc
2006-04-20 17:36
2006.05.07
БД, ошибка добавления


2-1145517328
K_VAL
2006-04-20 11:15
2006.05.07
ShowMessage - нажатие клавиши Enter


9-1128282128
3d[Power]__
2005-10-02 23:42
2006.05.07
OGG via directsound


2-1145382665
Lex Luthor
2006-04-18 21:51
2006.05.07
Dspack





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский