Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.05.07;
Скачать: CL | DM;

Вниз

Как правильно зарегить плагин к 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;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.048 c
15-1144918326
_!
2006-04-13 12:52
2006.05.07
Контроль доступа к файлам и папкам


2-1145365284
ZZZ_ZZZ
2006-04-18 17:01
2006.05.07
Формат веществ. чисел


15-1145001382
eukar
2006-04-14 11:56
2006.05.07
небольшая задача по матстатистике


15-1144877931
Volf_555
2006-04-13 01:38
2006.05.07
Как в Internet Explorer отображать php-скрипты?!


2-1145371762
Beni
2006-04-18 18:49
2006.05.07
HexToBin(), BinToHex()