После защиты паролем через библиотеку, макрос перестал работать

Автор Konstanta, 7 февраля 2020, 10:54

0 Пользователи и 1 гость просматривают эту тему.

Kadet

Вообще-то голова уже кругом. Ничего не понимаю в этих библиотеках и их загрузках.
Делаю проверку загрузки библиотеки:
If ThisDatabaseDocument.BasicLibraries.isLibraryLoaded("MyLibrary") Then
msgbox("Библиотека MyLibrary загружена")
TestMac() 'Макрос во встроенной и , как показывает проверка, загруженной библиотеке
Else
msgbox("Библиотека MyLibrary НЕ загружена")
End If

Получаю: "Библиотека MyLibrary загружена"
И тут же ошибка на TestMac(): "Переменная не определена".
Как же "не определена" если этот макрос в этой самой загруженной библиотеке?
Бред какой-то. Куда тогда загружается эта библиотека если макросы из неё не работают, не определяются?

Чего я не догоняю?

mikekaganski

#46
В этом конкретном месте что есть ThisDatabaseDocument? Куски кода без контекста бесполезны. Это текущий компонент? или это не текущий компонент, а просто некий открытый документ, сохранённый Вами в глобальную переменную?

Макросы загружаются в менеджер библиотек документа. При работе макроса имена ищутся в текущем модуле, в текущей библиотеке, в библиотеках, загруженных в менеджере текущего документа, и в библиотеках глобального менеджера. Имена никогда не ищутся в менеджерах других открытых документах. И загрузить библиотеки из других документов, емнип, нельзя. При использовании механизмов типа invoke макросы выполняются в контексте того документа, который был указан при вызове invoke (например, в ответе 43 это ThisComponent, чей ScriptProvider задействован; если вместо ThisComponent использовать ThisDatabaseDocument, то будет задействован, возможно, другой контекст).
С уважением,
Михаил Каганский

Kadet

Цитата: mikekaganski от 17 августа 2020, 22:17В этом конкретном месте что есть ThisDatabaseDocument?
Именно это:
Цитата: mikekaganski от 17 августа 2020, 22:17просто некий открытый документ, сохранённый Вами в глобальную переменную?
Это глобальная переменная, которая таскает ссылку на БД (головной документ).
Поясню, чтобы не было вырвано из контеста. Вот тело макроса, который при подключении внешней библиотеки (DBLibrary), которая является полным дубликатом внутренней библиотеки (MyLibrary), прекрасно работает.
Sub RegisterOpenDoc()
Dim oDoc, sDoc, lName, lUrl, oLibs, oLib, oLibs1, oLib1, oLibs2, oLib2
'ON LOCAL ERROR GOTO Error54:
oDoc = ThisComponent
REM Загружаем библиотеки.
If ThisDatabaseDocument.Title="Cyanopica.odb" Then
ThisDatabaseDocument.BasicLibraries.loadLibrary("MyLibrary")
Else
GlobalScope.BasicLibraries.loadLibrary("DBLibrary")
End If

If GetDocType(oDoc)="sCalc" Then
calcInsnall(oDoc)
SearchDoc()
ElseIf GetDocType(oDoc)="sWriter" Then
gDoc = oDoc
oDoc = SearchCalc()
calcInsnall(oDoc)
End If
Error54:
TabPageStart()
RegisterMouseClickHandler
' ON LOCAL ERROR GOTO 0
End Sub

Однако же при подключении внутренней библиотеки (MyLibrary) все макросы в ней становятся невидимыми.
Эта процедура запускается при загрузке формы "ОСНОВНАЯ", которая запускается при загрузке самого файла БД.
oDoc = ThisComponent - ловит документ, который система на данный момент считает активным. Это может быть WriteDocument или CalcDocument, причём какой конкретно будет пойман в oDoc - одному Богу известно и туда попеременно попадает то один, то другой. И отрегулировать этот процесс я не смог. Всё это происходит потому что одновременно загружается сама форма (WriteDocument) и IFrame-вложение в неё (CalcDocument). И этот макрос отлавливает их и записывает ссылки на них в глобальные переменные (gDoc или calcDoc (записывается в другом макросе, к которому обращается этот макрос)).
Так вот, при подключении внутренней библиотеки на все макросы, которые запускаются после строки If GetDocType(oDoc)="sCalc" Then выскакивает ошибка, что эти функции или процедуры не определены. Все они находятся в этой самой внутренней библиотеке (MyLibrary)

WriteDocument - имеет в Parent ссылку на головной документ БД - ThisDatabaseDocument и соответственно наследует и все библиотеки.
CalcDocument - открывается как отдельный документ, как бы не связанный ни с формой, в которую он вложен, ни с БД соответственно. В  Parent - Null

Kadet

Цитата: mikekaganski от 17 августа 2020, 22:17Макросы загружаются в менеджер библиотек документа.
Спасибо за пояснения. Значит придётся обходить эту ситуацию. Хотел добавить базу как ссылку в менеджер ThisComponent, но что-то не получается.

