Создаете консольные приложения без CRT и заголовков по умолчанию?

Я пытаюсь создать консольное приложение без использования CRT или любого другого импорта, кроме kernel32.lib, в любом случае. Я получаю свой код для компиляции, но не могу решить несколько проблем с помощью компоновщика:

unresolved external symbol @__security_check_cookie@4
unresolved external symbol "int __cdecl FreeLibrary(void *)" (?FreeLibrary@@YAHPAX@Z)
unresolved external symbol "void * __cdecl LoadLibraryW(wchar_t *)" (?LoadLibraryW@@YAPAXPA_W@Z)
unresolved external symbol "int (__cdecl*__cdecl GetProcAddress(void *,char *))(void)" (?GetProcAddress@@YAP6AHXZPAXPAD@Z)
unresolved external symbol _wmainCRTStartup

FreeLibrary, LoadLibraryW и GetProcAddress, которые я ввел в программу явно, не используя windows.h:

#pragma comment(lib, "kernel32.lib")

typedef int(*FARPROC)();

void* LoadLibraryW( wchar_t* lpLibFileName );
FARPROC GetProcAddress( void* hModule, char* lpProcName );
int FreeLibrary( void* hLibModule );

Я полагаю, что с моими прототипами что-то не так. Однако более серьезной проблемой являются __security_check_cookie и _wmainCRTStartup, которые, очевидно, имеют какое-то отношение к ЭЛТ. Поэтому мне интересно, как бы я переопределил int wmain(int argc, wchar_t* argv[]) по умолчанию для точки входа и как избавиться от файлов cookie безопасности.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
0
3 613
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Вы можете заглянуть в Windows.h, чтобы увидеть прототипы, необходимые для импорта kernel32. В общем, функции Windows определены WINAPI, который на самом деле является __stdcall, а не __cdecl. По крайней мере, это решит эту проблему.

Что касается другой вашей проблемы, вам нужно изучить аргументы командной строки компоновщика и посмотреть, есть ли способ заставить его не искать что-то в CRT. Я не знаю, есть ли способ сделать это или нет. Но вам придется найти способ или самостоятельно определить эти функции (чего вы, вероятно, не хотите делать).

Я бы рекомендовал просто использовать другой компилятор / компоновщик.

На самом деле я уже пробовал их как стандартные вызовы, и это не решило проблему.

anon6439 20.11.2008 15:31

Правильная точка входа - main(), а не wmain() (поскольку вы компилируете консольное приложение). Код безопасности cookie может быть взят из исходного кода CRT; нет необходимости связывать это.

Ответ принят как подходящий

_wmainCRTStartup - это функция, которая вызывает wmain ()

IIRC, он должен быть доступен в каком-то файле .o, с которым вы можете связать, посмотрите в своем каталоге lib.

Может быть, это тоже полезно прочитать: Уменьшите размер EXE и DLL с помощью LIBCTINY.LIB (и Мэтт Питрек крут :-)

Вам необходимо объявить функции windows.h как extern «C».

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

Как советовал MSalters, код cookie безопасности можно украсть из источника CRT, но, сделав это, я обнаружил, что флаг компилятора /GS- можно использовать, чтобы полностью избежать проблем с безопасностью.

Как сказал SoapBox, функции API должны быть __stdcall, а также точка входа. Я исправил проблему точки входа с флагом командной строки компоновщика /entry:wmain.

И, наконец, как указал Томек, функции API должны быть во внешнем C!

Так:

#pragma comment(lib, "kernel32.lib")

typedef int(*FARPROC)();

extern "C" {
  void* __stdcall LoadLibraryW( wchar_t* lpLibFileName );
  FARPROC __stdcall GetProcAddress( void* hModule, char* lpProcName );
  int __stdcall FreeLibrary( void* hLibModule );
  typedef int (__stdcall *f_MessageBoxW_t)( unsigned long hWnd, wchar_t* lpText, wchar_t* lpCaption, unsigned long uType);
  f_MessageBoxW_t fnMsg;
  void* hUser;
};

int __stdcall wmain(int argc, wchar_t* argv[])
{
  hUser = LoadLibraryW( L"user32.dll" );
  fnMsg = (f_MessageBoxW_t)GetProcAddress( hUser, "MessageBoxW" );
  fnMsg( 0, L"foo", L"bar", 0 );
  FreeLibrary( hUser );
  return 0;
}

Я как раз писал ответ, который включал опцию /entry, когда заметил, что в вашем собственном ответе есть почти все, кроме: 1. Включение windows.h не повредит размеру вашего исполняемого файла ни на бит. Используйте #define WIN32_LEAN_AND_MEAN и #define WIN32_EXTRA_LEAN, если хотите быть уверенными. Заголовки Win32 не включают заголовки CRT, поэтому здесь проблем не возникнет. 2. Вы, вероятно, уже делаете это, но передайте /NODEFAULTLIB компоновщику и сделайте ссылку на kernel32.lib и т. д. Вручную. Это действительно сильно снижает размер исполняемого файла.

rubenvb 14.09.2012 17:02

Более правильное объявление точки входа будет:

int __stdcall wmain(PVOID ThreadParam)

Без точки входа CRT, вызываемой напрямую BaseThreadInitThunk. Он передает указатель на что-то, но не на argc + argv.

Другие вопросы по теме