Закрытие навязчивых окон 1С

Программа для закрытия навязчивых окон в 1С и других приложениях. Использую ее, т.к. часто в копиях баз, предоставляемых клиентом при работе возникают навязчивые сообщения, на закрытие которых тратится драгоценное время.


Клиенты часто предоставляют мне копии своих баз. В последнее время 1С стало выдавать много навязчивых оповещений, которые мешают мне, как разработчику. Я трачу своё время на закрытие этих ненужных мне оповещений.

Вот примеры таких оповещений:

Приходится снимать галочку «Показывать при начале работы».
Это сообщение вообще не отключается.

Чтобы решить проблему раз и навсегда, я заказал программисту небольшую программку на Си, которая закрывает окна по их заголовку.

Как использовать программу

Программа называется kwnd.exe.

Заголовки окон нужно написать в файле kwnd без расширения и разместить в одной папке с kwnd.exe. Каждый заголовок должен быть с новой строки.

Для приведенных выше навязчивых окон 1С файл заголовков окон kwnd выглядит так:

Информация - Бухгалтерия предприятия, редакция 3.0
Рекомендуется обновить версию конфигурации

Программа консольная, не имеет графического интерфейса.

Программа работает в бесконечном цикле, но не завершается, проверяет список окон по таймеру. Если указать при запуске kwnd.exe числовой параметр, то очередь будет опрашиваться раз в указанное количество секунд.

Пример для запуска проверки очереди раз в секунду:

kwnd.exe 1 

Второй экземпляр kwnd.exe не запускается, программа выдает предупреждение, что она уже запущена. Снять программу можно через диспетчер задач:

Программа не нагружает процессор, несмотря на то, что постоянно проверяет список окон.

Для автозапуска программы используйте команду shell:startup или shell:common startup для открытия папки автозапуска текущего или всех пользователей.

В папке разместите ярлык на программу:

После этого можно забыть о навязчивых сообщениях.

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

Как определить заголовок программы

Обычно нет проблем визуально определить заголовок окна. Но иногда нужно получить точное название.

Для точного определения заголовка я использую Au3Info.exe от программы AutoIt.

Ее можно получить после установки AutoIT. Или скачать отдельно, она работает и отдельно от пакета AutoIt.

Также можно использовать AU3_Spy из пакета AutoHotKey и множество других подобных программ.

Получить программу

Исходный код программы:

#pragma hdrstop
#pragma argsused
 
#ifdef _WIN32
#include <tchar.h>
#else
  typedef char _TCHAR;
  #define _tmain main
#endif
 
#include <stdio.h>
#include <iostream>
#include <windows.h>
#include <ctime>
#include <tchar.h>
#include <string> // подключаем строки
#include <fstream> // подключаем файлы
 
 #define NAME_CONSOLE "myConsole"
 
using namespace std;
 
HWND hWnd;
HANDLE mutex;//Глобальный хендл мютекса
 
 int _tmain(int argc, _TCHAR* argv[])
{
 
 //При открытии программы пытаемся создать мютекс.
 //Мютекс - такой объект, который можно увидеть из любого приложения системы
   mutex=CreateMutex(NULL,true,"kWnd");
   DWORD result;
   result = WaitForSingleObject(mutex,0);//А теперь пытаемся его захватить себе
   //Если его захватить не получается, значит мютекс уже захватил кто-то другой
   if(result!=WAIT_OBJECT_0)
	 {
	  cout<<"the program is already running, and the second copy cannot be started"<<endl;
	  Sleep(5000);
	  exit(-1);
	 }
 
 
 FreeConsole();
 
 // переменная для сброса строки, прочитанной из файла.
 // Используется в ходе подсчета строк в файле, больше ни для чего не нужна
 string AS;
 
 // определим количество строк в файле в переменной i
  int i=1;
  ifstream file("kWnd");
  while (getline(file, AS))
  {
	i++;
  }
  if (i <= 0)
  {
	cout << "Файл пуст" << endl;
	return -1;
  }
 
 
 // Динамическое выделение памяти для массива s
  string *s;
  s=new string[i];
 // запишем все строки в массив, чтобы постоянно не ходить на диск
 // Заполнение массива s значениями строк из файла
  file.clear();
  file.seekg(0, std::ios::beg);
  for (int k = 1; k < i; k++)
  {
	getline(file, s[k]);
  }
 file.close(); // обязательно закрываем файл что бы не повредить его
 //   ...поехали ....
 char str[1024];
 while (1)
 {
	  for (int k = 1; k < i; k++)
	  {
		strcpy(str,s[k].c_str());
		hWnd = FindWindow(NULL, _T(str));
		 if(IsWindow(hWnd))
		  {
			SendMessage(hWnd,WM_SYSCOMMAND,SC_CLOSE,0);
		  }
	   }
   if (argc>0) Sleep(argc*1000);
 }
 
 //При выключении программы освобождаем мютекс, если он был у нас захвачен
 ReleaseMutex(mutex);
 //И удаляем его.
 CloseHandle(mutex);
 delete[] s;
 return 0;
}

