Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.67/9: Рейтинг темы: голосов - 9, средняя оценка - 4.67
DarkMasterW
4 / 4 / 1
Регистрация: 25.10.2013
Сообщений: 230
#1

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

28.01.2015, 09:40. Просмотров 1670. Ответов 31
Метки нет (Все метки)

Случайно наткнулся на код и прямо-таки заинтересовало:
Существует еще один вид стартовой функции, о котором, судя по всему, не знает по меньшей мере половина программистов, пишущих для 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.exe : fatal error LNK1120: неразрешенных внешних элементов: 1
Насколько я понимаю проблема как раз в SubSystem. Несколько не понятно, что именно там необходимо ввести в качестве значения. Просто Windows? /SUBSYSTEM:Windows? Перепробовал - толку нет. Среда MSVS2013.
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
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'
Здравствуйте. Помогите узнать в чем ошибка. По ходу с компилятором что-то не...

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

Точка входа
Подскажите пожалуйста как найти точку входа приложения?

31
aLarman
644 / 565 / 164
Регистрация: 13.12.2012
Сообщений: 2,112
Завершенные тесты: 1
28.01.2015, 10:38 #2
Цитата Сообщение от DarkMasterW Посмотреть сообщение
Итак, создаем новый проект HelloWorld3, все абсолютно аналогично прежним
чай консольное Вы создали, попробуйте win32
или как оно там называется - оконное?
0
DarkMasterW
4 / 4 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 10:42  [ТС] #3
Создал консольное, пересоздал оконным - тоже самое. Вообще насколько я понял из описания ему все равно из чего выполнятся, это вроде как одна из главных фич данного метода.
0
aLarman
644 / 565 / 164
Регистрация: 13.12.2012
Сообщений: 2,112
Завершенные тесты: 1
28.01.2015, 10:48 #4
ну так там настроек в проекте же полно, для консольного и для оконного сильно различаются, либо метод сомнительный
0
DarkMasterW
4 / 4 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 10:52  [ТС] #5
Кхе... Оказалось надо было создавать .c, а не .cpp... Все работает...
0
Kastaneda
Jesus loves me
Эксперт С++
4823 / 2997 / 345
Регистрация: 12.12.2009
Сообщений: 7,559
Записей в блоге: 2
Завершенные тесты: 1
28.01.2015, 11:10 #6
Помню давно еще ключи 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
DarkMasterW
4 / 4 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 11:15  [ТС] #7
Все верно, /ENTRY:"WinMainCRTStartup" в данном случае получился. Просто задавался он через гуй согласно описанию.
А дальше тупой вопрос... мне стыдно...
.c - это C, а .cpp - это C++? Т.е. код только для C? Под C++ как его необходимо модифицировать?
0
aLarman
644 / 565 / 164
Регистрация: 13.12.2012
Сообщений: 2,112
Завершенные тесты: 1
28.01.2015, 11:23 #8
Цитата Сообщение от DarkMasterW Посмотреть сообщение
.c - это C, а .cpp - это C++?
ну не обязательно ж,
Цитата Сообщение от DarkMasterW Посмотреть сообщение
Под C++ как его необходимо модифицировать?
то что написано в первом посте, не надо
0
DarkMasterW
4 / 4 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 11:29  [ТС] #9
Почему тогда .cpp не подхватывает? Не очень понимаю структурно суть происходящих проблем.
0
SatanaXIII
Супер-модератор
Эксперт С++
5773 / 2772 / 376
Регистрация: 01.11.2011
Сообщений: 6,744
Завершенные тесты: 1
28.01.2015, 11:44 #10
Цитата Сообщение от aLarman Посмотреть сообщение
ну не обязательно ж
Но желательно ж.
0
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
28.01.2015, 11:50 #11
Цитата Сообщение от DarkMasterW Посмотреть сообщение
Т.е. код только для C? Под C++ как его необходимо модифицировать?
Если вы отключаете плюсовый рантайм, то сможете использовать лишь
небольшое подмножество языка C++. Без исключений, без RTTI, без
стандартной библиотеки. Так что все эти рецепты по "оптимизации exe"
особого смысла не имеют. Ну станет exe-шник весить 2-3 КБ вместо 50,
принесет ли это радость за такую цену ?
1
DarkMasterW
4 / 4 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 12:00  [ТС] #12
Дык я поэтому и спрашиваю. Я не хочу падать в чистый C. Беда в том, что в .cpp не хочет компилиться(ошибка в 1 посте темы).
0
DrOffset
7996 / 4637 / 1127
Регистрация: 30.01.2014
Сообщений: 7,540
28.01.2015, 12:23 #13
Лучший ответ Сообщение было отмечено DarkMasterW как решение

Решение

Цитата Сообщение от DarkMasterW Посмотреть сообщение
Т.е. код только для C? Под C++ как его необходимо модифицировать?
В С++ имена функций декорируются. Вероятно надо прописать extern "C" той функции, чтобы собралось из C++.
Т.е. я об этом:
C++
1
extern "C" void WinMainCRTStartup()
0
DarkMasterW
4 / 4 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 12:32  [ТС] #14
Уже затестил, все шуршит теперь. Ну почти все. Где-то съезжает по адресации видимо(на С тоже). Выводит иероглифы и 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
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
28.01.2015, 13:54 #15
Цитата Сообщение от DarkMasterW Посмотреть сообщение
C++
1
TextOut(hDC, x, y, szMessage, strlen((const char*)szMessage));
Здесь или приведение к "const char *" нужно исправить, или написать в явном
виде TextOutA/TextOutW.
0
DarkMasterW
4 / 4 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 14:11  [ТС] #16
Цитата Сообщение от Убежденный Посмотреть сообщение
Здесь или приведение к "const char *" нужно исправить
Как раз на него косился. Видимо чутье не подвело. А что с ним не так? Размер съезжает из-за разного количества байт на символ? Я правильно понимаю, что в таком варианте const char * получится длиннее и вернет большее значение не соответствующее количеству символов?
0
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
28.01.2015, 14:17 #17
А Вы подумайте - зачем там вообще потребовалось приведение типов.
Ведь TextOut работает со строками, ничего приводить не нужно.
Если только...
0
DarkMasterW
4 / 4 / 1
Регистрация: 25.10.2013
Сообщений: 230
28.01.2015, 14:17  [ТС] #18
Цитата Сообщение от Убежденный Посмотреть сообщение
или написать в явном
виде 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
ValeryS
Модератор
7219 / 5482 / 682
Регистрация: 14.02.2011
Сообщений: 18,542
28.01.2015, 14:29 #19
Цитата Сообщение от DarkMasterW Посмотреть сообщение
Вроде же все логично, у меня юникод, вызов будет TextOutW.
вот вот!!! а приводишь к чему
Цитата Сообщение от DarkMasterW Посмотреть сообщение
TextOut(hDC, x, y, szMessage, strlen((const char*)szMessage));
в юникроде то длинна строки в байтах в два раза больше
0
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
28.01.2015, 14:30 #20
Так если все в Unicode, надо вместо strlen ставить wcslen.
0
28.01.2015, 14:30
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
28.01.2015, 14:30

Точка входа не найдена
написал dll и создал приложение. Как проге показать эту самую точку входа?

Где точка входа приложения?
В общем, есть 3 файла. Разбирать их содержимое не нужно, меня интересует только...

Точка входа в dll в Linux
Если в Windows точка входа в DLL является функция BOOL WINAPI DllMain(...), то...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru