Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.75/40: Рейтинг темы: голосов - 40, средняя оценка - 4.75
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230

Точка входа отличная от main/WinMain

28.01.2015, 09:40. Показов 8386. Ответов 32
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Случайно наткнулся на код и прямо-таки заинтересовало:
Существует еще один вид стартовой функции, о котором, судя по всему, не знает по меньшей мере половина программистов, пишущих для Windows. Суть проблемы заключается вот в чем – на самом деле, во время компиляции приложения, кроме написанного программистом кода компилятор вставляет свой собственный код, который инициализирует всякие интересные штуки и только когда сочтет нужным – то передает управление функциям main/WinMain. Сам добавляемый код можно посмотреть в файле <пусть к установленной VS>/VC/crt/src/crt0.c.
Так как в некоторых случаях этот код совершенно не нужен, то я покажу, как от него обычно избавляются, а заодно – как можно рисовать, не создавая своего окна, прямо поверх рабочего стола и окон других приложений. Итак, создаем новый проект HelloWorld3, все абсолютно аналогично прежним. После создания добавляем main.c со следующим кодом:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#pragma comment (linker,"-merge:.rdata=.text")
const CHAR szMessage[]="Hello, world!";
 
void CenterText(HDC hDC,int x,int y,LPCTSTR szMessage,int point)
{
    HFONT hFont=CreateFont(
        point * GetDeviceCaps(hDC, LOGPIXELSY) / 60,
        0, 370, 0, FW_BOLD, TRUE, FALSE, FALSE,
        RUSSIAN_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
        PROOF_QUALITY, VARIABLE_PITCH, "Times New Roman");  // Создаем новый шрифт
    HGDIOBJ hOld = SelectObject(hDC, hFont);    // Сохраняем старый шрифт
    SetTextAlign(hDC, TA_CENTER | TA_BASELINE); // Текст выровняем по центру
    SetBkMode(hDC, TRANSPARENT);    // Прозрачность, чтоб текст не оказался в квадратной рамке с цветом фона
    SetTextColor(hDC, RGB(0x40,0xAA,0));    // Цвет текста
    TextOut(hDC, x, y, szMessage, strlen(szMessage));   // Рисуем текст на поверхности
    SelectObject(hDC, hOld);    // Возвращаем старый шрифт
    DeleteObject(hFont);        // Удаляем наш кастомный шрифт
}
 
void WinMainCRTStartup()
{
    // HDC - это такая поверхность, по которой планируется рисовать
    // В данном случае мы будем рисовать по поверхности всех имеющихся
    // мониторов. А в общем случае она может быть создана и для принтера
    // и для других экзотических устройств
    HDC hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
    while(1)    // Повторять будем бесконечно
    {
        // Выводим текст
        CenterText(hDC, GetSystemMetrics(SM_CXSCREEN) / 2,
            GetSystemMetrics(SM_CYSCREEN) / 2, szMessage, 72);
        Sleep(100); // Ждем 1/10 секунды, чтоб не забивать процессор
    }
    // Сюда выполнение не дойдет, задачу нужно завершить через список процессов
    ReleaseDC(NULL, hDC);
    ExitProcess(0);
}
Теперь требуется настроить свойства проекта - щелкаем правой кнопкой в окне Solution Explorer по названию проекта HelloWorld3, выбираем Properties. В дереве открываем Configuration Properties/Linker/System, ставим в свойстве SubSystem значение Windows. Свойство SubSystem как раз и определяет, как будет компилироваться приложение – как консольное (/SUBSYSTEM:Console) или как оконное (/SUBSYSTEM:Windows). Если его не устанавливать, то оно само попытается определить тип подсистемы по имени стартовой функции. Однако, если функция имеет нестандартное имя, как в нашем примере – то его придется указывать явно. Помимо этих двух типов приложений, в списке имеются также и другие, но к теме уроков они не относятся.
Дальше открываем Configuration Properties/Linker/Advanced, в свойство Entry Point записываем название функции, с которой хотим начать выполнение – WinMainCRTStartup.
Собственно:
1>MSVCRTD.lib(crtexew.obj) : error LNK2019: ссылка на неразрешенный внешний символ _WinMain@16 в функции ___tmainCRTStartup
1>c:\users\w\documents\visual studio 2013\Projects\Overlay\Debug\HelloWorld.e xe : fatal error LNK1120: неразрешенных внешних элементов: 1
Насколько я понимаю проблема как раз в SubSystem. Несколько не понятно, что именно там необходимо ввести в качестве значения. Просто Windows? /SUBSYSTEM:Windows? Перепробовал - толку нет. Среда MSVS2013.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
28.01.2015, 09:40
Ответы с готовыми решениями:

Ошибка: In function main: 18 undefined reference to WinMain
Создайте класс, содержащий 2 закрытые переменные (катеты прямоугольного треугольника) и открытые функции (для присвоения значений...

Настройка размера окна при открытии программы (main(), не WinMain()
Доброго времени суток, форумчане! Во первых, хочу вас всех поблагодарить за помощь, благодаря вам я написал свою первую серьёзную...

[ERROR] id returned 1 exit status | main.c:(text.startup+0xa7):undefined reference to 'WinMain@16'
Здравствуйте. Помогите узнать в чем ошибка. По ходу с компилятором что-то не так. . . использую Dev C++ #include &lt;iostream&gt; ...

32
654 / 575 / 164
Регистрация: 13.12.2012
Сообщений: 2,124
28.01.2015, 10:38
Цитата Сообщение от DarkMasterW Посмотреть сообщение
Итак, создаем новый проект HelloWorld3, все абсолютно аналогично прежним
чай консольное Вы создали, попробуйте win32
или как оно там называется - оконное?
0
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 10:42  [ТС]
Создал консольное, пересоздал оконным - тоже самое. Вообще насколько я понял из описания ему все равно из чего выполнятся, это вроде как одна из главных фич данного метода.
0
654 / 575 / 164
Регистрация: 13.12.2012
Сообщений: 2,124
28.01.2015, 10:48
ну так там настроек в проекте же полно, для консольного и для оконного сильно различаются, либо метод сомнительный
0
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 10:52  [ТС]
Кхе... Оказалось надо было создавать .c, а не .cpp... Все работает...
0
 Аватар для Kastaneda
5232 / 3205 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
28.01.2015, 11:10
Помню давно еще ключи MS компилятора изучал, наткнулся на ключ, который задает точку входа в приложение. При помощи него можно писать Hello World вот в таком виде

C++
1
2
3
4
5
6
7
8
9
#include <iostream>
 
class HelloWorld {
public:
    static int someMethod() 
    {
        std::cout << "Hello, World!" << std::endl;
    }
};
потом при помощи этого ключа говоришь, что вместо main использовать HelloWorld::someMethod и все работает.
Точно не помню как этот ключ называется, что-то типа /ENTRY.
0
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 11:15  [ТС]
Все верно, /ENTRY:"WinMainCRTStartup" в данном случае получился. Просто задавался он через гуй согласно описанию.
А дальше тупой вопрос... мне стыдно...
.c - это C, а .cpp - это C++? Т.е. код только для C? Под C++ как его необходимо модифицировать?
0
654 / 575 / 164
Регистрация: 13.12.2012
Сообщений: 2,124
28.01.2015, 11:23
Цитата Сообщение от DarkMasterW Посмотреть сообщение
.c - это C, а .cpp - это C++?
ну не обязательно ж,
Цитата Сообщение от DarkMasterW Посмотреть сообщение
Под C++ как его необходимо модифицировать?
то что написано в первом посте, не надо
0
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 11:29  [ТС]
Почему тогда .cpp не подхватывает? Не очень понимаю структурно суть происходящих проблем.
0
Почетный модератор
Эксперт С++
 Аватар для SatanaXIII
5851 / 2862 / 392
Регистрация: 01.11.2011
Сообщений: 6,906
28.01.2015, 11:44
Цитата Сообщение от aLarman Посмотреть сообщение
ну не обязательно ж
Но желательно ж.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
28.01.2015, 11:50
Цитата Сообщение от DarkMasterW Посмотреть сообщение
Т.е. код только для C? Под C++ как его необходимо модифицировать?
Если вы отключаете плюсовый рантайм, то сможете использовать лишь
небольшое подмножество языка C++. Без исключений, без RTTI, без
стандартной библиотеки. Так что все эти рецепты по "оптимизации exe"
особого смысла не имеют. Ну станет exe-шник весить 2-3 КБ вместо 50,
принесет ли это радость за такую цену ?
1
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 12:00  [ТС]
Дык я поэтому и спрашиваю. Я не хочу падать в чистый C. Беда в том, что в .cpp не хочет компилиться(ошибка в 1 посте темы).
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
28.01.2015, 12:23
Лучший ответ Сообщение было отмечено DarkMasterW как решение

Решение

Цитата Сообщение от DarkMasterW Посмотреть сообщение
Т.е. код только для C? Под C++ как его необходимо модифицировать?
В С++ имена функций декорируются. Вероятно надо прописать extern "C" той функции, чтобы собралось из C++.
Т.е. я об этом:
C++
1
extern "C" void WinMainCRTStartup()
0
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 12:32  [ТС]
Уже затестил, все шуршит теперь. Ну почти все. Где-то съезжает по адресации видимо(на С тоже). Выводит иероглифы и Times вместо хелоу ворлда. Пришлось типы приводить, видимо не прошло бесследно.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#pragma comment (linker,"-merge:.rdata=.text")
const CHAR szMessage[]="Hello, world!";
 
void CenterText(HDC hDC,int x,int y,LPCTSTR szMessage,int point)
{
    HFONT hFont=CreateFont(
        point * GetDeviceCaps(hDC, LOGPIXELSY) / 60,
        0, 370, 0, FW_BOLD, TRUE, FALSE, FALSE,
        RUSSIAN_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
        PROOF_QUALITY, VARIABLE_PITCH, L"Times New Roman"); // Создаем новый шрифт
    HGDIOBJ hOld = SelectObject(hDC, hFont);    // Сохраняем старый шрифт
    SetTextAlign(hDC, TA_CENTER | TA_BASELINE); // Текст выровняем по центру
    SetBkMode(hDC, TRANSPARENT);    // Прозрачность, чтоб текст не оказался в квадратной рамке с цветом фона
    SetTextColor(hDC, RGB(0x40,0xAA,0));    // Цвет текста
    TextOut(hDC, x, y, szMessage, strlen((const char*)szMessage));  // Рисуем текст на поверхности
    SelectObject(hDC, hOld);    // Возвращаем старый шрифт
    DeleteObject(hFont);        // Удаляем наш кастомный шрифт
}
 
extern "C" void WinMainCRTStartup()
{
    // HDC - это такая поверхность, по которой планируется рисовать
    // В данном случае мы будем рисовать по поверхности всех имеющихся
    // мониторов. А в общем случае она может быть создана и для принтера
    // и для других экзотических устройств
    HDC hDC = CreateDC(L"DISPLAY", NULL, NULL, NULL);
    while(1)    // Повторять будем бесконечно
    {
        // Выводим текст
        CenterText(hDC, GetSystemMetrics(SM_CXSCREEN) / 2,
            GetSystemMetrics(SM_CYSCREEN) / 2, (LPCTSTR)szMessage, 72);
        Sleep(1000);    // Ждем 1/10 секунды, чтоб не забивать процессор
    }
    // Сюда выполнение не дойдет, задачу нужно завершить через список процессов
    ReleaseDC(NULL, hDC);
    ExitProcess(0);
}
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
28.01.2015, 13:54
Цитата Сообщение от DarkMasterW Посмотреть сообщение
C++
1
TextOut(hDC, x, y, szMessage, strlen((const char*)szMessage));
Здесь или приведение к "const char *" нужно исправить, или написать в явном
виде TextOutA/TextOutW.
0
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 14:11  [ТС]
Цитата Сообщение от Убежденный Посмотреть сообщение
Здесь или приведение к "const char *" нужно исправить
Как раз на него косился. Видимо чутье не подвело. А что с ним не так? Размер съезжает из-за разного количества байт на символ? Я правильно понимаю, что в таком варианте const char * получится длиннее и вернет большее значение не соответствующее количеству символов?
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
28.01.2015, 14:17
А Вы подумайте - зачем там вообще потребовалось приведение типов.
Ведь TextOut работает со строками, ничего приводить не нужно.
Если только...
0
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 14:17  [ТС]
Цитата Сообщение от Убежденный Посмотреть сообщение
или написать в явном
виде TextOutA/TextOutW.
так кстати не прошло. Да и там вроде define есть под это дело...

C++
1
2
3
4
5
6
7
WINGDIAPI BOOL  WINAPI TextOutA( _In_ HDC hdc, _In_ int x, _In_ int y, _In_reads_(c) LPCSTR lpString, _In_ int c);
 WINGDIAPI BOOL  WINAPI TextOutW( _In_ HDC hdc, _In_ int x, _In_ int y, _In_reads_(c) LPCWSTR lpString, _In_ int c);
#ifdef UNICODE
#define TextOut  TextOutW
#else
#define TextOut  TextOutA
#endif // !UNICODE
Вроде же все логично, у меня юникод, вызов будет TextOutW. Не совсем понимаю как может явное объявление TextOutA/TextOutW повлиять на обработку в текущей ситуации. Если бы строка была в мультибите, а выставлен был юникод, то подобный вызов вроде мог бы и помочь, но у меня вроде и так все юникоде.
0
Модератор
Эксперт по электронике
8981 / 6748 / 921
Регистрация: 14.02.2011
Сообщений: 23,871
28.01.2015, 14:29
Цитата Сообщение от DarkMasterW Посмотреть сообщение
Вроде же все логично, у меня юникод, вызов будет TextOutW.
вот вот!!! а приводишь к чему
Цитата Сообщение от DarkMasterW Посмотреть сообщение
TextOut(hDC, x, y, szMessage, strlen((const char*)szMessage));
в юникроде то длинна строки в байтах в два раза больше
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
28.01.2015, 14:30
Так если все в Unicode, надо вместо strlen ставить wcslen.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
28.01.2015, 14:30
Помогаю со студенческими работами здесь

Не могу запустить WPF проект. Не найдена точка входа Main. Ничего не понимаю...
Создал проект WPF. Удалил MainWindow.xaml, MainWindow.xaml.cs, App.xaml, App.xaml.cs. Потом такие же файлы скопировал с другого проекта и...

Что такое точка входа? (opengl32.dll была загружена, но найти точку входа для DllRegisterServer не удалось.)
:help: при открывании игр показывает окно: RegSvr32 opengl32.dll была загружена, но найти точку входа для DllRegisterServer не...

Вызов конструктора происходит до входа в main
Дебажу один большой проект Первый брейкпоинт у меня стоит на первой строке в main(), но при этом отладчик сначала попадает в...

Программа не содержит статистического метода Main, подходящего для входа
Помогите пожалуйста, ошибку эту выдает using System; using System.Collections.Generic; using System.Linq; using System.Text; ...

Программа не содержит статического метода main подходящего для точки входа
Вчера оба проекта нормально компилировались, а сегодня выдает ошибку &quot;Программа не содержит статического метода main подходящего для точки...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru