    СРЕДА РАЗРАБОТКИ 

    приложение С 

    При сборке программ-примеров Вам придется иметь дело с директивами и 
ключами компилятора и компоновщика. Чтобы не засорять ими тексты программ, я 
выделил почти все такие параметры в один заголовочный файл CMNHDR.H, 
включаемый в исходные файлы. К сожалению, некоторые параметры разместить там 
не нельзя, и поэтому пришлось вносить их в make-файл (сборочный файл проекта) 
каждой программы. Здесь мы обсудим, почему я выбрал для компилятора и 
компоновщика именно такие, а не другие параметры, и что они собой представляют. 

    Заголовочный файл CMNHDR.H 

    Все примеры в этой книге включают CMNHDR.H перед остальными заголовочными 
файлами. Я написал его (см. листинг на рис. В-1), чтобы хоть чуть-чуть 
облегчить себе жизнь. Он содержит макросы, директивы компоновщика и прочий 
код, общий для всех программ. Иногда, чтобы что-то попробовать, мне нужно было 
всего лишь модифицировать этот файл и собрать все программы-примеры заново. 
Файл CMNHDR.H находится в корневом каталоге на компакт-диске, прилагаемом к книге. 
    Далее я расскажу обо всех разделах заголовочного файла CMNHDR.H и объясню, 
для чего предназначен каждый из них и как его изменить. 

    Уровень диагностики 4 

    Разрабатывая программы, я всегда стараюсь, чтобы компилятор мог 
транслировать их, не выдавая предупреждений и сообщений об ошибках. Кроме 
того, я предпочитаю устанавливать при компиляции наивысший уровень 
диагностики. В этом случае компилятор делает за меня максимум работы и 
проверяет в коде даже самые незначительные мелочи. Для компиляторов Microsoft 
C/C++ это означает, что я компилировал все примеры с использованием уровня 
диагностики 4. 
    Увы, группа Operating Systems в Microsoft не разделяет моих сантиментов 
насчет компиляции с применением уровня диагностики 4. В общем, когда я 
установил такой уровень, компилятор выдал предупреждения по множеству строк из 
заголовочных файлов самой Windows. По счастью, они не свидетельствуют о 
каких-то проблемах в коде — большинство из них генерируется из-за нетипичного 
употребления конструкций языка С. При этом разработчики полагаются на 
расширения, реализованные практически всеми поставщиками компиляторов. 

    663 

    664 ______________________________Windows для профессионалов 

    Поэтому в первой части CMNHDR.H директива #pragma warning явно требует от 
компилятора игнорировать некоторые часто встречающиеся предупреждения. 

    Версия Windows 

    Поскольку часть моих программ обращается к новым функциям, появившимся 
только в Windows NT 4, в этом разделе определяется символ _WIN32_WINNT: 

    ffdefine _WIN32_WINNT 0х0400 

    Этот макрос нужен потому, что прототипы новых функций в заголовочных 
файлах Windows задаются так: 

    #if (_WIN32_WINNT >= 0х0400) 
    WINBASEAPI 
    BOOL 
    WINAPI 
    TryEnterCriticalSection( 
    LPCRITICAL_SECTION IpCnticalSection 
    ); 
    #endif /* _WIN32_WINNT >= 0х0400 */ 

    Пока Вы сами не определите _WIN32_WINNT (до включения файла WINDOWS.H), 
прототипы новых Win32^yHKi]^ не будут объявлены, и компилятор, встретив 
попытки вызова этих функций, сообщит об ошибках. Microsoft специально защитила 
их символом _WIN32_WINNT, чтобы разработчики, ориентирующиеся как на Windows 
NT, так и на Windows 95, случайно не использовали функции, существующие пока 
только в Windows NT 4. 

    Макрос STRICT 

    При компиляции всех примеров я использую преимущества строгой проверки 
типов, обеспечиваемой заголовочными файлами Windows. Это гарантирует, что 
переменным типа HWND я присваиваю значения именно типа HWND, переменным типа 
HDC — значения именно типа HDC и т. д. Если STRICT определен, компилятор 
выдает предупреждение, встречая, скажем, попытку присвоить переменной типа HDC 
значения типа HWND. 
    Чтобы задействовать строгую проверку типов, макрос STRICT надо определить 