kompilainenn

Kadet, мне кажется у вас с архитектурой того, что вы пишете, какая-то беда. Возможно можно иначе решить проблему, взглянуть по другому как-то?
Поддержать разработчиков LibreOffice можно тут, а наш форум вот тут

Kadet

Цитата: kompilainenn от 17 августа 2020, 23:44
Kadet, мне кажется у вас с архитектурой того, что вы пишете, какая-то беда. Возможно можно иначе решить проблему, взглянуть по другому как-то?
Я тоже прихожу именно к этому выводу, но придумать пока ничего толкового не могу.
Попробовал вынести этот проблемный кусок кода в отдельный макрос, положил его во внутреннюю библиотек. А к нему обратился посредством invoke. Снова ошибки сыпет. Разбираюсь.
Эх, жаль, что не получается подключить эту библиотеку как ссылку к ThisComponent посредством oDoc.BasicLibraries.createLibraryLink("MyLibrary", "//Cyanopica/MyLibrary", ReadOnly). Не пойму как ссылку правильно на библиотеку написать. Ошибку ввода-вывода даёт.

mikekaganski

Так вот Вы и загружайте все библиотеки в момент, когда инициализируете систему - до вызова OpenForm0, тогда же, когда инициализируете ThisDatabaseDocument. И затем везде вместо попытки вызова ProtectedLibrary.aModule.Function сделайте что-то в этом духе:

Function CallProtectedFunction(fName As String, fArgs())
    Dim scriptUri
    scriptUri = "vnd.sun.star.script:MyLibrary." & fName & "?language=Basic&location=document"
    ' Используем ThisDatabaseDocument, где все эти методы видны
    CallProtectedFunction = ThisDatabaseDocument.scriptProvider.getScript(scriptUri).invoke(fArgs, Array(), Array())
End Sub

...

Dim result
' Имя функции - это имя модуля точка имя Function или Sub
result = CallProtectedFunction("TabPage.TestMac", Array())
...
С уважением,
Михаил Каганский

bk

//Только теперь при нажатии кнопки макроса выходит сообщение вида:
"Ошибка сценария при выполнении сценария Basic vnd.sun.star.script:VBAProject.Module1.Текст?language=Basic&location=document."

Автору (Konstanta): по-видимому, у Вас эта ошибка происходит из-за того, что Вы запускаете макрос из незагруженной, да ещё и защищенной библиотеки. Сначала надо загрузить библиотеку (вспомогательным макросом из библиотеки Standart я сделал в Вашем документе), затем снять защиту с нее, и запустить нужный макрос. Примерно вот так можно запустить:
Sub CallLoadLib()
Dim oLibs
oLibs = BasicLibraries
If oLibs.hasByName("VBAProject") Then
oLibs.LoadLibrary("VBAProject")
  If oLibs.isLibraryPasswordProtected("VBAProject") Then
   If NOT oLibs.isLibraryPasswordVerified("VBAProject") Then
     oLibs.verifyLibraryPassword("VBAProject", "333") 'ваш пароль здесь
   End If
     If oLibs.isLibraryPasswordVerified("VBAProject") Then
       Текст 'ваш макрос в "VBAProject"
     End If
  End If
End If
End Sub
Это запустит макрос на исполнение.
Однако, после этого пользователь всё же может зайти в редактор и посмотреть пароль (т.к. пароль на библиотеку верифицирован). Т.е. нужна ещё строчка кода, которая выгружает библиотеку или что-то в этом роде (не нашел пока что именно можно сделать). Возможно галиматья получилась, но это навскидку, особо времени нет с кодом сидеть, извини.

bk

кстати, если после загрузки библиотеки (у меня  - после oLibs.LoadLibrary("VBAProject")) добавить строку кода:

oLibs.setLibraryReadOnly("VBAProject", True),

то пользователи код макроса могут видеть, а изменить не могут (опять же навскидку - у меня не получилось).

Дополнение: но в этом случае пользователи могут зайти в библиотеку, где вспомогательный макрос и заменить True на False (снять режим Только чтение). Промежуточное решение:
в исполняемом макросе библиотеки VBAProject добавить строку oLibs.setLibraryReadOnly("Standard", True), т.е. заблокировать изменения и в этой библиотеке. Но тогда Вам нужно (как мне видится) иметь свой документ под рукой (строго Ваш и строго под Вашим паролем), в котором макрос на снятие режима Только чтение в указанных библиотеках.
Такие вот "костыли".... чтобы хотя бы начать работать.

Kadet

Цитата: mikekaganski от 18 августа 2020, 08:55Так вот Вы и загружайте все библиотеки в момент, когда инициализируете систему - до вызова OpenForm0, тогда же, когда инициализируете ThisDatabaseDocument. И затем везде вместо попытки вызова ProtectedLibrary.aModule.Function сделайте что-то в этом духе:
Я перенёс инициализацию в первичный макрос, как вы говорите. Однако, уже в этом макросе (который обсуждаем), почему-то всё равно какие-то глюки появляются. Даже глобальную библиотеку приходится повторно загружать уже в этом макросе (даже при коннекте к глобальной библиотеке DBlibrary).

