- Classic Shell: Downloads
- Latest Stable Version 4.3.1
- Older Versions
- Translations
- Classic Shell Utility
- Save system log
- Remove Classic Shell
- Show Metro colors
- Uploads
- Classic Shell
- Dec 3rd, 2017 — Classic Shell is no longer actively developed
- Aug 12th, 2017 — General release 4.3.1 is out
- Jul 30th, 2016 — General release 4.3.0 is out
- May 22nd, 2016 — Beta version 4.2.7 is out
- May 21st, 2016 — Beta version 4.2.6 is out
- Choose between 3 different styles:
- Many usability improvements to Explorer (every feature can be turned on or off):
- «Шелл» на С: пишем командную оболочку для Unix
- Жизненный цикл командной оболочки
- Базовый цикл командной оболочки
- Чтение строки
- Парсинг строки
- Как командные оболочки запускают процессы
- Встроенные функции оболочки
- Объединение встроенных функций и процессов
- Собираем все вместе
- Подводя итоги
Classic Shell: Downloads
Latest Stable Version 4.3.1
The latest version is also available on the FossHub.com mirror.
Older Versions
Versions 3.6.8 and older can be downloaded from the Source Forge archive
The fosshub archive also contains a complete set of old versions.
Translations
Translation DLLs for the latest version can be downloaded from here:
Latest Translations
Translation DLLs for older version can be found here:
All Translations
Note: a translation DLL will only work for the exact version of Classic Shell it is intended for. Make sure you download the right version.
Classic Shell Utility
Save system log
The tool will collect information about your system to help with troubleshooting. Save the file and attach it in a forum post that describes your problem.
For best results:
- Run the tool using the same account that is causing problems. Do not run as administrator.
- The tool may ask for administrative credentials if necessary. If you choose not to provide them, the tool will still work but will collect less information.
- Some of the collected information may be sensitive (like what applications you have installed). If you wish to keep that information confidential, you can either upload the file to the FileDrop folder (see below), or archive it with a password, attach the archive in the forums and send a PM with the password to the user Ivo.
Remove Classic Shell
The tool will attempt to manually remove the Classic Shell software from your system. Use it in case you are having problems uninstalling using the conventional methods. It is designed to work even after a failed attempt to uninstall the software when some of the registry may be corrupted or some of the files may be missing.
For best results:
- Close all other programs
- Sign out all other accounts
- Read all the instructions carefully
- Restart your computer after the tool completes
Show Metro colors
The tool will display the Windows start screen color palette. This is useful for people trying to create skins for Windows 8, 8.1 and 10.
Uploads
Use this location to upload crash dumps or screenshots for troubleshooting:
Media Fire FileDrop
Important: Please enter a description for the file — who is it from and what is it for. Or post a message in the forums. Otherwise I have no way of knowing what to do with it.
Classic Shell
Classic Shell™ is free software that improves your productivity, enhances the usability of Windows and empowers you to use the computer the way you like it. The main features are:
- Highly customizable start menu with multiple styles and skins
- Quick access to recent, frequently-used, or pinned programs
- Find programs, settings, files and documents
- Start button for Windows 7, Windows 8, Windows 8.1 and Windows 10
- Toolbar and status bar for Windows Explorer
- Caption and status bar for Internet Explorer
Note: As of December 2017, Classic Shell is no longer in active development. More details here
Development has been picked up by volunteers on GitHub under the name Open Shell
The latest stable version of Classic Shell is 4.3.1
|
|
Visit the Classic Shell forum to find custom menu skins and start buttons.
If you are having problems uninstalling or upgrading Classic Shell, please read this forum post.
Dec 3rd, 2017 — Classic Shell is no longer actively developed
After 8 years I have decided to stop developing Classic Shell. The source code for the latest version is released on SourceForge. More details here.
Aug 12th, 2017 — General release 4.3.1 is out
It officially supports the Creators Update for Windows 10. More details here.
Jul 30th, 2016 — General release 4.3.0 is out
It officially supports the Anniversary Update for Windows 10. More details here.
May 22nd, 2016 — Beta version 4.2.7 is out
QFE fix for a crash bug in beta version 4.2.6 that affects 32-bit Windows 10.
May 21st, 2016 — Beta version 4.2.6 is out
It improves support for Windows 10 Redstone, adds taskbar skinning, menu animations, and many new features. More details here.
Choose between 3 different styles:
The Classic Start Menu is compatible with:
Download DisplayFusion from here
Many usability improvements to Explorer (every feature can be turned on or off):
«So happy to find this program. Very well made with lots of options. Makes Windows 7 worth using. Saves me from daily frustration. Thank you so much!» Eric
«Brilliant! No more frustration, I can work just like I used to! Thank you!» Anonymous Donor
Classic Shell works on Windows 7, Windows 8, Windows 8.1, Windows 10 and their server counterparts (Windows Server 2008 R2, Windows Server 2012, Windows Server 2012 R2, Windows Server 2016). Both 32 and 64-bit versions are supported. The same installer works for all versions.
Note: Windows RT is not supported.
Here are some of the people, who made significant contributions to the Classic Shell project:
«Шелл» на С: пишем командную оболочку для Unix
Многие считают, что сделать программу, которой будут пользоваться миллионы, очень трудно. Однако за любым, даже самым сложным, продуктом всегда стоит простая идея. Одним из них является командная оболочка, или «шелл». В этой статье мы расскажем, как написать упрощенную командную оболочку Unix на C.
Совет Не стоит сдавать или использовать (даже в изменённом виде) приведённый ниже код в качестве домашнего проекта в школе или вузе. Многие преподаватели знают об оригинальной статье и уличат вас в обмане.
Жизненный цикл командной оболочки
Оболочка выполняет три основные операции за время своего существования:
- Инициализация: на этом этапе она читает и исполняет свои файлы конфигурации. Они изменяют её поведение.
- Интерпретация: далее оболочка считывает команды из stdin и исполняет их.
- Завершение: после исполнения основных команд она исполняет команды выключения, освобождает память и завершает работу.
Именно эти три операции мы будем использовать как основу для нашей командной оболочки. Мы не будем добавлять дополнительные файлы конфигурации и команду выключения. Будем лишь вызывать функцию цикла и завершать работу. Стоит отметить, что, с точки зрения архитектуры, жизненный цикл сложнее, чем просто цикл.
В примере выше можно увидеть функцию lsh_loop() , которая будет циклически интерпретировать команды. Реализацию рассмотрим чуть ниже.
Базовый цикл командной оболочки
В первую очередь нам нужно подумать о том, как программа должна запускаться. И здесь важно понимать, что делает оболочка во время цикла. Простой способ обработки команд состоит из трех шагов:
- Чтение: считывание команды со стандартных потоков.
- Парсинг: распознавание программы и аргументов во входной строке.
- Исполнение: запуск распознанной команды.
Эта идея реализована в функции lsh_loop() :
Пройдемся по коду. Первые несколько строк — это просто объявления. Цикл с постусловием более удобен для проверки состояния переменной, поскольку выполняется перед проверкой ее значения. Внутри цикла выводится приглашение ввода, вызываются функции для чтения входной строки и разбиения строки на аргументы, а затем исполняются аргументы. Далее освобождается память, выделенная под строку и аргументы. Стоит обратить внимание, что в коде используется переменная состояния, возвращаемая в lsh_execute() и определяющая, когда нужно выйти из функции.
Чтение строки
Чтение строки из стандартного потока ввода — это вроде бы просто, но в C это может вызвать много хлопот. Беда в том, что никто не знает заранее, сколько текста пользователь введет в командную оболочку. Нельзя просто выделить блок и надеяться, что пользователи не выйдут за него. Вместо этого нужно перераспределять выделенный блок памяти, если пользователи выйдут за его пределы. Это стандартное решение в C, и именно оно будет использоваться для реализации lsh_read_line() .
В первой части много объявлений. Стоит отметить, что в коде используется старый стиль C, а именно объявление переменных до основной части кода. Основная часть функции находится внутри, на первый взгляд, бесконечного цикла while(1) . В цикле символ считывается и сохраняется как int , а не char (EOF — это целое число, а не символ, поэтому для проверки используйте int ). Если это символ перевода строки или EOF, мы завершаем текущую строку и возвращаем ее. В обратном случае символ добавляется в существующую строку.
Затем мы проверяем, выходит ли следующий символ за пределы буфера. Если это так, то перераспределяем буфер (при этом проверяем его на наличие ошибок распределения) и продолжаем исполнение.
Те, кто знаком с новыми версиями стандартной библиотеки C, могут заметить, что в stdio.h есть функция getline() , которая выполняет большую часть работы, реализованной в коде выше. Эта функция была расширением GNU для библиотеки C до 2008 года, а затем была добавлена в спецификацию, поэтому большинство современных Unix-систем уже идут с ней в комплекте. С getline функция становится тривиальной:
Парсинг строки
Теперь нам нужно распарсить входную строку в список аргументов. Мы сделаем небольшое упрощение и запретим пользователю использовать кавычки и обратную косую черту в аргументах командной строки. Вместо этого для разделения аргументов мы просто будем использовать пробелы. Таким образом команда echo «вот сообщение» будет вызывать команду echo не с одним аргументом «вот сообщение» , а с двумя: «вот» и «сообщение» .
22 апреля в 19:00, Онлайн, Беcплатно
Теперь всё, что нам нужно сделать — разбить строку на части, используя пробелы в качестве разделителей. Это значит, что мы можем использовать классическую библиотечную функцию strtok .
Реализация этой функции подозрительно похожа на lsh_read_line() , и это неспроста! Здесь используется та же стратегия, только вместо нуль-терминированного массива символов мы используем нуль-терминированный массив указателей.
Мы начинаем разбиение, вызывая strtok . Она возвращает указатель на первый кусок строки (токен). Вообще strtok() возвращает указатели на места в строке и помещает нуль-терминаторы в конце каждого токена. Эти указатели мы храним в отдельном массиве.
При необходимости мы перераспределим массив указателей. Повторяем процесс до тех пор, пока strtok не перестанет возвращать токены, и завершаем массив токенов нуль-терминатором.
Теперь у нас есть массив токенов, готовых к исполнению.
Как командные оболочки запускают процессы
Теперь мы добрались до самой сути того, что делает оболочка. Запуск процессов — это основная функция командных оболочек. Поэтому если вы создаёте оболочку, то должны точно знать, что происходит с процессами и как они запускаются. Именно поэтому сейчас мы поговорим о процессах в Unix.
В Unix есть только два способа запуска процессов. Первый (который не будем брать в счет) — это Init . Видите ли, когда загружается Unix-система, загружается её ядро. После загрузки и инициализации ядро запускает только один процесс, который называется Init . Этот процесс выполняется в течение всего времени работы компьютера, и управляет загрузкой остальных процессов, которые необходимы для его работы.
Поскольку все остальные процессы не Init , остаётся только один практический способ запуска процессов: системный вызов fork() . Когда эта функция вызывается, операционная система делает дубликат процесса и запускает их параллельно. Первоначальный процесс называется «родительским», а новый — «дочерним». Дочернему процессу fork() возвращает 0 , а родителю — идентификатор процесса (PID) его дочернего элемента. Таким образом, любой новый процесс можно создать только из копии уже существующего.
Это может показаться проблемой. Обычно, когда вы хотите запустить новый процесс, вам не нужна копия уже работающей программы — вы хотите запустить другую программу. Для этого нужно использовать системный вызов exec() . Он заменяет текущую запущенную программу совершенно новой. Это значит, что при вызове exec операционная система останавливает процесс, загружает новую программу и запускает ее на том же месте. Вызов exec() не возвращает процесс, если нет ошибки.
Благодаря этим двум системным вызовам и возможен запуск большинства программ в Unix. Сперва существующий процесс раздваивается на родительский и дочерний, а затем дочерний процесс использует exec() для замены себя новой программой. Родительский процесс может продолжать делать другие вещи, а также следить за своими дочерними элементами, используя системный вызов wait() .
Да уж, информации немало. Давайте посмотрим на код запуска программы:
Эта функция принимает список аргументов, которые мы создали ранее. Затем она разворачивает процесс и сохраняет возвращаемое значение. Как только fork() возвращает значение, мы получаем два параллельных процесса. Дочернему процессу соответствует первое условие if (где pid == 0 ).
В дочернем процессе мы хотим запустить команду, заданную пользователем. Поэтому мы используем один из вариантов системного вызова exec , execvp . Разные варианты exec делают разные вещи. Одни принимают переменное количество строковых аргументов, другие берут список строк, а третьи позволяют указать окружение, в котором выполняется процесс. Этот конкретный вариант принимает имя программы и массив (также называемый вектором, отсюда ‘v’ ) строковых аргументов (первым должно быть имя программы). ‘p’ означает, что вместо предоставления полного пути к файлу программы для запуска мы укажем только её имя, а также скажем операционной системе искать её самостоятельно.
Если команда exec возвращает -1 (или любое другое значение), значит, произошла ошибка. Таким образом, мы используем perror для вывода сообщения об ошибке вместе с именем программы, чтобы было понятно, где произошла ошибка. Затем мы завершаем процесс, но так, чтобы программная оболочка продолжала работать.
Второе условие ( pid ) проверяет, произошла ли в процессе выполнения fork() ошибка. Если ошибка есть, мы выводим сообщение об этом на экран, но программа продолжает работать.
Третье условие означает, что вызов fork() выполнен успешно. Там находится родительский процесс. Мы знаем, что потомок собирается исполнить процесс, поэтому родитель должен дождаться завершения команды. Мы используем waitpid() для ожидания изменения состояния процесса. К сожалению, у waitpid() есть много опций (например, exec() ). Процессы могут изменять свое состояние множеством способов, и не все состояния означают, что процесс завершился. Процесс может либо завершиться обычным путём (успешно либо с кодом ошибки), либо быть остановлен сигналом. Таким образом, мы используем макросы, предоставляемые waitpid() , чтобы убедиться, что процесс завершен. Затем функция возвращает 1 как сигнал вызывающей функции, что она снова может вывести приглашение ввода.
Встроенные функции оболочки
Возможно, вы заметили, что функция lsh_loop() вызывает lsh_execute() , но выше мы назвали нашу функцию lsh_launch() . Это было намеренно! Дело в том, что большинство команд, которые исполняет оболочка, являются программами — но не все. Некоторые из команд встроены прямо в оболочку.
Причина довольно проста. Если вы хотите сменить каталог, вам нужно использовать функцию chdir() . Дело в том, что текущий каталог является свойством процесса. Итак, допустим, вы написали программу cd , которая изменяет каталог. Она просто меняет свой текущий каталог и завершается, но текущий каталог родительского процесса не изменится. Вместо этого процесс оболочки должен исполнить chdir() , чтобы обновить свой текущий каталог. Затем, когда он запускает дочерние процессы, они также наследуют этот каталог.
Аналогично программа с именем exit не сможет выйти из командной оболочки, которая ее вызвала. Эта команда также должна быть встроена в оболочку. Кроме того, большинство оболочек настраиваются с помощью сценариев конфигурации, таких как
/.bashrc . Эти сценарии используют команды, которые изменяют работу оболочки. Сами же команды могут изменить работу оболочки, если только они были реализованы внутри самой оболочки.
Соответственно, имеет смысл добавить некоторые команды в оболочку. В эту оболочку мы добавим cd , exit и help . А вот и реализация этих функций:
Код состоит из трёх частей. Первая часть содержит предваряющее объявление функций. Предваряющее объявление — это когда вы объявляете (но не определяете) что-то, чтобы можно было использовать это имя до его определения. lsh_help() — причина, по которой мы делаем это. Она использует массив встроенных функций, а сами массивы содержат lsh_help() . Самый простой способ разбить этот цикл зависимостей — это предваряющее объявление.
Следующая часть представляет собой массив имён встроенных команд, за которыми следует массив соответствующих функций. Это значит, что в будущем встроенные команды могут быть добавлены путем изменения этих массивов, а не большого оператора switch где-то в коде. Если вы смущены объявлением builtin_func , все в порядке. Это массив указателей на функции (которые принимают массив строк и возвращают int ). Любое объявление, включающее указатели на функции в C, может стать действительно сложным.
Наконец, идет реализация каждой функции. Функция lsh_cd() сначала проверяет наличие своего второго аргумента и выводит сообщение об ошибке, если его нет. Затем она вызывает chdir() , проверяет наличие ошибок и завершает работу. Функция справки выводит информативное сообщение и имена всех встроенных функций. А функция выхода возвращает 0 , как сигнал для окончания цикла команд.
Объединение встроенных функций и процессов
Последний недостающий фрагмент головоломки заключается в реализации функции lsh_execute() , которая либо запускает либо встроенный, либо другой процесс.
Код проверяет, является ли команда встроенной. Если это так, то запускает её, а в противном случае вызывает lsh_launch() , чтобы запустить процесс.
Собираем все вместе
Вот и весь код, который входит в командную оболочку. Если вы внимательно читали статью, то должны были понять, как работает оболочка. Чтобы испробовать оболочку (на Linux), вам нужно скопировать эти сегменты кода в файл main.c и скомпилировать его. Обязательно включите только одну реализацию lsh_read_line() . Вам нужно будет включить следующие заголовочные файлы:
Чтобы скомпилировать файл, введите в терминале gcc -o main main.c , а затем ./main , чтобы запустить.
Кроме того, все исходники доступны на GitHub.
Подводя итоги
Очевидно, что эта оболочка не является многофункциональной. Некоторые из ее упущений:
- аргументы разделяются только пробелами, нет поддержки кавычек или обратного слеша;
- нет перенаправления и конвейеров;
- мало встроенных функций;
- нет подстановки имён файлов.
Чтобы разобраться в системных вызовах, рекомендуем обратиться к мануалу: man 3p . Если вы не знаете, какой интерфейс вам предлагают стандартная библиотека C и Unix, советуем посмотреть спецификацию POSIX, в частности раздел 13.