до включения заголовочных файлов Windows. 

    Макросы для переносимости между процессорами 

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

    Unicode 

    Все примеры написаны так, чтобы их можно было компилировать с 
использованием как ANSI, так и Unicode. При компиляции для процессоров х86 — 
чтобы программы работали и в Windows 95 — по умолчанию принимается кодировка 
ANSI. Но для других процессорных платформ при сборке применяется Unicode, что 
ускоряет работу программ. 
    Если Вы хотите создать Unicode-версию программы для процессоров х&6, 
раскомментируйте всего одну строку, в которой определяется макрос UNICODE и 
перекомпилируйте программу. Определяя макрос UNICODE в файле CMNHDR.H, я 
упрощаю себе управление сборкой программ-примеров. Подробнее о Unicode см. 
главу 17. 

    __________________________Приложение В. Среда разработки 665 


    Макрос chDIMOF 

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

    Макрос chBEGINTHREADEX 

    Все многопоточные программы из этой книги используют вместо \Уш32-функции 
CreateThread функцию _beginthreadex из стандартной библиотеки Microsoft С. Это 
связано с тем, что _beginthreadex подготавливает новый поток так, чтобы он мог 
вызывать библиотечные функции, а при его завершении гарантирует уничтожение 
информации, используемой библиотекой в данном потоке (подробнее см. главу 4). 
К сожалению, прототип этой функции имеет вид: 

    unsigned long __cdecl _beginthreadex(void *lpsa, unsigned cbStack, 
    unsigned (__stdcall *) (void *lpStartAddr), void *lpvThreadParm, 
    unsigned fdwCreate. unsigned *lpIDThread); 

    Хотя значения параметров _beginthreadex идентичны значениям параметров 
Win32функции CreateThread, их типы не совпадают. Вот прототип CreateThread: 

    HANDLE CreateThread(LPSECURITY_ATTRIBUTES Ipsa, DWORD cbStack, 
    LPTHREAD_START_ROUTINE IpStartAddr, LPVOID IpvThreadParm, 
    DWORD fdwCreate, LPDWORD IpIDThread); 

    Типы данных \Ут32-функции и ее библиотечного аналога так отличаются 
потому, что группа разработчиков стандартной библиотеки Microsoft С не 
пожелала зависеть от группы разработчиков Operating Systems. Похвальное 
решение, но оно затруднило работу с функцией _beginthreadex в коде, особенно 
если при компиляции определен макрос STRICT. 
    В том, как Microsoft объявила прототип _beginthreadex, есть целых две 
проблемы. Вопервых, некоторые типы данных, используемые этой функцией, не 
совпадают с базовыми типами, примененными в CreateThread. Например, в Win32 
тип данных DWORD определен как: 

    typedef unsigned long DWORD; 

    К этому типу данных относятся параметры cbStack и fdwCreate функции 
CreateThread. Но в прототипе _beginthreadex эти параметры объявлены как 
unsigned, что на деле означает unsigned int. Компилятор считает типы unsigned 
int и unsigned long разными и выдает предупреждение. Поскольку _beginthreadex 
не является частью стандарта языка С и существует лишь как альтернатива 
Win32^yHKHHH CreateThread, я полагаю, что Microsoft следовало бы объявить 
прототип _beginthreadex так, чтобы предупреждения не генерировались: 

    unsigned long __cdecl _beginthreadex(void *lpsa, 
    unsigned long cbStack, 
    unsigned (__stdcall *) (void «IpStartAddr), void «IpvThreadParm, 
    unsigned long fdwCreate, unsigned long *lpIDThread): 

    Вторая проблема — продолжение первой. Функция _beginthreadex возвращает 
значение типа unsigned long — описатель только что созданного потока. Обычно 
программа сохраняет это значение в переменной типа HANDLE: 

    HANDLE hThread = _beginthreadex(...); 

    Эта строка заставит компилятор выдать предупреждение, если при компиляции 
определен макрос STRICT. Чтобы избежать этого предупреждения, надо переписать 
строку с явным преобразованием типов: 

    HANDLE hThread = (HANDLE) _beginthreadex(...): 


    666 ______________________________Windows для профессионалов 

    Это, конечно, неудобно. Чтобы компилятор ко мне не приставал, я определил 
в файле CMNHDR.H макрос chBEGINTHREADEX, который сам делает эти преобразования. 

    Макросы chASSERT и chVERIFY 

    Чтобы упростить выявление ошибок при разработке программ, я часто вкраплял 
в код макросы chASSERT. Этот макрос проверяет, истинно ли выражение х, и, если 
нет, выводит окно с именем файла, строкой и выражением, вычисление которого 
закончилось неудачей. В готовой программе макрос chASSERT раскрывается в 
пустое определение. Макрос chVERIFY практически идентичен предыдущему за 
исключением того, что выражения проверяются не только при отладке, но и в 
готовой программе. 

    Макрос chHANDLE_DLGMSG 

    Используя распаковщики сообщений при работе с диалоговыми окнами, нельзя 
обращаться к макросу HANDLE_MSG из заголовочного файла WINDOWSX.H. Дело в том, 
что он не возвращает TRUE или FALSE в зависимости от того, обработано 
сообщение процедурой диалогового окна или нет. 
    Скрепя сердце, должен признать, что в двух предыдущих изданиях книги я 
допустил ошибку, использовав макрос HANDLE_MSG. Мне просто повезло, что 
программы работали корректно. В новом издании эта ошибка исправлена, и теперь 
в программах задействован макрос chHANDLE_DLGMSG. 

    Макрос chMB 

    Он просто выводит информационное окно, в заголовке которого показывает 
полное имя исполняемого файла вызывающего процесса. 

    Макрос chlNITSTRUCT 

    Этот макрос в файле CMNHDR.H нравится мне больше всего. Я его просто 
люблю! Программируя в Win32, часто приходится создавать какую-то структуру 
данных, обнулять ее и инициализировать первый элемент этой структуры ее 
длиной. Я давно заметил, что многие программисты забывают об одной из таких 
операций. В итоге их вызовы \Уш32-функций проваливаются по непонятной им 
причине или (что хуже!) иногда почему-то срабатывают. 
    Макрос chlNITSTRUCT позволит гарантированно обнулять все элементы любой 
структуры. При этом Вы сможете выбрать, надо ли заносить размер структуры в 
первый ее элемент, — передайте во втором параметре TRUE, и макрос 
инициализирует этот элемент. 

    Макрос chSETDLGICONS 

    Поскольку во многих программах диалоговое окно выступает как основное, его 
значок надо изменять вручную, чтобы он корректно показывался и на панели 
задач, и в окне переключения задач, и в заголовке основного окна программы. 
Макрос chSETDLGICONS — вызываемый всякий раз, когда диалоговое окно получает 
сообщение WM_INITDIALOG, — обеспечивает корректную установку значков. 

    Макрос chWARNIFUNICODEUNDERWIN95 

    Windows 95 не поддерживает Unicode в той мере, как Windows NT, и 
фактически приложения, вызывающие Unicode-функции, просто не будут работать в 
ней! К сожалению, Windows 95 не предупреждает о запуске приложения, 
использующего Unicode. Примени

    __________________________Приложение В. Среда разработки 667 

    тельно к моим программам это означало бы, что они немедленно завершатся 
без всякой диагностики. Поэтому я и создал макрос chWARNIFUNICODEUNDERWIN95, 
который предупреждает меня, что я попытался запустить в Windows 95 программу, 
скомпилированную под Unicode. 

    Вспомогательный макрос Pragma Message 

    Мне всегда хочется, чтобы какая-то часть программы, которую я еще пишу, 
сразу же начала работать, а доводку я обычно откладываю на потом. Так вот, 
раньше, когда мне надо было «завязать себе узелок на память» (дескать, этот 
участок кода еще потребует внимания), я включал в код строки типа: 
    йргадта message("Fix this later") 

    Встречая такую строку, компилятор выдавал мне сообщение, напоминающее, что 
в этом месте работа еще не закончена. Увы, толку от него не очень много. Было 
бы куда полезнее, если бы он сообщал имя исходного файла и номер строки, где 
стоит эта директива. Тогда я не только узнал бы, что какая-то работа не 
доделана, но и смог бы тут же найти нужный участок кода. 
    А для этого не обойтись без набора макросов. В итоге я создал макрос 
chMSG, вызываемый так: 

    #pragma chMSG(Fix this later) 

    Дойдя до соответствующей строки, компилятор выдает что-то вроде: 

    C;\Document\AdvWin\Code\Sysinro.06\..\CmnHdr.H(296):Fix this later 

    Теперь, работая в Visual C++, можно дважды щелкнуть это сообщение в окне 
вывода, и открывается соответствующий файл, а курсор ввода переходит на нужную строку. 
    И еще одна удобная мелочь — макрос chMSG не требует заключать текстовую 
строку в кавычки. 

    Директивы компоновщика 

    Одна из целей, которые я преследовал при написании примеров, — включать в 
make-файл проекта как можно меньше определений, зависимых от различных 
факторов. Я мог бы, например, через диалоговое окно Project Settings в Visual 
C++ добавить в параметры проекта макросы STRICT, UNICODE и _UNICODE, но тогда 
бы я внес в make-файл новую зависимость. Если бы Вы когда-нибудь захотели 
заново создать make-файл, то вполне могли бы забыть о каких-то параметрах, и в 
итоге отдельные программы работали бы неверно. 
    Честно говоря, именно это и произошло со мной. Некоторые DLL требуют 
определенных ключей компоновщика. Когда бы я ни создавал для этих DLL новые 
make-файлы, я всегда забывал о каком-нибудь ключе; DLL, разумеется, работала 
неправильно, и приходилось начинать отладку приложения и DLL, чтобы понять, в 
чем дело. Когда же до меня доходило, что код правилен, но я забыл про какой-то 
ключ, мне хотелось треснуть себя по лбу. 
    Поняв, что это грозит вылиться в серьезную проблему и для меня, и для моих 