Сделал вариант обхода этой фигни. По Питоньяку сварганил макрос переноса библиотеки из внутри в глобал и подгрузил её. Вроде бы, за мелкими ньюансами, такая модель работает. А при закрытии эту библиотеку удаляю. НО... сам прекрасно понимаю, что это "костыль хромой собаке". Этот обход на крайний самый крайний случай.

mikekaganski

Насчёт появляющихся глюков - это да, Ваш проект - стресс-тест для Бейсика в ЛО.
Например, использование global Raskroy() в модуле с таким же именем. Оно не работает. Это, конечно, баг. Не знаю пока как править, а тем временем посоветовал бы Вам от такого воздержаться.

Но написать то, что Вы написали в ответе #54 - это ничего не написать. Нет предмета (примера). И да, я знаю, что писал это не один раз ... что ж делать, если приходится повторять снова.
С уважением,
Михаил Каганский

sokol92

Михаил, большое спасибо за новые разъяснения!

Kadet (к сожалению, не знаю имени), получается, что если код приложения для LO не ограничивается одним документом, то есть смысл код (Basic) приложения держать именно в глобальных библиотеках. При этом, естественно, необходимо продумать политику обновления версий. Можно задействовать для "эталонной" версии, например, URI (URL) ресурсы.
Зона ответственности кода внутри документа (если потребуется) - обработка событий документа, пользовательские функции для ячеек Calc и т.д.
Владимир.

Kadet

Цитата: mikekaganski от 18 августа 2020, 08:55И затем везде вместо попытки вызова ProtectedLibrary.aModule.Function сделайте что-то в этом духе:
Ну, если заменить простенький код:
If GetDocType(oDoc)="sCalc" Then
calcInsnall(oDoc)
SearchDoc()
ElseIf GetDocType(oDoc)="sWriter" Then
gDoc = oDoc
oDoc = SearchCalc()
calcInsnall(oDoc)
End If
TabPageStart()

На такую казябру:
If CallProtectedFunction("dlgALL.GetDocType", oDoc)="sCalc" Then
CallProtectedFunction("ListenerSet.calcInsnall", oDoc)
CallProtectedFunction("dlgALL.SearchDoc", oDoc)
ElseIf CallProtectedFunction("dlgALL.GetDocType", oDoc)="sWriter" Then
gDoc = oDoc
oDoc = CallProtectedFunction("dlgALL.SearchCalc", "")
CallProtectedFunction("ListenerSet.calcInsnall", oDoc)
End If
CallProtectedFunction("TabPage.TabPageStart", "")

То в принципе работает. Но, однако, как-то слишком геморойно, громоздко. К тому же у меня не только в этом макросе идут перехлёстные обращения между библиотекам. Однако, спасибо! Это ещё один вариант обходного пути.

Однако, вот, что мне таки не понятно. Грубо говоря, у меня сейчас на одном компе - две базы. Одна - в которой я работаю, с подключением глобальной библиотеки DBLibrary, другая с подключением внутренней библиотеки MyLibrary.
Так вот, если даже без всяких переработок кода (как было изначально) вначале открыть первую, то и открытие второй не вызывает ошибок. А вот если открывать только вторую, с внутренней библиотекой, и тогда выскакивают эти обсуждаемые ошибки.
И в моём понимании получается, что вторая база просто использует макросы внешней библиотеки, подгруженной в первую базу. Не понятно. Если либра разделяет менеджеры макросов даже внутри одной базы, то почему тогда она спокойно хватает макросы из совершенно другого документа.

Таки не въеду как же всё это происходит.

mikekaganski

да нет же, это не макросы другого документа, это макросы глобального менеджера. Вы в *глобальный менеджер* загружаете макросы из глобальных библиотек.
С уважением,
Михаил Каганский

Kadet

Цитата: sokol92 от 18 августа 2020, 14:16Kadet (к сожалению, не знаю имени), получается, что если код приложения для LO не ограничивается одним документом, то есть смысл код (Basic) приложения держать именно в глобальных библиотеках. При этом, естественно, необходимо продумать политику обновления версий. Можно задействовать для "эталонной" версии, например, URI (URL) ресурсы.
Именно так и по тем же причинам в рабочей БД и выбрана политика внешних библиотек. Для простых юзеров в рабочую станцию я подгружаю только стартовый установочные модули (StartSet) в Standsrd. А основную рабочую библиотеку кладу на сервер, и у них подключаю как ссылку. И если я меняю код в каких-нибудь макросах, делаю апгрейд, то просто выгружаю эту библиотеку на сервер. И при следующей загрузке все рабочие станции автоматически получают внесённые изменения. Очень удобно.

А вот с переносом этой рабочей библиотеки во внутрь заморочился, потому что хочу сделать демку с защитой авт.прав, для того чтобы показывать её потенциальным клиентам. И это пока не получается.