Имя: Пароль:
1C
 
Удалить меню "Файл"
Ø
0 Young
 
28.08.05
00:27
Написал ради интереса процедуру, которая удаляет меню "Файл", "Сервис", "Окна" и "Помощь" из главного меню программы.
Всё ниженапечатанное надо вставить в глобальник. Печатаю по частям, т.к. текста слишком много.
=======================================================================
Перем ExcelApp;
//*********************************************************************
Процедура глУбратьМенюФайл(ExcelApp)
  ПолныйЗаголовокСистемы="1С:Предприятие - "+СокрЛП(Метаданные.Идентификатор)+": "+ЗаголовокСистемы();
  ExcelApp.DisplayAlerts = 0; // не выводить сообщений и вопросов
  WorkBook = ExcelApp.WorkBooks.Add(); // создание новой книги Excel
  WorkBook.Worksheets.Add(); // создание нового листа в книге Excel
  //добавление нового модуля VBA в книгу Excel и получение ссылки на его код:
  ы = ExcelApp.VBE.ActiveVBProject.VBComponents.Count;
  ExcelApp.VBE.ActiveVBProject.VBComponents.Add(1);
  CodeModule = ExcelApp.VBE.ActiveVBProject.VBComponents.Item(ы + 1).CodeModule;
  //************************************************************************************************
  //=>>Добавление кода VBA *************************************************************************
  //Объявления нужных Win32 API:
  CodeModule.InsertLines(1, "Public Declare Function GetDesktopWindow Lib ""user32"" () As Long");
  CodeModule.InsertLines(2, "Public Declare Function EnumChildWindows Lib ""user32"" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long");
  CodeModule.InsertLines(3, "Public Declare Function GetWindowTextLength Lib ""user32"" Alias ""GetWindowTextLengthA"" (ByVal hwnd As Long) As Long");
  CodeModule.InsertLines(4, "Public Declare Function GetWindowText Lib ""user32"" Alias ""GetWindowTextA"" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long");
  CodeModule.InsertLines(5, "Public Declare Function GetMenu Lib ""user32"" (ByVal hwnd As Long) As Long");
  CodeModule.InsertLines(6, "Public Declare Function GetMenuItemCount Lib ""user32"" (ByVal hMenu As Long) As Long");
  CodeModule.InsertLines(7, "Public Declare Function RemoveMenu Lib ""user32"" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long");
  CodeModule.InsertLines(8, "Public Declare Function GetMenuItemInfo Lib ""user32"" Alias ""GetMenuItemInfoA"" (ByVal hMenu As Long, ByVal un As Long, ByVal b As Boolean, lpmii As MENUITEMINFO) As Long");
  CodeModule.InsertLines(9, "Public Declare Function SetTimer Lib ""user32"" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long");
  CodeModule.InsertLines(10, "Public Declare Function KillTimer Lib ""user32"" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long");
  CodeModule.InsertLines(11, "Public Declare Function DrawMenuBar Lib ""user32"" (ByVal hwnd As Long) As Long");
  //Объявления глобальных переменных, констанот и типов:
  CodeModule.InsertLines(12, "Public count_wnd As Long"); //количество найденных окон
  CodeModule.InsertLines(13, "Public hwnd_1C As Long"); //хэндл окна 1С
  CodeModule.InsertLines(14, "Public uIDEvent As Long"); //идентификатор таймера
  CodeModule.InsertLines(15, "Public Type hwnd_app"); //структура, хранящая хэндл и заголовок окна
  CodeModule.InsertLines(16, " hwnd As Long");
  CodeModule.InsertLines(17, " caption As String * 1024");
  CodeModule.InsertLines(18, "End Type");
  CodeModule.InsertLines(19, "Public WindowSys() As hwnd_app"); //массив, хранящий хэндлы и заголовки найденных окон
  CodeModule.InsertLines(20, "Public Type MENUITEMINFO"); //структура, хранящая информацию об элементе меню
  CodeModule.InsertLines(21, " cbSize As Long");
  CodeModule.InsertLines(22, " fMask As Long");
  CodeModule.InsertLines(23, " fType As Long");
  CodeModule.InsertLines(24, " fState As Long");
  CodeModule.InsertLines(25, " wID As Long");
  CodeModule.InsertLines(26, " hSubMenu As Long");
  CodeModule.InsertLines(27, " hbmpChecked As Long");
  CodeModule.InsertLines(28, " hbmpUnchecked As Long");
  CodeModule.InsertLines(29, " dwItemData As Long");
  CodeModule.InsertLines(30, " dwTypeData As String");
  CodeModule.InsertLines(31, " cch As Long");
  CodeModule.InsertLines(32, " hbmpItem As Long");
  CodeModule.InsertLines(33, "End Type");
  CodeModule.InsertLines(34, "Public Const MIIM_STRING = &H40");
  CodeModule.InsertLines(35, "Public Const MF_REMOVE = &H1000&");
  CodeModule.InsertLines(36, "Public Const MF_BYPOSITION = &H400");
1 Young
 
28.08.05
00:30
  //Процедура, находящая хэндл окна 1С:
  CodeModule.InsertLines(37, "Public Sub Find1C_Window()");
  CodeModule.InsertLines(38, " hwndDesktop = GetDesktopWindow()"); //получение хэндла окна рабочего стола
  CodeModule.InsertLines(39, " EnumChildWindows hwndDesktop, AddressOf EnumChildProc, ByVal 0&"); //перечисление дочерних окон рабочего стола
  CodeModule.InsertLines(40, " For i = 1 To count_wnd");
  CodeModule.InsertLines(41, " If (InStr(WindowSys(i).caption, """+ПолныйЗаголовокСистемы+""") > 0) Then"); //найдено окно 1С
  CodeModule.InsertLines(42, " hwnd_1C = WindowSys(i).hwnd"); //получение хэндла окна 1С
  CodeModule.InsertLines(43, " Exit For");
  CodeModule.InsertLines(44, " End If");
  CodeModule.InsertLines(45, " Next");
  CodeModule.InsertLines(46, "End Sub");
  //Функция перечисления дочерних окон:
  CodeModule.InsertLines(47, "Public Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Long");
  CodeModule.InsertLines(48, " Dim sSave As String");
  CodeModule.InsertLines(49, " sSave = Space$(GetWindowTextLength(hwnd) + 1)");
  CodeModule.InsertLines(50, " GetWindowText hwnd, sSave, Len(sSave)"); //получение заголовка окна
  CodeModule.InsertLines(51, " sSave = Left$(sSave, Len(sSave) - 1)");
  CodeModule.InsertLines(52, " If sSave <> """" Then");
  CodeModule.InsertLines(53, " count_wnd = count_wnd + 1"); //увеличение счётчика окон
  CodeModule.InsertLines(54, " ReDim Preserve WindowSys(count_wnd)"); //помещение найденного окна в массив
  CodeModule.InsertLines(55, " WindowSys(count_wnd).hwnd = hwnd");
  CodeModule.InsertLines(56, " WindowSys(count_wnd).caption = sSave");
  CodeModule.InsertLines(57, " End If");
  CodeModule.InsertLines(58, " EnumChildProc = 1");
  CodeModule.InsertLines(59, "End Function");
  //Процедура перечисления и удаления нужных колонок меню:
  CodeModule.InsertLines(60, "Public Sub DeleteColMenu()");
  CodeModule.InsertLines(61, " hMenu = GetMenu(hwnd_1C)"); //получение хэндла меню окна 1С
  CodeModule.InsertLines(62, " nCnt = GetMenuItemCount(hMenu)"); //получение количества колонок меню окна 1С
  CodeModule.InsertLines(63, " For j = nCnt - 1 To 0 Step -1"); //перечисление колонок меню
  CodeModule.InsertLines(64, " Dim MII As MENUITEMINFO");
  CodeModule.InsertLines(65, " MII.cbSize = Len(MII)");
  CodeModule.InsertLines(66, " MII.fMask = MIIM_STRING");
  CodeModule.InsertLines(67, " GetMenuItemInfo hMenu, j, True, MII"); //получение информации о пункте меню
  CodeModule.InsertLines(68, " MII.cch = MII.cch + 100");
  CodeModule.InsertLines(69, " MII.dwTypeData = Space(MII.cch)");
  CodeModule.InsertLines(70, " GetMenuItemInfo hMenu, j, True, MII");
  CodeModule.InsertLines(71, " If InStr(MII.dwTypeData, ""Файл"") > 0 Then"); //удаление меню "Файл"
  CodeModule.InsertLines(72, " RemoveMenu hMenu, j, MF_BYPOSITION Or MF_REMOVE");
  CodeModule.InsertLines(73, " End If");
  CodeModule.InsertLines(74, " If InStr(MII.dwTypeData, ""Сервис"") > 0 Then"); //удаление меню "Сервис"
  CodeModule.InsertLines(75, " RemoveMenu hMenu, j, MF_BYPOSITION Or MF_REMOVE");
  CodeModule.InsertLines(76, " End If");
  CodeModule.InsertLines(77, " If InStr(MII.dwTypeData, ""Окна"") > 0 Then"); //удаление меню "Окна"
  CodeModule.InsertLines(78, " RemoveMenu hMenu, j, MF_BYPOSITION Or MF_REMOVE");
  CodeModule.InsertLines(79, " End If");
  CodeModule.InsertLines(80, " If InStr(MII.dwTypeData, ""Помощь"") > 0 Then"); //удаление меню "Помощь"
  CodeModule.InsertLines(81, " RemoveMenu hMenu, j, MF_BYPOSITION Or MF_REMOVE");
  CodeModule.InsertLines(82, " End If");
  CodeModule.InsertLines(83, " Next");
  CodeModule.InsertLines(84, " DrawMenuBar hwnd_1C");
  CodeModule.InsertLines(85, "End Sub");
  //Процедура запуска таймера:
  CodeModule.InsertLines(86, "Public Sub InstallTimer()");
  CodeModule.InsertLines(87, " uIDEvent = SetTimer(0, 1000000, 50, AddressOf DeleteColMenu)");
  CodeModule.InsertLines(88, "End Sub");
  //Процедура уничтожения таймера:
  CodeModule.InsertLines(89, "Public Sub DeleteTimer()");
  CodeModule.InsertLines(90, " KillTimer 0, uIDEvent");
  CodeModule.InsertLines(91, "End Sub");
  //<<=Добавление кода VBA *************************************************************************
  //************************************************************************************************
  ExcelApp.Application.Run("Find1C_Window"); //получение хэндла окна 1С
  ExcelApp.Application.Run("DeleteColMenu"); //удаление нужных колонок меню
  ExcelApp.Application.Run("InstallTimer"); //запуск таймера
КонецПроцедуры //глУбратьМенюФайл
2 Young
 
28.08.05
00:38
Процедура ПриНачалеРаботыСистемы()
  Попытка
    ExcelApp = СоздатьОбъект("Excel.Application");
    глУбратьМенюФайл(ExcelApp);
  Исключение
    Предупреждение("Не удалось запустить MS Excel!");
    СтатусВозврата(0);
    Возврат;
  КонецПопытки;
КонецПроцедуры // ПриНачалеРаботыСистемы
//************************************************************************************************
Процедура ПриЗавершенииРаботыСистемы()
  ExcelApp.Application.Run("DeleteTimer");
  ExcelApp.DisplayAlerts=0;
  ExcelApp.Quit();
  ExcelApp="";
КонецПроцедуры // ПриЗавершенииРаботыСистемы
======================================================================
Вопрос в следующем: имеет ли вообще право на жизнь подобный подход к программированию? Есть проблема: если Excel был запущен пользователем до запуска этой процедуры, то пользователь может интерактивно завершить процесс Excel, и всё перестанет работать. И наоборот, процедура "ПриЗавершенииРаботыСистемы" может завершить процесс Excel, нужный пользователю...
P.S. Приношу извинения за размер постов, но весь текст можно легко скопировать и вставить в глобальник.
3 VZ
 
28.08.05
01:23
Сам себе вопрос задал, сам себе и ответил... :)
4 Тертый
 
28.08.05
01:28
FormEx с этим прекрасно справляется.
5 GrayT
 
28.08.05
09:14
Прикольно, но стоит ли из пушки (Excel) по воробьям?
Я так понимаю, что при небольшой модиффикации все это можно и на WSH можно сделать или написать отдельню программулину, если нет желания использовать ВК (4)
6 GrayT
 
28.08.05
09:40
Ламерский вопросик - а для чего в данном случае работа с таймером? :(
ЗЫ: Не стреляйте в тапера - он играет как может
7 Young
 
28.08.05
11:36
(6) Работа с таймером для того, чтобы меню "обрезалось" всегда. Если обрезать один раз, то при открытии форм отчётов, журналов и т.д. меню будет восстанавливаться.
(5) По-моему, Excel не такая уж и "пушка"... На WSH этого сделать просто так нельзя, нужны "отдельные программулины". Вот я и попытался использовать Excel как "отдельную программулину". На WSH можно ещё работать с Win32 API с помощью вот этого:
http://www.script-coding.info/dynwrap.html
Однако, возможности Excel по работе с Win32 API значительно шире (хотя бы из-за ключевых слов "Public Type" и "AddressOf"). Кроме того, Excel есть практически у всех.
=====================================================================
А всё же вопрос: можно ли ухитриться вызвать CreateObject("Excel.Application") так, чтобы не "затронуть" уже запущенную копию Excel, если таковая существует?
8 Slawa
 
28.08.05
13:32
(4) Если не секрет, как ?
9 Тертый
 
28.08.05
13:53
точно не помню, но:
Окна = СоздатьОбъект("Окна");
Окна.ВидимостьМеню("&Файл",0);
10 MetaEditor
 
28.08.05
13:58
7) примерно так:
Workbook - в глобальные...
в ПриНачалеРаботыСистемы()
wbcm = Workbook.VBProject.VBE.ActiveVBProject.VBComponents.Item(1).CodeModule;
wbcm.InsertLines (1, "Private Sub Workbook_BeforeClose(Cancel As Boolean)");
wbcm.InsertLines (2, "MsgBox ""Это служебная книга закроется автоматически при выходе из 1С""");
wbcm.InsertLines (3, "Cancel = True");
wbcm.InsertLines (4, "End Sub");
в ПриЗавершенииРаботыСистемы()
Workbook.VBProject.VBE.ActiveVBProject.VBComponents.Item(1).CodeModule.Deletelines(1,4);
WorkBook.Close();
Если ExcelApp.Workbooks.Count = 0 Тогда
   ExcelApp.Quit();
   ExcelApp="";
КонецЕсли;
но всёравно не серьёзно всё это..........
8) тестовая версия формекса 2.0, недавно вышла...
11 АЛьФ
 
28.08.05
16:12
2(7) Большой минус таймера в том, что менб при этом мигает. Половина красивости, ради которой все и делается, сходит в null.
12 Young
 
28.08.05
17:26
(10) Спасибо за интерес к теме, но такой метод пожалуй действительно неприемлем...
Похоже, проблема закрытия решается просто: код VBA надо просто расположить в файле надстройки .xla. При работе из VBS-скрипта всё вроде работает как надо, из 1С проверю чуть позже...
(11) А что можно придумать кроме таймера? (если ипользовать всё те же VBA+Win32API)
13 Young
 
28.08.05
17:31
+(12) Кстати, меню мигает по-моему не из-за таймера, а из-за вызова API DrawMenuBar()...
14 Young
 
28.08.05
17:34
Попробую написать .xla, а DrawMenuBar() вызывать только тогда, когда меню реально обрезано.
15 smaharbA
 
29.08.05
06:52
(__) Ну вот сперли методу ;)
А хэндл можно найти просче... без перебора всех окон...
Можно скрыть процесс, покрайней мере из таскмана....
(12) Кроме таймера, можно глобальный хук...
16 smaharbA
 
29.08.05
07:03
(0) Кстати зря ты так ищешь,
Public Sub Find1C_Window()
hwndDesktop = GetDesktopWindow()
EnumChildWindows hwndDesktop, AddressOf EnumChildProc, ByVal 0&
For i = 1 To count_wnd
If (InStr(WindowSys(i).caption, """+ПолныйЗаголовокСистемы+""") > 0) Then
hwnd_1C = WindowSys(i).hwnd
Exit For
End If
Next
End Sub
...
Если уж по заголовку, то необязательно перебирать, у тебя есть FindWindow, но я бы передал в 1С заголовку Какоенибудь уникальное значение, а то если будет открыто несколько, какое найдется?
...
17 Young
 
29.08.05
13:00
(15) Спасибо за участие, насчёт FindWindow идею понял.
А что такое "глобальный хук", извиняюсь за невежество?
И не понял, к чему это ты сказал "Можно скрыть процесс, по крайней мере из таскмана"...
18 smaharbA
 
29.08.05
13:09
(17) Глобальный хук, этт будут отслеживаться все сообщения в системе(сообщения это не але-здрасьте, а все события/инициализациисобытий)...
А скрыть процесс, для того чтоб умники через таскманагер не убивали его, и чтоб запускать "индивидуальный" эксель, нужно наверно тока имя процесса задать другое(но этт надо попробовать)...
(17) Я передавал в перед вызовом Ворда(если видел мои изыскания на эту тему, похоже так и есть...) то передавал заголовку окна случайный номер, но можно найти PID процесса 1С(Пример тут http://www.karat-e.ru/files/VBS/priority1s.rar, но там на ВМИ - на вин апи почти также) а по нему уж найти хэндл окна...
19 Young
 
29.08.05
16:44
(18) Спасибо, идеи понятны.
 
(All) Слегка подправил код, меню больше не мигает. Проблема путаницы с процессами Excel всё же остаётся, но только в одном случае - если Excel запущен в момент запуска 1С (а это легко проконтролировать). После того, как 1С уже запущена, можно запускать-завершать Excel свободно, всё будет нормально. Результат здесь:
http://forum.script-coding.info/topic.php?topic=35
20 smaharbA
 
29.08.05
16:52
(19) могу подсказать, как завершить нафих и твой процесс ехеля(в смысле хоть таймера хоть хука)...
Private Declare Function timeKillEvent Lib "winmm.dll" (ByVal uID As Long) As Long
Public Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
for i=1 to 2147483647
timeKillEvent i
KillTimer i
UnhookWindowsHookEx i
Next
...
Медленно правда, но завершит ;)
21 АЛьФ
 
29.08.05
16:56
И почему бы на том же VB не написать нормальную ВК без извратов с офисом?
22 smaharbA
 
29.08.05
17:02
(21) а лень потомучто учить "Теорию" создания ВК...
А серьезно, это тоже метода, когда нет ВК, правда считаю что метода не для решения таких задач, но например работа с ФТП, ХТТП, диалуп, РАС, добавление какихнибудь пунктиков меню(наличие которых невлияет на работоспособность в целом) да много еще чего можно так решить, не создавая ВК...
23 АЛьФ
 
29.08.05
17:06
2(22) Но ты ведь фактически и создаешь ВК. Просто более геморный способ используешь.
24 smaharbA
 
29.08.05
17:15
(23) Здесь я "находу" делаю, в любом месте(в смысле хоть у клиента) могу подправить, а вот ВК придется всяческие компиляторы/интерпритаторы и прочее иметь...
Согласен что ВК лучче работает, но если мне надо к примеру накидать чтение файла с инета или чтение/запись огромадного файла, я так прям наместе сбацаю...
Нет, конечно твой ФормЕкс этт весч, несменю на свои приблуды в некоторых(во многих) случаях...
25 Young
 
29.08.05
17:21
(23) На все задачи ВК не напасёшься :) На каждую задачку писать ВК, регистрировать её - тоже кстати гемор. Вот сделали бы добрые люди COM-сервер, который позволял бы писать как в (0), но без VBA... DYNWRAP - здорово, но мало :) Хочется иметь слово AddressOf и прочее...
26 smaharbA
 
29.08.05
20:15
(25) сделай на ВСШ... туда динврап вставь и методы свои создай...
Это фонтазии, но это возможно... ком на всш вполне реально...
Программист всегда исправляет последнюю ошибку.