читателей, я задался целью удалить из make-файлов все ключи, специфичные для 
конкретного проекта. Начиная с Visual C++ 4.0, ключи компоновщика можно 
указывать в исходном коде программ, для чего служит директива pragma comment. 
Например, код: 
    
    // указываем компоновщику сделать раздел Shared 
    // доступным для чтения и записи, а также общим 
    ftpragma co(nment(linker, "/sectioh :Shared, rws") 

    заставляет компилятор вставить ключ компоновщика в объектный модуль, 
сгенерированный из данного файла. Формируя исполняемый файл, компоновщик 
проверяет, есть ли в 

    668 _____________________________Windows для профессионалов 

    модуле встроенные ключи, и, если да, ведет себя так, будто они заданы ему 
в командной строке. Это очень удобно. 

    CMNHDR.H 
    Модуль; CmnHdr.H 
    Автор: Copyright © 1995-1997, Джеффри Рихтер (Jeffrey Richter) 
    Назначение; Общий заголовочный файл, содержащий полезные макросы 
    и определения, используемые во всех примерах из этой книги. 
    /* отключаем нелепые предупреждения, чтобы можно было */ 
    /* компилировать код при уровне диагностики 4         */ 
    /« нестандартное расширение - однострочный комментарий */ 
    ffpragma warning(disable: 4001) 
    // нестандартное расширение - безымянная структура или объединение 
    #pragma warning(disable: 4201) 
    // нестандартное расширение - типы битовых полей, отличные от int 
    ffpragma warning(disable: 4214) 
    // внимание: создается предкомпилированный заголовочный файл 
    #pragma warning(disable: 4699) 
    // подставляемая функция, на которую нет ссылок, удалена 
    Spragma warning(disable: 4514) 
    // неиспользуемый формальный параметр 
    #pragma warning(disable: 4100) 
    // "тип" не совпадает с "другой тип" при ссылке 
    // на несколько отличающиеся базовые типы 
    ffpragma warning(disable: 4057) 
    // именованный тип определен в скобках 
    ftpragma warning(disaole: 4115) 
    // нестандартное расширение - безопасное переопределение typedef 
    ftpragma warning(dlsable: 4209) 
    ////// Версия Windows ///// //////// /////////// //////// 
    Sdefine _WIN32_WINNT 0х0400 

    Рис. В-1. Заголовочный файл CMNHDR.H 

    _________________________Приложение В. Среда разработки 669 


    РИС. В-1   (продолжение) 

    11111111111/11111/111/1111111 Определение STRICT ////////////////////////////// 
    // во всех ЕХЕ и DLL применять строгий контроль типов 
    ftdefine STRICT 
    111111111/111/111 Макрос для переносимости между процессорами ///////////////// 
    // если целевой процессор не указан, по умолчанию компилируем 
    // для текущей платформы 
    #if !defined(_PPC_) && !deflned(_ALPHA_) && 'defined (MIPS)\ 
    && !defined(_X86_) 
    #if defined (_M_IX86) 
    ftdefine _X86_ 
    ftendif 
    #if defined (_M_MRXOOO) 
    ftdefine _MIPS_ 
    #endif 
    ffif defined (_M_ALPHA) 
    ftdefine _ALPHA_ 
    ftendif 
    #if defined (_M_PPC) 
    ftdefine _PPC_ 
    ftendif 
    ftendif 
    11111111111111111/1111/1111111 Опции для Unicode I I I I I / I / I I I//I 
    II если мы компилируем не для х86, то всегда используем Unicode 
    flifndef _X86 
    ftdefine UNICODE 
    #endif 
    // чтобы компилировать с Unicode на х8б, раскомментируйте следующую строку 
    //ftdefine UNICODE 
    // работая с Unicode-версиями М1п32-функций, надо применять и Unicode-функции 
    // из стандартной библиотеки С 
    ftifdef UNICODE 
    ftdefine _UNICODE 
    #endif 
    1111111111111111/11111111111111 Макрос chDIMOF I I I I I I i I I I I Ц I / 
    I / этот макрос вычисляет количество элементов в массиве 
    Mefine chDIMOF(Array) (sizeof(Array[0])) 

    см. слео. стр. 

    670 ______________________________Windows для профессионалов 


    РИС. В-1   (продолжение) 

    /////////////////////////// Макрос chBEGINTHREADEX //////////////////////////// 
    // Макрос chBEGINTHREADEX вызывает библиотечную функцию _beginthreadex. 
    // Библиотека построена так, чтобы не зависеть от типов данных Win32, например, 
    // HANDEE. Таким образом, программист, работающий в Win32, должен привести 
    // возвращаемое значение к типу HANDLE. Это жутко неудобно, поэтому я написал 
    // этот макрос, выполняющий преобразование типов. 
    typedef unsigned (__stdcall *PTHREAD_START) (void *); 
    ffdefine chBEGINTHREADEX(lpsa,cbStack,IpStartAddr, \ 
    IpvThreadParm, fdwCreate, IpIDTheread)     \ 
    ((HANDLE)_beginthereadex(              \ 
    (void *) (Ipsa),                    \ 
    (unsigned) (cbStack),               \ 
    (PTHREAD_START) (IpStartAddr),      \ 
    (void *) (IpvThreadParm),           \ 
    (unsigned) (fdwCreate),             \ 
    (unsigned *) (IpIDThread))) 
    //////////////////////////// Макросы Assert/Verify //////////////////////////// 
    #define chFAIL(szMSG) {                                          \ 
    MessageBox(GetActiveWindow(), szMSG,                       \ 
    __TEXT("Assertion Failed"),MB J)K : MB_ICONERROR);       \ 
    DebugBreak():                                              \ 
    // выводим окно, которое сообщает о нарушении условия 
    ffdefine chASSERTFAIL(file,line,expr) {                           \ 
    TCHAR sz[128];                                             \ 
    wsprintf(sz, __TEXT("File %d : %hs"), file, line, expr);   \ 
    chFAIL(sz);                                                \ 
    \ 
    // выводим окно, если условие нарушено в отладочном режиме 
    #lfdef _DEBUG 
    ftdefine chASSERT(x) if (!(x))\ 
    chASSERTFAIL(__FILE__, __LINE__, #x) 
    ftelse 
    ftdefine chASSERT(x) 
    #endif 
    // проверка работает только в режиме отладке, 
    // но из готовой программы не удаляется 
    #ifdef _DEBUG 
    ftdefine chVERIFY(x) chASSERT(x) 
    #else 
    ffdefine chVERIFY(x) (x) 
    ffendif 

    см. след. стр. 

    __________________________Приложение В.  Среда разработки 671 


    РИС. В-1   (продолжение) 

    //////////////////////////// Макрос cnHANDLE_DLGMSG I / 1 I I / I I I I i 
    // Обычный макрос HANDLE_MSG из WINDOWSX.H с диалоговыми окнами работает 
    // некорректно, так как функции DIgProc возвращают BOOL вместо LRESULT 
    // (как и функции WndProc). Макрос chHANDLE_DLGMSG исправляет ситуаций. 
    #define chHANDLE_DLGMSG(hwnd, message, fn)                       \ 
    case (message); return (SetDlgMsgResult(hwnd, uMsg,           \ 
    HANDLE_##message((hwnd), (wParam), (IParam), (fn)))) 
    1111111111111111111 Макрос для вывода информационного окна //////////////////// 
    ftdefine chMB(s) {                                                 \ 
    TCHAR szTMP[128];                                          \ 
    GetModuleName(NULL, szTMP, chDIMOF(szTMP)):                \ 
    MassegeBox(GetActiveWindow(), s, szTMP, MB_OK);            \ 
    } 
    /////////////////// Макрос для обнуления ////////////////////// 
    II Заполняет структуру нулями. Если fInitSize равен TRUE. макрос инициализирует 
    // первый элемент типа Int размером структуры. Многие структуры, например 
    // WNDCLASSEX и STARTUPINFO, требуют, чтобы первый элемент содержал их размер, 
    ffdefine chINITSTRUCT(structure, fInitSize)                       \ 
    (ZeroMemory(&(structure), sizeof(structure)),                 \ 
    fInitSize? (*(int*) &(structure) = sizeof(structure)) : 0) 
    ////////////////// Макрос для установки значка диалогового окна ////////////////// 
    /I Вызов SetClassLong рассчитан на Windows NT 3.51 или более ранние версии, 
    // Сообщения WM_SETICON рассчитаны на Windows NT 4.0 и Windows 95. 
    ftdefine chSETDLGICONS(hwnd, idiLarge, idiSmall)                  \ 
    {                                                             \ 
    OSVERSIONINFO Verlnfo;                                     \ 
    chINITSTRUCT(VerInfo.TRUE);                                \ 
    GetVersionEx(&VerInfo);                                    \ 
    if ((Verlnfo.dwPlatformId == VER_PLATFORM_WIN32_NT) &&     \ 
    (Verlnfo.dwMajorVertion <= 3 &&                       \ 
    Verlnfo.dwMajorVertion <= 51)) {                     \ 
    SetClassLong(hwnd,GCL_HICON, (LONG)                    \ 
    LoadIcon(GetWindowInstance(hwnd),                     \ 
    MAKEINTRESOURCE(idilarge)));                      \ 
    } else {                                                   \ 
    SendMessage(hwnd, WM_SETICON, TRUE, (LPARAM)           \ 
    LoadIcon(GetWindowInstance(hwnd),                     \ 
    MAKEINTRESOURCE(idiSmall)));                      \ 

    672    .___________________________Windows для профессионалов 


    РИС. В-1   (продолжение) 

    /////////////////////////// Проверка на UNICODE /////////////////////////////// 
    (tifdef UNICODE 
    Sdeflne chWARNIFUNICODEUNDERWIN95()                              \ 
    if (GetWindowsDirectoryW(NUEE,0) <=0)                         \ 
    MassegeBoxA(NUEE,                                          \ 
    "This operating system doesn't support Unicode.".       \ 
    NUEL. MB_OK) 
    #else 
    Sdefine chWARNIFUNICODEUNDERWIN95() 
    #endif 
    //////////////// Вспомогательный макрос Pragma message //////////////////// 

    когда компилятор видит строку вида: 

    #pragma chMSG(Fix this later) 

    он генерирует сообщение вроде: 

    C:\Document\AdvWin\Code\Sysinro.06\..\CmnHdr.H(296):Flx this later 

    Вы можете перейти прямо на эту строку и проверить окружающий ее код 

    #/ 
    ftdefine chSTR(x)       их 
    ffdefine ch8TR2(x)      chSTR(x) 
    #define chMSG(desc)                                             \ 
    message(_FIEE__"(" chSTR2(__LINE_J"): "(tdesc) 
    //////////////////// конец файла //////////////////////////

 
    Параметры проекта, которые нельзя было задать в исходных файлах 

    Единственное, что Вам, может быть, придется изменить, — параметры в 
разделе Output Directories. Создавая проект, Visual C++ выбирает какой-то 
подкаталог для генерируемых им двоичных файлов. Если Вы собираете исполняемый 
файл, требующий DLL (или библиотеку, связанную с исполняемым файлом), то 
Output Directories надо изменить так, чтобы конечные ЕХЕ- или DLL-файлы 
оказались в одном подкаталоге. 