комментариев 67

  1. bob:

    Да, время написания минут 5. Нафиг заказывать.
    Автор еще и С++ плохо знает и код не безопасен.

    • 5 минут, если постоянно пишешь на Си, не спорю.
      Поэтому я и заплатил не дорого программисту, который в теме.
      Чем не безопасен код? Посоветуй, поправим.

      • NorthWind:

        вместо strcpy лучше юзать strncpy, в противном случае появляется возможность набить в память процесса чего-нибудь вредоносного. В вашем случае это сделать довольно просто, потому что содержимое файла kwnd никак и ни на что не проверяется.

        • Да, ну тут пользователь сам себе буратино. Вряд ли пользователь будет составлять сам себе битый файл kwnd.
          😉
          Не, я не против улучшений, но перекомпилировать вряд ли буду. Код открыт — вперед!

      • NorthWind:

        и еще — у меня в win10 наклонный шрифт после заголовка «Закрытие навязчивых окон 1С» в начале страницы отображатется зябрами. Видимо, он какой-то нестандартный.

  2. Lolz:

    Оказыется, сережа не смекает, что сто лет в обед есть AutoHotKey. Гений my ass.

    https://www.autohotkey.com/docs/commands/WinClose.htm по кэпшену

  3. Fepafal:

    И ты, «программист» со стажем во много лет, заплатил деньги за это… Надеюсь, не очень много хотя бы. Хотя что это я, для фрилансера-вот-вот-миллионера нет такого понятия как «много».

    • Не вижу ничего плохого в делегировании программисту. Я за час получаю 1500, почему бы и не заказать что-то другому?

  4. naf2000:

    Почему не сделать расширением в 1с? Взял базу — установил расширение. Потом удалил.

    • Подумай сам почему?
      Видимо из-за экономии времени.
      Расширение ставить не надо, в автозагрузку один раз прописал и забыл.
      Автоматизация называется.

      • Я:

        База клиент сервер, пользователи подключаются к базе через вэб клиент, и тонкий клиент. Как будешь помогать своим коллегам ? Напрягать сис админа, писать скрипты для AD ? ну или сценарного исполнения в линуксовой среде ? ))))
        А, чисто для себя если, на своем ПК — то не вижу практического применения, ради чего ? ради того что бы закрыть окно столько кипеша ? Накидал расширение, при загрузки базы для каждого пользователя блокируется работа всех окон, и не важно, в каком видео работает клиент, через вэб, в тонком или толстом клиенте, да хоть с луны.

        • Тут такой момент, что окна эти платформенны.
          Не проверял, правда, попадают ли они в список ПолучитьОкна. Но думаю, вряд ли.
          Но если попадают, то да, можно закрывать и в расширении.

  5. хорошее дело! и статья грамотно написана. Всё четко и понятно.
    Молодец Фиксин!

  6. Виталий:

    А что нужно добавить для автонажатия ОК в предупреждении «Небезопасное открытие файла»?
    (Вылазит при обновлении из файла дополнительных обработок и, например, портативной ИРки ).
    Закладка для отслеживания новых комментов https://forum.mista.ru/topic.php?id=854603.

    • я думаю, такие окна не отлавливаются, тк у них нет заголовка. Но проверь через Au3info или другой инспектор окон.
      например, нет заголовка у окна, которое напоминает о бэкапе. поэтому его нельзя идентифицировать.

  7. Ёся:

    //При выключении программы освобождаем мютекс, если он был у нас захвачен
    ReleaseMutex(mutex);
    //И удаляем его.
    CloseHandle(mutex);
    delete[] s;
    return 0;

    вот эта часть кода когда выполняется?

  8. Спасибо, а то задолбало уже каждые 5 минут выскакивать в самый неподходящий момент!

  9. Денис:

    … в RemoteApp не закрывает окна((

  10. Morgen:

    Отличная программа.
    Даже и не знаю как раньше жил без нее.
    Эти окна 1С, особенно окна с рекламой, которая предлагает, что-то мне.
    Я и так уже купил 1С и ИТС, ещё и рекламу мне пихают

  11. Ктото Там:

    Хе Хе Хе я программку вашу все равно попробую но осадочек: Trojan.Malware.300983.susgen

    https://www.virustotal.com/gui/file/91db11f5dfe11e97894503d14d1000e8d5ec865bf2a2cbaa3f3530e4b6cb1488?nocache=1

    И вопрос касательно RemoteApp без вариантов?

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

      Про Remote App не понял вопроса.

      • ryadovoi_zidiot:

        это не из-за неугодности, а потому что в программе потенциальная пропись в памяти

  12. Андрей:

    В текст добавил строку
    Проверка правомерности использования конфигурации

    Но это окно не закрывается …

    • проверьте текст заголовка утилитами autoit

      • Евгений:

        Такая же проблема, не закрывает этот тип окна. А как получить через autoit вообще не понятно( Сначала скачал exe файл, он либо вылетает с ошибкой, либо просит указать какой-то файл. Затем скачал установщик, установил, и тоже самое. Можете помочь с заголовком окна?

        • У меня такие заголовки, окно с правомерностью у меня не появляется, так что не знаю, как его вызывать, чтобы протестить:

          Информация — Бухгалтерия предприятия, редакция 3.0
          Рекомендуется обновить версию конфигурации
          Проверка правомерности использования конфигурации
          Подключение Интернет-поддержки
          Информация

          • sema:

            убери (точнее введи ошибочный, например 1 / 1) в интернет-поддержке (зуп 3.1.26.13)

          • да, такой способ тоже есть.
            Но там надо кодом это делать. Ошибочный пароль не будет сохранен 1с.

  13. Влад:

    Было бы неплохо научить эту программу закрывать окна не только по заголовку, но и без заголовка тоже. «Классификатор банков устарел», «Настройте резервное копирование» и подобные окна — они все без заголовка. А бухов эти вспылывающие окна нервируют

    • Влад:

      Я понимаю что окна без заголовка отловить труднее, но может их по совокупности ключей можно будет идентифицировать: Class/Position/Style например. Все то, что показывает AutoIt_Info. Впрочем, учитывая что делал прогу не сам Гений, хотелки вряд-ли будут реализованы. В любом случае — спасибо за то, что поделилились. Даже с той функциональностью, что в программе заложена, она очень полезная.

      • да, дописать не могу. источник кода открытый, пишите. Можно нанять исполнителя на kwork, как это сделал я.

    • да, было бы неплохо, но как их идентифицировать.

  14. Евгений:

    Доброго дня! Мне удалось применить это решение в опубликованном приложении 1С (вариант терминала). Поэтому, с одной стороны, готов поделиться решением (если нужно), а с другой — просьба. Можно попросить пересобрать программу без задержки вывода (минимум), а лучше вообще без вывода сообщения о ранее запущенной копии? 🙂 (сам попробовал, но лет 10 не программил и сходу не получилось)

    • увы, приложение писал не я. Я заказывал фрилансеру под клиента. Так что пересобрать не смогу.
      Если решение есть, делитесь, внесу изменения в статью.

  15. Мазай:

    Странная реализация через постоянный скан. Почему не через хуки на открытие окон, это куда как менее затратно по ресурсам.

  16. Дмитрий:

    Спасибо автору!

  17. Александр:

    Благодарю автора!
    Приятная и полезная мелочь, которой от души безкорысно делится человек. Успехов.

  18. sawer:

    чат жипити накалякал скприпт на повершел. батник в автозагрузку ))

    # Заголовки окон, которые вы хотите закрыть
    $targetWindowTitles = @(«Заголовок_Окна_1», «Заголовок_Окна_2», «Заголовок_Окна_3»)

    while ($true) {
    foreach ($targetWindowTitle in $targetWindowTitles) {
    # Получение списка процессов по заголовку окна
    $targetProcesses = Get-Process | Where-Object { $_.MainWindowTitle -eq $targetWindowTitle }

    # Закрытие окон
    foreach ($process in $targetProcesses) {
    $process.CloseMainWindow()
    }

    Write-Host «Окна с заголовком ‘$targetWindowTitle’ были закрыты.»
    }

    # Задержка в 2 секунды
    Start-Sleep -Seconds 2
    }

  19. Егор:

    А как такая программа может работать в терминальном сервисе ?

  20. Игнат:

    Подскажите у кого получилось реализовать этот вариант на терминальном сервере? Если да, то подскажите как вы это сделали.

  21. Иван:

    Судя по всему данный способ более не работает. Пытаюсь получить имя окна в Spy от Autohotkey и в Au3Info.exe — везде пишет только имя главного окна, например «Бухгалтерия предприятия, редакция 3.0».
    На текущий момент есть рабочее решение?

    • я делал задачу под клиента и то находил исполнителя.
      на текущий момент заявок от клиентов по этой теме нет, потому нет и потребности решать проблему.

    • Иван:

      опровергну, работает в 1С БП 3.0.161.22, платформа 8.3.24.1667

  22. Дмитрий:

    Огромное Спасибо Автору! В 1С 8.3.25 все работает

  23. Роман:

    Прикрутите графический интерфейс, пожалуйста. А то не все петрят в командную строку.

    • увы, разработчик приложения не я.
      я только его заказывал.
      код открыт, можете любого на kwork напрячь и он напишет.
      ну или сейчас модно ИИ просить.

  24. paradoxx1976:

    Подключитесь к Интернет-поддержке поддержке пользователей для работы с сервисами 1С
    По какой причине может не работать?

  25. sksoso:

    ебать да вы охуели чтоль? сколько комментов умников, которые осуждают автора. Спасибо бы сказали, сидят там жирыные задроты че то бубнят. Такие обычно в лицо ничего сказать не могут. Автору спасибо и не обращай внимание умников которые поскулить пришли, типичное ру комьюнити

  26. Olaf72:

    Критические уязвимости и ошибки безопасности
    Переполнение буфера (Buffer Overflow):

    Факт: Строка char str[1024]; выделяет 1024 байта. Функция strcpy(str, s[k].c_str()); копирует данные из файла в этот буфер без проверки длины.

    Следствие: Если злоумышленник (или сам пользователь) добавит в файл kWnd строку длиннее 1023 символов, произойдет переполнение стека. Это классическая уязвимость (CWE-120), позволяющая выполнить произвольный код или гарантированно «уронить» программу.

    Непреднамеренное закрытие системных окон (Local DoS):

    Факт: Код не проверяет прочитанные строки на пустоту. Если в файле есть пустая строка (например, лишний перенос каретки), функция FindWindow(NULL, «») начнет искать окна с пустым заголовком.

    Следствие: В Windows существует множество невидимых системных окон с пустыми заголовками. Отправка им сигнала SC_CLOSE может привести к нестабильности работы операционной системы или зависанию проводника.

    Некорректное использование макроса _T():

    Факт: Конструкция _T(str) синтаксически некорректна для переменных. Макрос _T() (или TEXT()) предназначен только для строковых литералов (например, _T(«myText»)).

    Следствие: При компиляции проекта с поддержкой UNICODE этот код выдаст ошибку. При компиляции в Multi-Byte (MBCS) он работает только потому, что макрос игнорируется препроцессором.

    Архитектурные ошибки
    Утечка памяти и логика массивов: Массивы в C++ индексируются с нуля. Код for (int k = 1; k < i; k++) пропускает нулевой индекс. Использование "сырых" указателей (new string[i]) без необходимости повышает риск утечек памяти.

    Отсутствие проверки существования файла: Код ifstream file("kWnd"); не проверяет, открылся ли файл (например, если его нет или нет прав на чтение). При неудаче программа продолжит работу с пустым массивом.

    Недостижимый код (Dead Code): Блок while (1) является бесконечным циклом без оператора break. Весь код после него (ReleaseMutex, delete[] s) математически недостижим и никогда не выполнится.

    вот исправленная версия по мнению Gemini:
    #pragma hdrstop
    #pragma argsused

    #ifdef _WIN32
    #include
    #else
    typedef char _TCHAR;
    #define _tmain main
    #endif

    #include
    #include
    #include
    #include
    #include

    #define NAME_CONSOLE «myConsole»

    using namespace std;

    int _tmain(int argc, _TCHAR* argv[]) {
    // 1. Создание мютекса и проверка на вторую копию
    // Используем CreateMutexA для явной работы с узкими строками (ANSI)
    HANDLE mutex = CreateMutexA(NULL, TRUE, «kWnd_Mutex»);
    if (GetLastError() == ERROR_ALREADY_EXISTS) {
    cout << "The program is already running, and the second copy cannot be started" << endl;
    Sleep(5000);
    return -1;
    }

    FreeConsole();

    // 2. Безопасное чтение файла
    ifstream file("kWnd");
    if (!file.is_open()) {
    // Если файл невозможно прочитать, освобождаем мютекс и выходим
    ReleaseMutex(mutex);
    CloseHandle(mutex);
    return -1;
    }

    // Используем вектор вместо сырого динамического массива
    // Он автоматически управляет памятью и размером
    vector windowTitles;
    string line;

    while (getline(file, line)) {
    // Строго исключаем пустые строки во избежание закрытия системных окон
    if (!line.empty()) {
    windowTitles.push_back(line);
    }
    }
    file.close();

    if (windowTitles.empty()) {
    ReleaseMutex(mutex);
    CloseHandle(mutex);
    return -1;
    }

    // 3. Главный цикл программы
    while (true) {
    // Итерация начинается с 0, как положено в C++
    for (size_t k = 0; k 1) {
    Sleep(argc * 1000);
    } else {
    Sleep(1000); // Базовая пауза в 1 секунду
    }
    }

    // При принудительном завершении процесса (Task Manager)
    // ОС Windows автоматически освобождает хэндлы мютексов и память.
    return 0;
    }

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *