Ошибка недопустимая лексема computeruniverse

По нерасторопности пользователей либо из-за технически сбоев  на сайте интернет-магазина могут возникать проблемы авторизации под своим логином и паролем личной учетной записи. Сначала стандартно перепроверяется раскладка клавиатуры, активна ли функция «Caps Lock» (ввод заглавных букв) или нет, произодится поиск проблем в самом интернет-браузере на компьютере (чистка cookies, смена браузера).

Если озвученные мероприятия не принесли успех и причина явно не в техническом сбое на хостинге онлайн магазина, то прибегают к сбросу и замене пароля на новый. Данная процедура в интернет-магазине Comuteruniverse в целом стандартна. Для начала нужно найти ссылку «Забыли пароль?» мелким шрифтом в выпадающем окне вверху страницы.

забыл пароль компьютеруниверс
  После ввода своего адреса электронной почты необходимо кликнуть по «Запросить пароль!».

запросить пароль computeruniverse

Проверка адреса электронной почтыПридет письмо со ссылкой, по которой необходимо будет перейти на страницу смены пароля учетной записи computeruniverse.ru.

сброс пароля личной учетной записи computeruniverse
На новой странице будут приведены общие рекомендации для выбора нового пароля:

  • Пароль должен насчитывать не менее 6 символов.
  • Используйте буквы и цифры.
  • Не используйте в качестве пароля части вашего логина или адреса электронной почты!
  • Не используйте в качестве пароля слова «пароль», «кодовое слово» или «парольная фраза»!
  • При вводе старайтесь избегать сочетания букв/цифр, следующих друг за другом на клавиатуре или в алфавите, например, «1234», «qwertz» или «abcde»!

Например, если использовать при вводе нового пароля часть логина, система не одобрит изменений и предложить подобрать другую комбинацию для входа в учётную запись.

выбрать новый пароль для www.computeruniverse.ru
При соблюдении всех правил на новой странице вы увидите такое сообщение, а по клику «Стартовая страница сообщества» можно будет попасть в свою личную учетную запись Computeruniverse.

пароль успешно изменён
Всё теперь можно делать покупки в магазине, проверять состояние своих заказов или отслеживать передвижение посылки. В идеале во избежание таких проблем, конечно же, лучше хранить все логины и пароли на внешнем цифровом носителе,а при необходимости прибегать к помощи такой «шпаргалки», но, к сожалению, не всегда всё можно продумать наперёд.

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

Модераторы: Varg, 4e_alex

Автор Сообщение
 

Прилепленное (важное) сообщение

СообщениеДобавлено: 03.08.2013 21:20 

[профиль]

Junior

Статус: Не в сети
Регистрация: 01.01.2011

Тема-обсуждение немецкого интернет-магазина computeruniverse

ПРИЁМ ЗАКАЗОВ ИЗ РФ ПРИОСТАНОВЛЕН МАГАЗИНОМ С 1 МАРТА 2022 ГОДА

MINI FAQ

С 1 января 2020 года необлагаемый налогом лимит — €200 на посылку. С суммы превышения лимита — налог 15% (например, с €201 налог будет 15 евроцентов, с €300 — €15 и т.д.).
Новый Таможенный Кодекс ЕАЭС.

С превышения до ~€15 (т.е. сумма покупки до ~€215) налог могут и не начислить.

В период с 17 марта до 1 октября 2022 года лимит временно увеличен обратно до €1000.
https://www.interfax.ru/business/829862
Повышенный порог сохранён до 1 апреля 2023 года: https://ria.ru/20220923/eaes-1819028696.html

Краткий, постоянно обновляемый справочник — на первой странице темы.
Читайте его перед тем как спрашивать — практически все ответы там есть.

С 15 января 2018 года нотификация товаров в посылках для частных лиц отменена:

computeruniverse.net (ПРИЁМ ЗАКАЗОВ ИЗ РФ ПРИОСТАНОВЛЕН) [+FAQ] #15289929

Нужен ли ИНН для покупок в этом магазине?
Нет, посылки из CU в Россию доставляются силами Почты РФ, на которую данное нововведение не распространяется.

Почему товары в CU стоят дёшевле, нежели в РФ?
Согласно таможенному законодательству, трансграничные покупки не облагаются НДС. Он просто не платится никем, в т.ч. и получателем заказа. Отсюда меньшая цена.

Флудерам с их вопросами «а чего бы тут не купить, всего пара тысяч разница?»: на ваших видеокартах свет клином не сошёлся и жизнь за МКАД не заканчивается. Во-первых, есть множество позиций, которые стоят зачастую вдвое-втрое дешевле (NAS, SSD, память). Во-вторых, люди обычно берут по три-шесть и более позиций, разница выходит уже не копеечная. В-третьих, не все живут в Москве и крупных городах, для живущих в глубинке с их торговыми точками по три-пять позиций в прайсе, да и те под заказ, совершенно монописуально, откуда заказывать, и для них CU — шанс сделать это не только дешевле, но и приобрести то железо, которое в местных магазинах не купить даже под заказ.

Премиум-упаковка — пустая трата 4 евро.

Тема по совместным закупкам — здесь:

Совместные покупки (сборные заказы) в computeruniverse

Если у вас карта Сбербанка РФ, то платите через PayPal, а не напрямую — очень часты случаи «задваивания» платежа (один раз сумма списывается сразу, затем, спустя несколько дней — происходит повторное списание этой же суммы, если денег на второе списание не хватит, платёжная система может прислать магазину отказ и заказ не будет оформлен, первый платёж при этом на карту в любом случае не вернётся, необходимо будет обращаться в Сбербанк).

Реклама

Партнер
 
Resso

Member

Статус: Не в сети
Регистрация: 14.04.2016

Leonator писал(а):

Подождем завтрашней ММВБ, куда курс пойдет, туда и мир с лагом и наценкой, но двинется. Не будет больше такого, что в миру рубль 120, а здесь 80 за енота.

Курс будет 60 рублей за доллар к концу мая и июне. Торговое сальдо в России сейчас сильно искажённое. Экспорт из России 80%. Импорт в Россию всего 20%, так как торговые цепочки разрушились и наложено эмбарго на ввоз множества товаров. Ритейлеры, промежуточные поставщики хотят купить и привезти товар, но не могут. А если не могут, то и валюта для покупки им не нужна. Отсюда переизбыток валюты. Внутренний спрос на доллары и евро уменьшается. Цена падает. Рубль временно и быстро укрепляется. Потом летом экспорт из России начнёт уменьшатся, когда введут эмбарго на нефть и начнёт действовать эмбарго на уголь, металл. А импорт увеличиваться, так как придётся всё равно завозить необходимую продукцию, даже если параллельным импортом. Сальдо немного выравняется, рубль снова начнёт слабеть, к концу года курс будет 80-100 за доллар.

Overc писал(а):

Господа. Здравствуйте. Сейчас совсем нет вариантов доставить посылку даже через знакомых из Германии?

А смысл? Доставку то всё равно делать на немецкий адрес этих знакомых. Или им самим идти в магазин и покупать. И цена будет +19% немецкого НДС, а не та что указана на сайте при выборе Россия. Выбери там Германия цена будет выше. Вся супер фишка компьютеруниверса для России была именно в этом. В вычете -19% НДС. Если цена не важна, может тебе какой-то товар там редкий нужен, который только там, то можешь через немецких знакомых. А если с целью сэкономить, то знакомые нужны из Казахстана или Армении.


_________________
Ryzen 5900X • Msi B350 Gaming Pro Carbon • 4x8Gb G.Skill FlareX B-die • Gainward GTX 1080 Ti Phoenix GS • Corsair RMx 650 W • LG 34UC89G

 
antagonist

Member

Статус: Не в сети
Регистрация: 12.05.2013
Откуда: я знаю
Фото: 0

Resso писал(а):

то знакомые нужны из Казахстана

Интересно, казахский днс в Россию не отправит?) Или может есть какие посредники для покупки там и отправки сюда? Никто не в курсе где искать их проверенных?
Из Омска до Петропавловска 300км, омичам можно сесть в машину, съездить и купить там
3060 там 50к на наши деньги, 3070 по 70к, а у нас такие же по 80 и 140 втюхивают, ублюдки барыжьи


_________________
«Кто не рискует — тот не получает премию Дарвина»

Последний раз редактировалось antagonist 11.05.2022 14:28, всего редактировалось 1 раз.

 
Leonator

TSC! Russia member

Статус: Не в сети
Регистрация: 31.08.2005
Откуда: Петербург
Фото: 0

https://tass.ru/ekonomika/14594919

?
Это уже какое-то бесстыдство, игнорят неудобный для них курс, чтобы не мешал рисовать свой, в котором бензоколонка порвана в клочья.
Спекули хорошо на этом заработают, купил здесь — продал там.


_________________
www.btbooks.ru, www.forums.btbooks.ru — официальный русскоязычный фансайт Battletech

 
Andy-S

Member

Статус: Не в сети
Регистрация: 15.09.2009
Фото: 0

игнорят неудобный для них курс, чтобы не мешал рисовать свой

На форексе бакс 63 сейчас, пусть игнорят. 20 мая уже рядом, если газ половине европки закроют, будет евро по писят или ниже. Правда, ставку цб понизит скорее всего.

 
Beznagyoga1

Junior

Статус: Не в сети
Регистрация: 13.05.2022

Resso писал(а):

А если с целью сэкономить, то знакомые нужны из Казахстана или Армении.

Добрый день, а не подскажите уже при пересылку из Казахстана в Россию какие-то проблемы таможенного характера могут возникнуть?

 
Gabberun

Junior

Статус: Не в сети
Регистрация: 14.05.2022

Добрый день! Искал информацию, но единой картины в голове не сложилось.
Скажите, сейчас пройдет заказ из магазина computeruniverse.net с доставкой в Армению и оплата картой резидента Армении?!
Хотел сделать заказ с доставкой в Армению, а потом переслать в РФ.

 
eRzZz

Member

Статус: Не в сети
Регистрация: 02.12.2011
Откуда: Новокузнецк
Фото: 3

Beznagyoga1 писал(а):

Добрый день, а не подскажите уже при пересылку из Казахстана в Россию какие-то проблемы таможенного характера могут возникнуть?

Отправляйте Boxberry из Казахстана и ни каких проблем с таможней. СДЕК в этом плане шизанутые. Пытался отправить товарищу в Алма-ату мат. плату с памятью все бу, так в СДЕКе меня попросили сертификаты из магазина где я все это брал. А я живу в Новокузнецке(Сибирь) , а брал все это в Мск три года назад,память вообще брал тут на оверах, что я им должен предоставить?)) В Boxberry вообще не о чем особо не спрашивали,помогли упаковать и посылка с железом через 10 дней была у товарища.


_________________
Если все присутствующие говорят про Вас только хорошее — значит это Ваши похороны!

 
H_Awk

Member

Статус: Не в сети
Регистрация: 26.08.2010

Кто встрял на бабки есть хорошая беседа вк с таблицей пострадавших от «кидалова» именно так мы считаем отказ альтернативного возврата и всеми предпринятыми шагами по чарджам итд. Админ не удаляй может поможет кому понять что произошло.
ссылка вк
https://vk.me/join/8mG7zOHdYe22guOOAHnaY2o9d3Ujc5ciACQ=


_________________
msi p67☞2500k⇒4600 ϟ 1.285V☞macho☞powercolor★7970★V3☃AceleroXtreme☞ϟϟ ETG850☞plextor128; Londisk480☞16gb⇒1867(9-9-9-24CR2)

 
Frost

Member

Статус: Не в сети
Регистрация: 28.08.2010

Мейкун можно спросить самих посредников возят они или нет.


_________________
Ryzen7 7950X / Asus X670E Hero / G.Skill TridentZ Neo 2x32GB (F5-6000J3040G32GX2-TZ5N) / KFA2 RTX4090 / CustomWater

 
yerrtd

Member

Статус: Не в сети
Регистрация: 23.11.2021

Yag0r писал(а):

заказывал память в CU

Вот у меня вопрос к вам. А разве ндс не нужно платить если на склад в ЕС отправлено с CU? Благодарю.


_________________
i7 12700k/MSI MPG Z690 EDGE WIFI DDR4/Crucial Ballistix 64/MSI RTX 3080 Ti SUPRIM X/Noctua NH-D15S/Fractal Design Ion+ 760P/PHANTEKS Eclipse P600S

 
Leonator

TSC! Russia member

Статус: Не в сети
Регистрация: 31.08.2005
Откуда: Петербург
Фото: 0

yerrtd Придется платить конечно. Поэтому и берут так если очень надо.


_________________
www.btbooks.ru, www.forums.btbooks.ru — официальный русскоязычный фансайт Battletech

 
Мейкун

Member

Статус: Не в сети
Регистрация: 16.08.2012

yerrtd писал(а):

Вот у меня вопрос к вам. А разве ндс не нужно платить если на склад в ЕС отправлено с CU? Благодарю.

а куда деваться, если дешевле всё-равно нету.

 
smaximaa

Member

Статус: Не в сети
Регистрация: 22.04.2016
Фото: 36

Кто нибудь пробовал покупать с КУ через Бандерольку?

https://qwintry.com/ru/shop-help


_________________
RM650x | CH VII HERO (WI-FI) | Ryzen 9 3900x CTR 2.0 RC5 | 2*16 Micron E-die 3763 16-16-19-16 1.38 | Palit GTX 1080Ti SjS (GRP bios)

 
Yag0r

Junior

Статус: Не в сети
Регистрация: 23.05.2022
Фото: 1

yerrtd писал(а):

А разве ндс не нужно платить если на склад в ЕС отправлено с CU?

Да заплатить VAT пришлось, но почему то вот это Samsung 980 PRO 1 ГБ M.2 никак не желает дешеветь на нашей территории. и курс был тогда 100 и все равно выгодней получилось

У вас нет необходимых прав для просмотра вложений в этом сообщении.

 
cultivated

Member

Статус: Не в сети
Регистрация: 08.07.2016
Откуда: МОСКВА

Для заказа через qiwi в долларах, надо ставить версию 8.28.0 пока работает.

 
el_cucui

Junior

Статус: Не в сети
Регистрация: 11.04.2018

smaximaa писал(а):

Кто нибудь пробовал покупать с КУ через Бандерольку?

https://qwintry.com/ru/shop-help

У них в группе ВК люди заказывают, только до порога 750 евро и не авиаперевозкой

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Лаборатория

Новости

flowxrc

Участник


    Автор темы

  • #1

#define NOMINMAX
#include <cmath>
#include <filesystem>
#include <algorithm>
#include <math.h>
#include <iostream>

template < typename t >
__forceinline void clamp(t& n, const t& lower, const t& upper) {
    n = std::max(lower, std::min(n, upper));
}

ошибка тут: std::max
в редакторе пишет что всё нормально а при компиляции выводит ошибку

sove


  • #2

#define NOMINMAX
#include <cmath>
#include <filesystem>
#include <algorithm>
#include <math.h>
#include <iostream>

template < typename t >
__forceinline void clamp(t& n, const t& lower, const t& upper) {
    n = std::max(lower, std::min(n, upper));
}

ошибка тут: std::max
в редакторе пишет что всё нормально а при компиляции выводит ошибку

а зачем тебе эта функция, если она делает тоже самое, что и std::clamp……………..

flowxrc

Участник


    Автор темы

  • #3

а зачем тебе эта функция, если она делает тоже самое, что и std::clamp……………..

я чё знаю? я пасту делаю, вижу там функция такая есть значит надо спастить
а так спасибо

ставь чайник, зажигай плиту

Flowseal

Эксперт


  • #4

#define NOMINMAX
bruh

std::max(lower, std::min(n, upper));

flowxrc

Участник


    Автор темы

  • #5

на другом форуме сказали так сделать но не помогло

sove


  • #6

на другом форуме сказали так сделать но не помогло

мужик…………………..
просто удали эту функцию………………..
и все………………………………………

flowxrc

Участник


    Автор темы

  • #7

мужик…………………..
просто удали эту функцию………………..
и все………………………………………

давно сделал уже проблема решена

Немецкий магазин Computeruniverse ≠ хвалёная немецкая пунктуальность. В это сложно поверить, если ты новичок. У нас же за плечами 10-летний опыт работы с этим интернет-магазином, и, поверь, нам есть, что тебе рассказать! В этой статье мы поговорим о проблемах работы сайта и о плохой работе техподдержки Computeruniverse.

У некоторых покупателей Computeruniverse проблемы начинаются буквально сразу же: например, сайт обваливался на стадии оплаты, деньги списались, а заказ не сформировался или зависла корзина. И, если за несколько лет магазину удалось исправить серьезные баги, связанные с потерей денег, то поддержка магазина с каждым годом работает все хуже и хуже.

Технологическая отсталость магазина

Неоднократные зависания и ошибки в процессе оплаты и в личном кабинете – это только вершина айсберга.

Если ты начинающий покупатель на Computeruniverse, то вряд ли догадываешься о том, что в сформированный заказ нельзя просто так добавить какие-либо товары или заменить позиции по одному щелчку. Звучит странно, ведь в любом другом интернет-магазине (например, yandex market, Ozon или Wildberries) проделать всё то же самое, вплоть до возврата денег, не составляет труда. Но только не на Computeruniverse! Для выполнения всех этих элементарных действий, тебе придется неоднократно писать или звонить немцам. Иногда, за отмененный заказ деньги приходится буквально выпрашивать.

Магазин может в одностороннем порядке удалить один из товаров в заказе и отправить заказ без него, если моментально на это не отреагировать. При этом стоимость доставки не пересчитывается.

Заменить отсутствующий товар тоже не так просто, как кажется на первый взгляд. Магазин игнорирует письменные обращения покупателей. Поэтому, для замены требуется совершить телефонный звонок на немецком или английском языках. Русскоговорящих работников в computeruniverse нет.

Тот случай, когда магазин в одностороннем порядке удаляет позицию из заказа.

Поддержка из 90-х

В магазине нельзя оперативно связаться с поддержкой. Даже, если звонить по телефону, иногда можно потратить целый день и не дозвониться. Большинство сообщений на email магазин игнорирует. 90% работников в поддержке на телефоне некомпетентные и не способны решить иногда даже простейших вопросов с заказом.

Обслуживание по гарантии можно получить только с боем

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

Неверные статусы товаров на сайте.

Как показала практика, до 30% статусов наличия товаров на сайте – неверные. Это происходит в том числе потому, что магазин делает запрос поставщику только после того, как покупатель оплатит заказ и его проверит сотрудник магазина. По факту на складе магазина очень мало товаров, которые можно отправить сразу. Об этом мы писали в отдельной статье.

Если на сайте написано, что остался последний товар – не спишите его покупать, возможно его уже купили до вас. Дело в том, что информация о доступности товаров не обновляется в этом магазине в режиме реального времени.

Товар в наличии? Отправка сразу? Не тут-то было!

К сожалению, если ты видишь статус В наличии и готов к отправке – это далеко не означает, что магазин отправит твой заказ на следующий день. Первая ситуация: статус ложный и товара на самом деле нет в наличии, на это может быть много причин – в том числе и тот случай, когда его сняли с производства, а магазин не удосужился это проверить. Вторая ситуация: товар все-таки есть на складе, но по каким-то неведанным причинам заказ не двигается с места и прибывает в статусе “Готов к поставке и зарезервирован за вами”. Даже пройдя этот статус, и перейдя на этап подготовки к отправке, заказ может зависнуть в этом положении на 1-2 недели и протолкнуть его иногда удается только с помощью жалоб в поддержку.

Итоги:

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

Так же учтите, что обращаясь к неопытным посредникам, не стоит рассчитывать, что они смогут решить все ваши вопросы и проблемы с заказом элементарно в силу отсутствия опыта или знания языков. Помните, что несколько успешно совершенных заказов – это не победа, а счастливая случайность.

050918 — 18 сентября 2005

Столкнулся с ошибкой линкера LNK2019:

module.obj : error LNK2019: unresolved external symbol __imp__mciSendCommandA@16 referenced in function «long __stdcall WndProc(struct HWND__ *, unsigned int, unsigned int, long)» (?WndProc@@YGJPAUHWND__@@IIJ@Z)

Устранил ошибку следующим образом:
— Нашёл (через HelpIndex…) подпрограмму mciSendCommand. В конце справки там была указана используемая библиотека с этой функцией — Winmm.lib.
— Через ProjectИмяПроекта Properties…Configuration PropertiesLinkerInputAdditional Dependencies добавил в список библиотек Winmm.lib.

051001 — 1 октября 2005

Полную информацию по процессу линковки даёт опция линкера /VERBOSE, устанавливается через ProjectИмяПроекта Properties…Configuration PropertiesLinkerGeneralShowProgressDisplay All Progress Messages (/VERBOSE). Иногда HelpIndex… даёт неверное имя библиотеки. Тогда может помочь поиск по содержимому всех файлов c:Program FilesMicrosoft Visual Studio .NET 2003Vc7PlatformSDKLib*.lib, на появление строки с искомой функцией (для нашего примера mciSendCommand). Один из найденных файлов надо добавить в список библиотек (через ProjectИмяПроекта Properties…Configuration PropertiesLinkerInputAdditional Dependencies).

Можно использовать целые типы INT и UINT, которые являются производными от int и unsigned int (задаются в файле windef.h).

Для получения помощи по функции в коде иногда лучше не просто нажать F1, когда курсор стоит на имени функции, а скопировать имя функции в поле LookFor окна поиска HelpIndex… — тогда будут видны все варианты описаний прототипов функции.

051014 — 14 октября 2005

rand()%n;

Изменение поведения (кода) методов класса — открыть исходный файл *.cpp нашего нового класса, и выбрать в меню ViewProperties Window (или нажать Alt+Enter). В появившемся окне нажать кнопку Overrides (на ней значок в виде зелёного кубика). Появится список методов класса. Выбираем нужный метод, выбираем из выпадающего списка имя_метода. В модуль класса вставляется пустышка, которую предстоит изменить для доработки поведения метода класса.

В конструкторе класса окна m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);

Что происходит, когда мы добавляем (привязываем) переменную к ресурсу (например, полю ввода)? Когда мы добавляем переменную, связанную с ресурсом окна ввода, то на самом деле в *.h-файл, описывающий класс главного окна (например, диалога, в котором есть окно ввода), добавляется в раздел public класса главного окна добавляется переменная. В моём примере *.h-файл ciconfigDlg.h описывал класс главного диалогового окна CciconfigDlg (тип CDialog), и в этом файле в раздел public описания класса CciconfigDlg добавлялась переменная CEdit IPaddress.

Два метода получить текст из переменной типа CEdit (переменной, связанной с окном ввода). В нашем случае переменная, куда считываем текст, это CString ip, а переменная CEdit IPaddress связана с ресурсом окна ввода IDC_EDIT1.

CString ip;
GetDlgItemText (IDC_EDIT1, ip);
IPaddress.GetWindowText(ip);

Когда меняем свойства ресурса, то меняется его текстовое описание в файле *.rc. Например, имеем IDC_LIST1 (окно — список вывода) и связанную с ним переменную CListBox LogList. Если у IDC_LIST1 свойство Sort == False, то описание у него в *.rc-файле будет таким:

LISTBOX  IDC_LIST1,7,36,306,157,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP

Если Sort == True, то таким:

LISTBOX IDC_LIST1,7,36,306,157,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP

Указатель на экземпляр класса диалогового окна можно получить с помощью ключевого слова this

void CciconfigDlg::OnBnClickedButton1(){
   // TODO: Add your control notification handler code here
   ...
   pSocket = new CClientSocket(this);
   ...}

В этом примере вызов конструктора CClientSocket требует параметра, который содержит указатель на главное окно диалога (им инициализируется внутренняя переменная).

Ошибка Compiler Error C2582 ‘operator =’ function is unavailable in ‘class’ возникает, когда в правой части стоит указатель на экземпляр класса, в котором нет определения оператора «=». Например, наш класс, не имеющий этого оператора CciconfigDlg. На выражение присваивания

CClientSocket::CClientSocket(CciconfigDlg* Dlg){
   m_Dlg = Dlg;}

генерится ошибка C2582. Тогда лечится проблема добавлением определения оператора «=» в заголовочный файл класса CciconfigDlg.h:

public:
...void operator = (const CciconfigDlg& bbb){};

Здесь bbb произвольное имя. Кроме того, эта ошибка может возникнуть тогда, когда в левой части выражения с «=» стоит не указатель на экземпляр класса CciconfigDlg, а сам экземпляр класса, например, переменная m_Dlg определена ошибочно вот так:

class CClientSocket : public CSocket{
   public:
   ..
   protected:
   CciconfigDlg m_Dlg;};

а нужно вот так, тогда ошибки C2582 не будет даже без определения оператора «=» в классе CciconfigDlg:

class CClientSocket : public CSocket{
   public:
   ..
   protected:
   CciconfigDlg* m_Dlg;};

Текстовую метку можно поменять командой:

m_Dlg->SetDlgItemText(IDC_STATIC, "new label text");

где m_Dlg — указатель на экземпляр класса окна диалога, в котором размещена данная метка.

При работе с CSocket нужно быть осторожным с ->Close() и delete — например, эти функции вызывать в обработчике кнопки, в котором создался экземпляр CSocket, иначе не получает управления обработчик приёма ::OnReceive.

Нельзя никакие операции, вызывающие блокировку, выполнять в обработчиках событий кнопок, иначе приложение «виснет», пока не закончится операция. Такие операции нужно запускать в отдельном потоке.

Частенько бывает что нужно воспользоваться некоторыми функциями WinAPI, но если проект создается с поддержкой MFC, то ничего не выходит. Для вызова функций WinApi из MFC используй оператор :: перед именем функции, например ::GetWindowText(hWnd, ….

Использование опции вывода «wt» подпрограммы fopen выводит в файл дополнительные символы r в конце каждой строки.

060125 — 25 января 2006

В Visual Studio есть очень удобный менеджер конфигураций проекта. Конфигурация — это набор установок для компилируемой и линкуемой программы. По умолчанию существует 2 конфигурации — Debug и Release, назначение которых очевидно из названия. Когда я научился их применять (достаточно в тулбаре выбрать одну из них в выпадающем списке) — одну для отладки, другую для получения готового приложения, то мне захотелось автоматически упаковывать exe-шник релиза упаковщиком AsPack. Оказалось, для этого можно воспользоваться Build Evens:

— Projectимя_приложения Properties…, выбираем тип конфигурации Release
— Build EventsPost Build EventCommand Line, вставляем туда «c:Program FilesAsPackASPack.exe» «$(ProjectDir)$(OutDir)$(TargetFileName)» /Q /B-

Здесь «$(ProjectDir)$(OutDir)$(TargetFileName)» означает полный путь к упаковываемому экзешнику (путь этот составлен из специальных макроопределений Visual Studio), а /Q /B- просто опции для AsPack, которые указывают без вопросов всё сделать и не делать бэкапа.

— для отладки макроопределений удобно в командную строку Build Event подставить команду echo макроопределение(я) >testfile.txt. В результате в файле testfile.txt можно прочитать, что подставляется вместо макроопределения.

060203 — 3 февраля 2006

Глобальные переменные в C++ можно определять как внутри основного тела программы _tmain, так и до нее — сразу после одной или нескольких (если есть) строк include. Инициализировать переменные, объявленные до _tmain, можно только вместе с объявлением.

Уже существующие (написанные ранее) процедуры из файлов *.cpp удобно использовать следующим образом:

— наш *.cpp файл с нужными функциями переписываем в корневую папку проекта;
— добавляем *.cpp файл в проект — в Solution Explorer щёлкаем правой кнопкой на папке Source Files, выбираем AddAdd Existing Item…, выбираем наш файл *.cpp;
— в тело модуля, где вызывается процедура любая процедура из *.cpp (в этом примере процедура WLog), вставляем в глобальный блок объявления extern:

extern void WLog (CString S);

В процессе написания программы целесообразно изредка переключаться в режим компилирования Release, потому что при этом могут вылезать неожиданные ошибки (не проявляющие себя в режиме компилирования Debug).

060212 — 12 февраля 2006

compound-statement означает простой набор операторов за фигурными скобками (или один оператор).

060225 — 26 февраля 2006

Оказывается, любые константы, у которых не указана разрядность (или тип), по умолчанию считаются компилятором за 32-х разрядные, то есть, например, если мы укажем 0xE0, то это на самом деле будет означать 0x000000E0. На первый взгляд, ну и что тут такого? Однако из-за приведения типов это может порождать непредсказуемый результат. Например, вариант 1 нерабочий, а вариант 2 работает нормально.

//Вариант 1:
...char ch0;
...
 switch (ch0){case 0x00:
   ...
   break;case 0xE0:
   ...
   break;default:
   ...}
 //Вариант 2:
...char ch0;
...
 switch (ch0){case (char)0x00:
   ...
   break;case (char)0xE0:
   ...
   break;default:
   ...}

В варианте 1 по метке case 0xE0 управление НИКОГДА не передаётся, независимо от значения переменной ch0. Дизассемблирование показывает, что в начале оператора switch происходит приведение переменной к типу int с помощью инструкции movsx, которая заполняет все старшие биты слова битом 7 значения 0xE0, то есть получается при этом 0xFFFFFFE0. Далее это значение по метке case 0xE0 уже сравнивается с 0x0000000E0. Пример дизассемблированного кода варианта 1:

switch (ch0)
0049436A movsx eax,byte ptr [ch0] ;тут 0xE0 превращается в 0xFFFFFFE0
0049436E mov dword ptr [ebp-190h],eax
00494374 cmp dword ptr [ebp-190h],0
0049437B je 0049438B
0049437D cmp dword ptr [ebp-190h],0E0h; а тут сравн. 0xFFFFFFE0 с 0x000000E0
00494387 je 00494391 ; по метке 00494391 управление НИКОГДА не передается
00494389 jmp 00494397 { case 0x00:...
0049438B ...break;
0049438F jmp 004943A3 case 0xE0:...
00494391 ...break;
00494395 jmp 004943A3
default: ...
00494397 ...
0049439A ...
0049439B ...
004943A0 ...
}
004943A3 jmp
...

Само собой, 0xFFFFFFE0 никогда не равняется 0x0000000E0, и код не работает.

В заключение привожу правильный код варианта 2:

switch (ch0)
0049436A mov al,byte ptr [ch0]
0049436D mov byte ptr [ebp-190h],al
00494373 cmp byte ptr [ebp-190h],0E0h
0049437A je 0049438D
0049437C cmp byte ptr [ebp-190h],0
00494383 je 00494387
00494385 jmp 00494393 { case (char)0x00:...
00494387 ...break;
0049438B jmp 0049439F case (char)0xE0:...
0049438D ...break;
00494391 jmp 0049439F
default: ...
00494393 ...
00494396 ...
00494397 ...
0049439C ...
}0049439F jmp
...

Другой метод побороть проблему — применить тип переменной unsigned.

060302 — 2 марта 2006

   Перехват Ctrl-Break в консольном приложении можно установить с помощью функции SetConsoleCtrlHandler — позволяет, кроме того, реагировать на Ctrl-C и события закрытия консоли. Пример:

1. Описываем обработчик консоли:

BOOL CtrlHandler( DWORD fdwCtrlType )/* Обработчик исключительных ситуаций консоли, типа нажатия на Ctrl-Break 
или щелчка на кнопке с крестиком */
{ CString ctrl_message_descr; switch( fdwCtrlType ) { // Handle the CTRL-C signal. case CTRL_C_EVENT: //поскольку мы запустили поток, обрабатывающий клавиатурные // нажатия, сюда управление никогда не попадает ctrl_message_descr = "Ctrl-C event"; WLog (ctrl_message_descr); return( TRUE );   // CTRL-CLOSE: confirm that the user wants to exit. case CTRL_CLOSE_EVENT: ctrl_message_descr = "Ctrl-Close event"; WLog (ctrl_message_descr); CleanUp(); bStop = true; Beep( 600, 200 ); return ( FALSE );   // Pass other signals to the next handler. case CTRL_BREAK_EVENT: ctrl_message_descr = "Ctrl-Break event"; WLog (ctrl_message_descr); printf (ctrl_message_descr); CleanUp(); bStop = true; Beep( 900, 200 ); return FALSE;   case CTRL_LOGOFF_EVENT: ctrl_message_descr = "Ctrl-Logoff event"; WLog (ctrl_message_descr); printf (ctrl_message_descr); CleanUp(); bStop = true; Beep( 1000, 200 ); return FALSE;   case CTRL_SHUTDOWN_EVENT: ctrl_message_descr = "Ctrl-Shutdown event"; WLog (ctrl_message_descr); printf (ctrl_message_descr); CleanUp(); bStop = true; Beep( 750, 500 ); return FALSE;   default: ctrl_message_descr = "Unknown event!!!"; WLog (ctrl_message_descr); printf (ctrl_message_descr); CleanUp(); bStop = true; return FALSE; } }

2. Инициализация в начале main:

...if( SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ) ) { 
   if (iDebugLevel == 1)
      WLog("Control Handler (Ctrl-Break interception) is installed.");} else {
   messtr = "ERROR: Could not set control handler";
   WLog(messtr);
   printf(messtr);
   nRetCode = 2;
   Error = true;}
...

См. также, как выполнять действия при выходе из программы Win32 (функция atexit()).

060710 — 10 июля 2006

В dialog-based MFC приложении размер диалоговой формы задается в rc-файле, в строке с ключевым словом DIALOGEX, например:

IDD_QOSTEST_DIALOG DIALOGEX 0, 0, 402, 236

где QOSTEST — имя класса окна, 402 — размер по горизонтали, 236 — по вертикали. Окно About получает свои размеры аналогично:

IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55

Чтобы точно изменить размеры окон, придется вручную подредактировать числа, в самом Visual Studio можно менять размеры только перетаскиванием мышью.

Многострочное окно текста можно выводить, воспользовавшись простым Edit Control (обычно он используется для редактирования однострочного текста). По шагам:

— перетаскиваем его на конструируемое окно.
— меняем размеры перетаскиванием границ. Для того, чтобы выбрать наш Edit Control, можно пользоваться выпадающим списком панели Properties (иногда иначе не получается, например, если Edit Control лежит поверх какого-нибудь Tab Control).
— устанавливаем у Edit Control свойство Multiline = True
— при необходимости включаем полосы прокрутки (Horizontal Scroll и/или Vertical Scroll присваиваем True)
— привязываем к нашему Edit Control переменную — правой кнопкой Add Variable…, из выпадающего списка Control ID выбираем наш Edit Control (например IDC_EDIT1), указываем Variable name (например, edVar).
— для вывода текста используем метод SetWindowText (смотри также другие методы класса CEdit в справке Visual Studio), например:

edVar.SetWindowText("Hello World!");

Чтобы вывести несколько строк, используйте разделитель rn, например:

edVar.SetWindowText("Line 1rnLine 2");

Чтобы очистить окно текста, используем:

edVar.SetWindowText("");

Чтобы добавить текст в конец, используем:

CString csTempText;
edVar.GetWindowText(csTempText);
csTempText += "этот текст добавим ";
edVar.SetWindowText(csTempText);

Чтобы прокрутить текст, например, до конца:

::SendMessage(edVar.m_hWnd, WM_VSCROLL, SB_BOTTOM, 0);

Чтобы прокрутить текст на одну строку:

::SendMessage(edVar.m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0);

Это Вам не Delphi и не CBuilder, привыкайте к порядку!

060711 — 11 июля 2006

Как использовать закладки (CTabCtrl).

— создаем новый проект, тип проекта Visual C++ ProjectsMFCMFC Application, даем название проекту (пусть это будет test003).
— открывается MFC Application Wizard. Выбираем Application TypeDialog based, Use MFC in a static library, жмем Finish.
— открываем Resource View, выбираем test003test003.rcDialogIDD_TEST003_DIALOG, двойным щелчком открываем редактор диалога.
— удаляем с формы диалога «TODO: Place dialog controls here.». Находим на Toolbox элемент Tab Control, перетаскиваем его на форму диалога, меняем размеры по вкусу.
— привязываем к нашему Tab Control переменную — правая кнопка на нём, выбираем Add Variable…, Variable name указываем m_Tabs, жмем Finish.
— Теперь если запустить программу, то у Tab Control закладок не будет. Нужен код, который изначально создает 2 закладки. Этот код добавляем в место, где инициализируется наш диалог — в метод Ctest003Dlg::OnInitDialog(),
после подсказки «TODO: Add extra initialization here»:

   TC_ITEM tci;   // эта структура нужна для вставки закладки
   memset(&tci,0,sizeof(tci)); // очистка структуры
   tci.mask = TCIF_TEXT;       // у закладки будет только текст
   tci.pszText = "Закладка 1";
   m_Tabs.InsertItem(0, &tci); // первая закладка имеет индекс 0
   tci.pszText = "Закладка 2";
   m_Tabs.InsertItem(1, &tci); // вставляем вторую закладку

— если запустить программу, то увидим закладки. Для того, чтобы поместить на закладки содержимое, нужно предварительно для каждой закладки подготовить форму диалога и нарисовать на каждой форме свои элементы управления. Для этого в Resource View на папке Dialog щелкаем правую кнопку, выбираем Add Resource…, в появившемся окошке выбираем Dialog и нажимаем кнопку New. Переименуем наш ресурс — Resource View, выбираем test003test003.rcDialog, правый щелчок на IDD_DIALOG1, выбираем Properties. Свойство ID содержит имя IDD_DIALOG1, меняем его на IDD_TABPAGE1.
— меняем свойства и содержимое нашей закладки — двойной щелчок на Resource Viewtest003test003.rcDialogIDD_TABPAGE1, в панели Properties откроются свойства нашей закладки. Меняем свойство Style на Child, свойство Border на None, удаляем кнопки Ok и Cancel, чтобы осталась чистая форма.
— делаем копию созданной закладки — правая кнопка на Resource Viewtest003test003.rcDialogIDD_TABPAGE1, выбираем Copy, правая кнопка на Resource Viewtest003test003.rcDialog, выбираем Paste. Появляется IDD_TABPAGE2.
— добавляем элементы управления, которые нам нужны — предположим, на первой страничке будет строка редактирования Edit Control, а на второй страничке будет IP Address Control. Перетаскиваем с Toolbox соответствующие элементы на каждую страничку IDD_TABPAGE1 и IDD_TABPAGE2.
— добавляем к каждой страничке свой класс — правый щелчок на страничке в визуальном редакторе, выбираем Add Class…, указываем Class name CTabPage1, Base Class выбираем CDialog, жмем Finish. Для второй странички делаем тоже самое, имя класса указываем CTabPage2. Эти классы нужны, чтобы в обработчике смены закладок запускать создание соответствующей закладки вызовом конструктора класса (например, new CTabPage1).
— чтобы классы были CTabPage1 и CTabPage2 были видны в реализации основного класса диалога программы, в начало файла test003Dlg.cpp добавим строчки:

#include "TabPage1.h"#include "TabPage2.h"

— добавляем в описание класса Ctest003Dlg (файл test003Dlg.h) переменную m_pTabDialog — указатель на память, в которой будет храниться отображаемая страничка Tab Control (этот указатель присваивается вызовом конструктора классов CTabPage1 и CTabPage2):

class Ctest003Dlg : public CDialog{
  ...public:
CTabCtrl m_Tabs;
CDialog* m_pTabDialog; // < --- добавить
  ...};

В конструктор класса Ctest003Dlg (файл test003Dlg.cpp) Добавим код, обнуляющий эту переменную:

Ctest003Dlg::Ctest003Dlg(CWnd* pParent /*=NULL*/):CDialog(Ctest003Dlg::IDD, pParent){
   m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
   m_pTabDialog = 0;         // < --- добавить}

— Нужно добавить обработчик события смены закладки. Двойным щелчком открываем Resource Viewtest003test003.rcDialogIDD_TEST003_DIALOG (нашу главную форму диалога), правая кнопка на Tab Control, выбираем Add Event Handler…, проследим, чтобы в окне Message type было выбрано TCN_SELCHANGE, жмем кнопку Add and Edit.
— Теперь добавим код в обработчик события смены закладки:

void Ctest003Dlg::OnTcnSelchangeTab1(NMHDR *pNMHDR, LRESULT *pResult){
  // TODO: Add your control notification handler code here
  int id; // ID диалога
 
  // надо сначала удалить предыдущий диалог в Tab Control'е:
  if (m_pTabDialog)
  {
     m_pTabDialog->DestroyWindow();
     delete m_pTabDialog;
  }
 
  // теперь в зависимости от того, какая закладка выбрана, 
  // выбираем соотв. диалог
  switch( m_Tab.GetCurSel()+1 ) // +1 для того, чтобы порядковые номера закладок
                               // и диалогов совпадали с номерами в case
  {
   // первая закладка
   case 1 :
      id = IDD_TABPAGE1;
      m_pTabDialog = new CTabPage1;//вызываем конструктор класса
      // тип указателя соответствует нужному диалогу,
      // иначе добавленный в диалог код не будет функционировать
   break;
 
   // вторая закладка
   case 2 :
      id = IDD_TABPAGE2;
      m_pTabDialog = new CTabPage2;//вызываем конструктор класса
   break;
 
   // все остальные закладки, если они есть,
   // будут здесь тоже представлены, каждая - отдельным case
 
   // а если обработка такого номера не предусмотрена
   default:
      m_pTabDialog = new CDialog; // новый пустой диалог
      return;
 
   } // end switch
 
  // создаем диалог
  m_pTabDialog->Create (id, (CWnd*)&m_Tabs); //параметры: ресурс диалога и родитель
 
  CRect rc; 
 
  m_Tab.GetWindowRect (&rc); // получаем "рабочую область"
  m_Tab.ScreenToClient (&rc); // преобразуем в относительные координаты
 
  // исключаем область, где отображаются названия закладок:
  m_Tab.AdjustRect (FALSE, &rc); 
 
  // помещаем диалог на место..
  m_pTabDialog->MoveWindow (&rc);
 
  // и показываем:
  m_pTabDialog->ShowWindow ( SW_SHOWNORMAL );
  m_pTabDialog->UpdateWindow();
 
  *pResult = 0;}

— все, программа работоспособна, за исключением того, что при запуске не отображается содержимое первой закладки. Для этого в BOOL Ctest003Dlg::OnInitDialog() нужно добавить код:

BOOL Ctest003Dlg::OnInitDialog(){
   ...
   m_Tabs.InsertItem(1, &tci); // вставляем вторую закладку
   //-----------------
   // добавить:
   NMHDR hdr;
 
   hdr.code = TCN_SELCHANGE;
   hdr.hwndFrom = m_Tabs.m_hWnd;
   SendMessage ( WM_NOTIFY, m_Tabs.GetDlgCtrlID(), (LPARAM)&hdr );
   //-----------------
   ...}

Можно еще проще:

BOOL Ctest003Dlg::OnInitDialog(){
   ...
   m_Tabs.InsertItem(1, &tci); // вставляем вторую закладку
   //-----------------
   // добавить:
   LRESULT dummy_var;
   OnTcnSelchangeTab1(NULL, &dummy_var);
   //-----------------
   ...}

Ну что, в тоске вспоминаете Delphi и CBuilder =)? Это Вам не хухры-мухры, это Visual Studio, почувствуйте разницу! Использовалась статья http://gzip.rsdn.ru/archive/vc/issues/pvc012.htm.

Это можно сделать, удалив из дерева Solution Explorerимя_проектаSource Filesимя_класа.cpp и Solution Explorerимя_проектаHeader Filesимя_класа.h. Соответствующий класс автоматически пропадет из списка Class View. При этом файлы имя_класа.cpp и имя_класа.h с диска не удаляются, это нужно сделать вручную. В противном случае при попытке создать класс с тем же именем появится предупреждающее сообщение.

060716 — 16 июля 2006

— чтобы поменять высоту выпадающего списка, нужно щелкнуть в визуальном редакторе ресурсов на стрелочку вниз в CComboBox. Появится возможность поменять высоту выпадающего списка перетаскиванием нижнего квадратика. При этом в файле *.rc, в разделе «Dialog» меняется значение высоты выпадающего списка (здесь число 134):

/////////////////////////////////////////////////////////////////////////////// Dialog//
...BEGIN
   ...
   COMBOBOX IDC_COMBO2,33,22,280,134,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
   ...END
...

— свойство Type меняет поведение CComboBox. Если выбран тип Dropdown, то в окне редактирования можно вводить текст, если выбрано Drop List, то вводить ничего нельзя, можно только выбирать из списка.
— в свойство Data можно добавлять свои строки в режиме редактирования ресурса, каждая строка отделяется от другой точкой с запятой.
— в режиме выполнения очищается список функцией ResetContent(), добавляются строки в конец списка AddString(), вставляются InsertString(). В InsertString() указывается индекс строки, перед которой будет вставка, если указать -1, то вставка будет в конец, по аналогии с AddString().
— SetCurSel() выбирает строку, параметром является индекс выбираемой строки. 0 означает 1-ю строку, 1 — вторую и т. д. (если указать -1, то не будет выбрана никакая строка).

   Здесь показано, как выполнить действия по завершению программы. Для этого в момент инициализации (для приложения — диалогового окна это будет, например, тело BOOL имя_класса_диалога::OnInitDialog()) запускается подпрограмма atexit(). Пример:

...void OnExit (void){
  Beep(4000, 200);}
...BOOL Cping5bDlg::OnInitDialog(){
   ... // TODO: Add extra initialization here
   ... atexit(OnExit);
  return TRUE; // return TRUE unless you set the focus to a control}

Можно также использовать функцию _onexit(), пример:

int OnExit (){
   Beep(4000, 200);
   CString param_list;
   param_list = "";
   for (int i=0; i<Include.GetSize();i++)
      param_list += Include.GetAt(i) + ";";
   csSaveIni("common_settings", "Include", param_list);
   return 0;}
...BOOL CsyslogvDlg::OnInitDialog(){
       ...
   // TODO: Add extra initialization here
       ...
   _onexit(OnExit);
 
   return TRUE; // return TRUE unless you set the focus to a control}

Ограничения — в теле OnExit нельзя использовать переменные, связанные с окнами, поскольку они уже уничтожены; нужно использовать заранее заполненные глобальные переменные (в этом примере массив Include.). Кроме того, у меня не получилось объявить метод OnExit как экземпляр класса окна CsyslogvDlg (в целях доступа к переменным класса), пришлось сделать простую глобальную процедуру. См. также пример, как перехватывать момент выхода из консоли (функция SetConsoleCtrlHandler()).

Окно Output выглядит примерно так:

Compiling…
имя_файла.cpp
c:VisualStudioProjectsping5bимя_файла.cpp(33) : fatal error C1010: unexpected end of file while looking for precompiled header directive

Build log was saved at «file://c:VisualStudioProjectsping5bDebugBuildLog.htm»
ping5b — 1 error(s), 0 warning(s)

———————- Done ———————-
   Build: 0 succeeded, 1 failed, 0 skipped

У меня эта ошибка возникала, когда в начало файла имя_файла.cpp забыл вставить строчку #include «stdafx.h».

[Через имя класса приложения]

Нужно добраться до свойств объекта CWinApp, а там обилие возможностей — например, у него есть переменная m_pszExeName, которая как раз и содержит имя исполняемого файла без расширения. Если, например, у вас приложение типа MFC-диалог, то у него обязательно есть класс приложения, обычно называемый Cимя_программыApp (реализация класса в имя_программы.cpp, заголовочный файл имя_программы.h). Этот класс Cимя_программыApp является производным от класса CWinApp (задается в имя_программы.h). Экземпляр класса объявлен в имя_программы.cpp, и обычно носит имя theApp. Что нужно сделать по шагам:

— узнаем название класса приложения (виден в корне дерева Class View, название класса заканчивается на App). Например, название класса Cping5bApp.
— ищем название экземпляра класса (переменной) — либо в помощью поиска по файлам на название класса Cping5bApp, либо открыв файл определения класса, в нашем случае это будет ping5b.cpp. В этом файле будет строка, в которой и будет задаваться переменная класса:

Cping5bApp theApp;

— в файле, где нужно обратиться к theApp.m_pszExeName, нужно добавить в начало строку для нашего примера:

#include "ping5b.h"

Теперь в этом файле можно обращаться к переменным и методам объекта theApp:

CString LogFileName;
LogFileName = theApp.m_pszExeName + (CString)".log";

[С помощью AfxGetAppName()]

CString csExe;
csExe = AfxGetAppName();
printf("Имя приложения без расширения: %sn", csExe);

060719 — 19 июля 2006

CWnd->EnableWindow(false); //запрещает окно (кнопка, список, любой Control)
CWnd->EnableWindow(true);  //разрешает окно (кнопка, список, любой Control)
CWnd->IsWindowEnabled();   //получить состояние запрещенности окна

Поскольку все Control-ы являются наследниками класса CWnd, то в вышеуказанных выражениях нужно просто подставить указатель на переменную нужного Control.

pButton->SetWindowText("Текст на кнопке");

060726 — 26 июля 2006

void CTestPaintDlg::OnButton1() {
  CDC* dc;
  dc=GetDC();
  dc->TextOut(20,20,"GetDC() example");  }

У этого метода куча недостатков. Текст выводится некультяпистым шрифтом на белом фоне, так что на серой форме это будет смотреться некрасиво — происходит из-за того, что по умолчанию используется для вывода непрозрачный фон (OPAQUE). Тот же эффект дает вызов:

dc->SetBkMode(OPAQUE);

Чтобы это поправить, можно использовать

dc->SetBkMode(TRANSPARENT);

Теперь фон текста будет прозрачный.

Текст рисуется поверх всех элементов управления на окне, как будто их и не было. Если текст попадает при выводе за пределы окна, он обрезается или не прорисовывается.
При передвижении окна или перерисовке нарисованный текст будет пропадать. Это легко исправить, если код поместить в OnPaint.

void CTestPaintDlg::OnPaint() {
   ...........
   }
   else
   {
       CDialog::OnPaint();
   }
   CDC* dc;
   dc=GetDC();
   dc->TextOut(20,20,"GetDC() example"); }

Кроме GetDC, существует еще GetWindowDC:

   CDC* dc;
   dc=GetWindowDC();
   dc->TextOut(20,20,"dc=GetWindowDC() example");

Разница в работе GetWindowDC() и GetDC() в том, что GetDC() выводит тест относительно верхнего левого угла серой формы, сразу под голубой плашкой окна, а GetWindowDC() выводит тест относительно верхнего левого угла всего окна целиком, вместе с плашкой.

060727 — 27 июля 2006

Есть как минимум две разновидности этой Функции:

int CWnd::MessageBox (
   LPCTSTR lpszText,
   LPCTSTR lpszCaption = NULL,
   UINT nType = MB_OK );

и

int MessageBox(
   HWND hWnd,
   LPCTSTR lpText,
   LPCTSTR lpCaption,
   UINT uType);

Вторую разновидность нужно вызывать как ::MessageBox, иначе она в зависимости от контекста окажется принадлежащей какому-нибудь оконному классу. Если вместо hWnd указать NULL, то отображаемое окно не будет иметь родительского окна. Это означает, что он становится «независимым» от основной программы — и к окну программы, и к окошку MessageBox можно одновременно получить доступ через интерфейс GUI. Если же в качестве параметра hWnd указать m_hWnd, то появляющееся окно MessageBox станет модальным — не закрыв его, нельзя получить доступ в главное окно. Остальные параметры у обоих функций MessageBox эквивалентны, как и возвращаемые значения, и подробно описаны в MSDN.

060905 — 5 сентября 2006

Класс CListCtrl предоставляет возможность создать список а-ля списка окна Explorer — объектами списка могут быть маленькие иконки, большие иконки (туда можно загрузить картинку), список может быть простой и расширенный, в виде таблицы. Отображение зависит от стиля, который можно назначить при разработке программы (в окне свойств Properties меняем значение свойства View, выбрав из выпадающего списка один из вариантов Icon, Small Icon, List или Report). Манипулируем экземпляром CListCtrl, привязав, как обычно, к нему переменную, и потом в коде обращаемся к методам этой переменной. Вот примеры действий над экземпляром CListCtrl:

1. Получить размеры

CRect rect;
m_cListCtrl.GetClientRect(&rect);

2. Добавить столбцы (только если стиль выбран в Report)

int nColInterval = rect.Width()/10;
m_cListCtrl.InsertColumn(0, _T("Time"), LVCFMT_LEFT, nColInterval);
m_cListCtrl.InsertColumn(1, _T("IP"), LVCFMT_LEFT, nColInterval*2);
m_cListCtrl.InsertColumn(2, _T("Event"), LVCFMT_LEFT, nColInterval*2);
m_cListCtrl.InsertColumn(3, _T("Description"), LVCFMT_LEFT, rect.Width() - 5*nColInterval);

3. Вставляем экземпляры объектов в CListCtrl

LVITEM lvi;
CString strItem;// Insert the first item
lvi.mask = LVIF_IMAGE | LVIF_TEXT;
strItem.Format("%s",evnt.time);
lvi.iItem = idx;
lvi.iSubItem = 0;
lvi.pszText = (LPTSTR)(LPCTSTR)(strItem);
m_cListCtrl.InsertItem(&lvi);// Set subitem 1
strItem.Format("%s", evnt.IP);
lvi.iSubItem =1;
lvi.pszText = (LPTSTR)(LPCTSTR)(strItem);
m_cListCtrl.SetItem(&lvi);// Set subitem 2
strItem.Format("%s", evnt.evID);
lvi.iSubItem =2;
lvi.pszText = (LPTSTR)(LPCTSTR)(strItem);
m_cListCtrl.SetItem(&lvi);// Set subitem 3
strItem.Format("%s", evnt.evDescr);
lvi.iSubItem =3;
lvi.pszText = (LPTSTR)(LPCTSTR)(strItem);
m_cListCtrl.SetItem(&lvi);

4. Очистка

m_cListCtrl.DeleteAllItems();

Класс CStringArray позволяет работать с динамическим массивом строк. Вот примеры действий с таким массивом:

1. Очистка

CStringArray csArray;
csArray.RemoveAll();

2. Добавление строки в массив

csArray.Add( "Эту строку добавляем в массив" );

3. Получение количества строк в массиве, получение строк из массива (индексация элементов, начиная с 0):

for (int i=0; i<csArray.GetSize();i++)
   MessageBox (NULL, csArray.GetAt(i), "", MB_OK);

061223 — 23 декабря 2006

Как определить размер объекта (массива, переменной, класса) в байтах:

CSliderCtrl sl;
...int size_in_bytes = sizeof(sl);

Как определить размер массива (количество элементов в массиве).

CSliderCtrl sl[9];
...int elements_in_array = sizeof(sl) / sizeof(sl[0]);  // ==9

070403 — 3 апреля 2007

[Строки]

AnsiString             -> CString
byte                   -> char
ParamStr(param_num)    -> argv[param_num]
AnsiString.Pos(строка) -> CString.Find(строка)
AnsiString.SubString() -> CString.Left() или CString.Mid()
AnsiString.Length()    -> CString.GetLength()
AnsiString.UpperCase() -> CString.MakeUpper()

При работе со строками важно учитывать следующее отличие AnsiString и CString — нумерация символов в AnsiString начинается с 1, а у CString с 0. Например, так нужно получить последний символ и удалить его в AnsiString:

 char sym = asPattern[asPattern.Length()];
 asPattern.Delete(asPattern.Length(), 1);

А так делаем все то же самое в CString:

char sym = asPattern[asPattern.Length() - 1]; asPattern.Delete(asPattern.Length() - 1, 1);

[Дата и время]

DecodeDate(), Date() -> CTime, CTime::GetCurrentTime(), CTime.GetYear(), CTime.GetMonth(), CTime.GetDay(), CTime.Format()

Пример на CBuilder:

 WORD Year, Month, Day;
 AnsiString asYear, asMonth, asDay;
 DecodeDate(Date(), Year, Month, Day);
 asYear  = IntToStr(Year);
 asMonth = IntToStr(Month);
 asDay   = IntToStr(Day);

То же самое на Visual C:

 WORD Year, Month, Day;
 CString asYear, asMonth, asDay;
 CTime ctTime = CTime::GetCurrentTime();
 Year  = ctTime.GetYear();
 Month = ctTime.GetMonth();
 Day   = ctTime.GetDay();
 asYear  = ctTime.Format( "%Y" );
 asMonth = ctTime.Format( "%m" );
 asDay   = ctTime.Format( "%d" );

[Файлы]

1. ExtractFileName() -> _splitpath()
    ExtractFileDir () -> _splitpath()

Пример на CBuilder:

 AnsiString asDir, asName;
 asName = ExtractFileName(asFullPath);
 asDir = ExtractFileDir (asFullPath);
 AnsiString asOldName, asNewName;
 asOldName = asFullPath;
 asNewName = asDatePart + asName;
 if (!asDir.IsEmpty())
    asNewName = asDir + "" + asNewName;

Пример на Visual C:

 CString csDrive, csDir, csName, csExt;
 char drive;
 char dir[256];
 char fname[256];
 char ext[256];
 _splitpath(csFullPath, &drive, dir, fname, ext);
 csDrive = (CString)drive;
 csDir   = (CString)dir;
 csName  = (CString)fname;
 csExt   = (CString)ext;
 if (csDrive != "")
   csDir  = csDrive + ":" + csDir;
 CString csOldName, csNewName;
 csOldName = csFullPath;
 csNewName = csDatePart + csName + csExt;
 if (!csDir.IsEmpty())
   csNewName = csDir + "" + csNewName;

2. FileExists()  -> PathFileExists() (#include «shlwapi.h»)
3. FileGetAttr() -> GetFileAttributes()
4. FileSetAttr() -> SetFileAttributes()
5. DeleteFile()  -> DeleteFile()
6. FileOpen()    -> _open()
7. Получение длины файла
   FileSeek() -> _filelength()
8. FileSeek() -> _lseek()
9. FileRead() -> _read()
10. FileWrite() -> _write()
11. FileClose() -> _close()
12. RenameFile() -> rename()
13. CopyFile()   -> CopyFile()

070409 — 9 апреля 2007

1. Скачиваем RegexVc71.EXE (см. Download на http://www.tropicsoft.com/Components/RegularExpression/index.html ).

2. Устанавливаем компонент Regular Expression Component Library Vc71 в любую папку, я поставил в C:Program FilesMicrosoft Visual Studio .NET 2003Regular Expression Component Library Vc71

3. В Visual Studio C++ 7.1 делаем FileNew Project…Project Types:Win32Win32 Console Project, указываем имя проекта, например, regextest, Жмем OK, в Application Settings должно быть выбрано Console application, и можно поставить галочку на Add support for:MFC, жмем Finish.

4. Добавляем

#include < RegularExpressionClass.h >

В ProjectPropertiesConfiguration PropertiesC/C++GeneralAdditional Include Directories
добавляем «$(VSInstallDir)Regular Expression Component Library Vc71Include»

5. В ProjectPropertiesConfiguration PropertiesLinkerGeneralAdditional Library Directories добавляем «$(VSInstallDir)Regular Expression Component Library Vc71Lib»

6. В теле main или до него определяем экземпляр класса регулярного выражения.

7. В раздел // TODO: code your application’s behavior here. добавляем код, использующий класс (код чисто тестовый):

RegexClass::RegularExpression re;
CString csPattern = "YYMMDD";
CString csRegExp = "(Y{2,4}|M{2}|D{2}|h{2}|m{2}|s{2}|.){1,}";
re.SetExpression(csRegExp.GetBuffer());
re.StringToMatch = csPattern.GetBuffer();if (re.MatchAll())
     MessageBox(NULL, "Matched!", "O.K.", MB_OK);else
     MessageBox(NULL, "No match...", "Err.", MB_ICONASTERISK);

8. Все это мы проделали в конфигурации Debug. Для конечного релиза нужно сделать то же самое, только еще целесообразно в ProjectPropertiesConfiguration PropertiesGeneralUse of MFC выбрать Use MFC in a Static Library, а также для предотвращения ошибки Linker Tools Error LNK2005 в Configuration PropertiesLinkerCommand LineAdditional Options: добавляем /FORCE:MULTIPLE (см. совет Ошибка линкера LNK2005).

9. Преобразование текста в IP.

void TEXTtoIP (CString csIP, byte* addr){
   //проверка IP
   RegexClass::RegularExpression re;
   CString csRegExp = (CString)"^([0-9]|[0-9][0-9]|[01][0-9][0-9]|2[0-4][0-9]|25[0-5])"
              + (CString)"(.([0-9]|[0-9][0-9]|[01][0-9][0-9]|2[0-4][0-9]|25[0-5])){3}";
   re.SetExpression(csRegExp.GetBuffer());
   re.StringToMatch = csIP.GetBuffer();
   if (!re.MatchAll())
   {
      bError = true;
      WLog("ini IP error - bad address" + csIP);
      exit(1);
   }
   //выделение байт из IP
   int iStringIdx;
   int iByteIdx = 0;
   csIP.Trim();
   CString csByte;
   while (!csIP.IsEmpty())
   {
      iStringIdx = csIP.Find('.');
      if (-1 != iStringIdx)
      {
         csByte = csIP.Mid(0, iStringIdx);
         addr[iByteIdx] = atoi (csByte);
         csIP.Delete(0, iStringIdx+1);
      }
      else
      {
         addr[iByteIdx] = atoi (csIP);
         csIP = "";
      }
      csIP.Trim();
      iByteIdx++;
   }/* while */}

10. Преобразование из строки в дату.

void TEXTtoOleDateTime (CString csDate, COleDateTime* datetime){
   RegexClass::RegularExpression re;
   CString csRegExp = (CString)"^d{1,2}([-. /])d{1,2}d{2,4}";
   re.SetExpression(csRegExp.GetBuffer());
   re.StringToMatch = csDate.GetBuffer();
   if (!re.MatchAll())
   {
     bError = true;
     WLog("ini IP error - bad date" + csDate);
     exit(1);
   }
   int iStringIdx;
   byte iParam = 0;
   int iYear, iMonth, iDay;
   csDate.Trim();
   CString csParam;
   while (!csDate.IsEmpty())
   {
     iStringIdx = csDate.Find('.');
     if (-1 != iStringIdx)
     {
         csParam = csDate.Mid(0, iStringIdx);
         csDate.Delete(0, iStringIdx+1);
     }
     else
     {
         csParam = csDate;
         csDate = "";
     }
     switch (iParam)
     {
     case 0:
         iDay = atoi (csParam);
         break;
     case 1:
         iMonth = atoi (csParam);
         break;
     case 2:
         iYear = atoi (csParam);
         break;
     }
     csDate.Trim();
     iParam++;
   }
   datetime->SetDate(iYear, iMonth, iDay);}

11. Разбиение строки на части (по разделителю — пробелу). В этом примере на входе строка csLine, на выходе части помещаются в вектор out. Части извлекаются с помощью итератора it, первая часть помещается в csPart.

#include < vector >
 ...CString csLine = "part1 part2 part 3";
CString csPart;
CString csRegExp = "s+";
RegexClass::RegularExpression re;
std::vector<std::string> out;
re.SetExpression(csRegExp.GetBuffer());
re.StringToMatch = csLine.GetBuffer();
re.Split(out);
std::vector<std::string>::iterator it = out.begin();
csPart = it->c_str();

070410 — 10 апреля 2007

Ошибка линкера LNK2005: Linker Tools Error LNK2005 «symbol already defined in object» быстро устраняется добавлением опции /FORCE:MULTIPLE в командную строку линкера: Configuration PropertiesLinkerCommand LineAdditional Options: добавляем /FORCE:MULTIPLE.

После компиляции получаем кучу страшных предупреждений, но программа работает:

Compiling resources…
Linking…
nafxcw.lib(afxmem.obj) : warning LNK4006: «void * __cdecl operator new(unsigned int)» (??2@YAPAXI@Z) already defined in libcpmt.lib(newop.obj); second definition ignored
nafxcw.lib(afxmem.obj) : warning LNK4006: «void * __cdecl operator new[](unsigned int)» (??_U@YAPAXI@Z) already defined in libcpmt.lib(newaop.obj); second definition ignored
Release/autoname.exe : warning LNK4088: image being generated due to /FORCE option; image may not run
LINK : warning LNK4089: all references to ‘SHELL32.dll’ discarded by /OPT:REF
LINK : warning LNK4089: all references to ‘comdlg32.dll’ discarded by /OPT:REF
LINK : warning LNK4089: all references to ‘ole32.dll’ discarded by /OPT:REF

Build log was saved at «file://c:VisualStudioProjectsautonameReleaseBuildLog.htm»
autoname — 0 error(s), 6 warning(s)
———————- Done ———————-
   Rebuild All: 1 succeeded, 0 failed, 0 skipped
———————————————————————————

varOutputList.SetWindowText(csFN + ", ["+ csIP +"]");
UpdateWindow();

Если Вы создали приложение с помощью визарда как диалоговое окно, и добавили обработчики сообщений для диалогового окна WM_KEYDOWN или WM_KEYUP (напомню, что это делается через Class Viewправая кнопка на классе диалогового окна, Propertiesкнопка Messages, далее выбираем сообщение и добавляем для него обработчик), то этот обработчик все равно срабатывать не будет. Проблема (и её решение) описана тут — http://www.winterdom.com/dev/mfc/pretrans.html . Проблема решается так:

1. В заголовочном файле класса (имя_класса.h), в секции public класса диалогового окна добавляется строка с переназначением процедуры PreTranslateMessage:

...DECLARE_MESSAGE_MAP()public:
...BOOL PreTranslateMessage(MSG* pMsg);};

2. В файле класса диалогового окна (имя_класса.cpp) вставляется код процедуры PreTranslateMessage (в этом примере отслеживается нажатие кнопок Ctrl+C):

BOOL CunusedportsDlg::PreTranslateMessage(MSG* pMsg){
   if (pMsg->message == WM_KEYDOWN)
   {
     if ((pMsg->wParam == 17) && (pMsg->lParam == 1900545))
         //Ctrl нажата
         bCtrl = true;
     else if (bCtrl && (pMsg->wParam == 67))
     {
         //нажата комбинация Ctrl+C
         Beep (2000, 100);
         bStop = true;
     }
   }
   if (pMsg->message == WM_KEYUP)
   {
     if ((pMsg->wParam == 17) && (pMsg->lParam == -1071841279))
         //Ctrl отпущена
         bCtrl = false;
     else if (bCtrl && (pMsg->wParam == 67))
         //отпущена комбинация Ctrl+C
         Beep (1000, 100);
   }
   return CDialog::PreTranslateMessage(pMsg);}

Этот метод позволяет вставлять в процедуру PreTranslateMessage обработку и других сообщений.

070418 — 18 апреля 2007

1. Добавить private или protected переменную типа CToolTipCtrl в класс вашего диалога.
2. Добавить в класс управляющую переменную (control member variable), для каждого элемента, у которого будет подсказка. Это можно сделать с помощью ClassWizard (на закладке Member Variable).
3. Переопределить CDialog::OnInitDialog и вызвать в нем CToolTipCtrl::Create. Затем вызвать CToolTipCtrl::AddTool для каждого элемента с подсказкой, передавая адрес управляющей переменной и текст подсказки в качестве параметров.
4. Переопределить CDialog::PreTranslateMessage и вызвать в ней CToolTipCtrl::RelayEvent для каждого сообщения, передаваемого в функцию. Это нужно для того, чтобы элемент ToolTip получал все необходимые сообщения мыши.

Практическая реализация по шагам (на примере простейшего приложения на основе стандартного диалога):

1. Открываем файл имя_класса_диалога.h (у меня был файл unusedportsDlg.h), в определение класса (у меня был класс class CunusedportsDlg : public CDialog), в раздел public, в конец вставляем переменную класса типа CToolTipCtrl:

class CunusedportsDlg : public CDialog{
  ...protected:
  ...public:
  ...
  afx_msg void OnClose();
  CToolTipCtrl hints;};

Еще добавляем переопределение в классе CDialog процедуры PreTranslateMessage:

class CunusedportsDlg : public CDialog{
  ...protected:
  ...public:
  ...BOOL PreTranslateMessage(MSG* pMsg);
  afx_msg void OnClose();
  CToolTipCtrl hints;};

Добавляем в имя_класса_диалога.cpp (у меня был файл unusedportsDlg.cpp), добавляем код процедуры PreTranslateMessage:

BOOL CunusedportsDlg::PreTranslateMessage(MSG* pMsg){
   // TODO: Add your specialized code here and/or call the base class
   if (pMsg->message == WM_KEYDOWN)
   {
     ...
   }
   if (pMsg->message == WM_KEYUP)
   {
     ...
   }
   hints.RelayEvent(pMsg);
   return CDialog::PreTranslateMessage(pMsg);}

2. Идем на закладку Resource View, далее выбираем в дереве проекта папку Dialog, двойным щелчком открываем редактор диалога, правой кнопкой на каждом элементе диалога добавляем переменную (в контекстном меню выбираем Add Variable…, далее запускается Wizard, указываем в поле Variable name: что-то типа varOkBtn, жмем Finish). Так надо поступить с каждом элементом управления, для которого будет всплывающая подсказка (для кнопки, строки редактирования, пикера даты и т. п.).

3. В файле имя_класса_диалога.cpp (у меня был файл unusedportsDlg.cpp), в подпрограмме имя_класса::OnInitDialog() (у меня была подпрограмма BOOL CunusedportsDlg::OnInitDialog()) добавляем инициализацию хинтов, код должен быть наподобие такого:

...//включаем систему подсказок
hints.Create(pDlg);
hints.AddTool(&varDateBeg, "select START data to analize free ports");
hints.AddTool(&varDateEnd, "select END data to analize free ports");
hints.AddTool(&varOutputList, "analize result will be here");
hints.AddTool(&varOkBtn, "click to start analize free ports");
...

Теперь при запуске приложения у нас нужные элементы управления получат нужные надписи подсказок.

4. В процедуре имя_класса::PreTranslateMessage (у меня была процедура BOOL CunusedportsDlg::PreTranslateMessage(MSG* pMsg)) добавляем в конец код:

BOOL CunusedportsDlg::PreTranslateMessage(MSG* pMsg){
   ...
   hints.RelayEvent(pMsg);
   return CDialog::PreTranslateMessage(pMsg);}

Все, теперь при наведении курсора на элемент управления будут всплывать желтенькие подсказки. Если нужно переопределить эти подсказки runtime, то нужно пользоваться методом DelTool:

   ...
   hints.DelTool(&varOkBtn);
   hints.AddTool(&varOkBtn, "новый текст хинта");
   ...

Для работы с файлами есть два основных метода — _open/_filelength/_read/_close, и fopen/fread/feof/fclose. Опишем оба метода, их достоинства и недостатки.

_open/_filelength/_read/_close

Работа с файлами через хендл. Самая большая неприятность этого метода — файл всегда открывается в текстовом режиме. Это означает, что часть информации будет при чтении потеряна — например, последовательность rn преобразуется в n, и это не всегда удобно. Удобство в том, что есть подпрограмма определения размера файла (_filelength). Пример использования:

int fhSour;int iFileLength, iBytesReaded;char *buf;
fhSour = _open(catalog + "" + csFN, _O_RDONLY);if (-1 == fhSour){
   WLog( "The file " + catalog + "" + csFN + " was not opened" );
   exit (1);}
iFileLength = _filelength(fhSour);
buf = (char*)malloc(iFileLength);//iButesReaded может быть меньше iFileLength
iBytesReaded = _read(fhSour, buf, iFileLength);
_close(fhSour);if (-1 == iBytesReaded){
   WLog("Error read file " + csFN);
   exit (1);}//делаем ASCIIZ-строку
buf[iBytesReaded] = 0;
CString csFileContent = (CString)buf;free(buf);

fopen/fread/feof/fclose

Работа с файлами через потоки, хороший выбор. Удобство в том, что можно открывать файлы в двоичном виде. Неудобство в том, что нельзя сразу определить размер файла, не прочитав его до конца (конец файла тестируется feof). Пример использования:

FILE *stream;size_t count, total = 0;char buffer[100];
CString csOutput = "";if( (stream  = fopen( csFileName, "rb" )) == NULL )
   WLog( "Error open (not exist?): " + csFileName );else{
   while( !feof( stream ) )
   {
     /* Attempt to read in 99 bytes: */
     count = fread( buffer, sizeof( char ), 99, stream );
     if( ferror( stream ) )
     {
         WLog( "Error read file " + csFileName);
         break;
     }
     buffer[count] = 0;
     total += count;
     csOutput += (CString)buffer;
   }
   fclose( stream );
   varOutputList.SetWindowText(csOutput);}

Постоянно забываю эти простые специальные символы.
CR, Carriage Return, код 0x0D, использование в C как r
LF, Line Feed, код 0x0A, использование в C как n
CRLF, rn, используется в файлах DOS и Windows как последовательность, завершающая строку (0x0D 0x0A).

070426 — 26 апреля 2007

— Resource Viewпапка Bitmapправая кнопка Add Resource…выбираем Bitmapнажимаем кнопку New
— в папке ресурсов Bitmap появляется новая запись IDB_BITMAP1 (это ID картинки) и одновременно открывается окно редактора картинки. IDB_BITMAP1 лучше поменять на что-то более подходящее по смыслу, например IDB_MYBUTTON (делается через свойства картинки, параметр ID).
— меняем у нашей кнопки свойство Bitmap на True, а свойство Caption очищаем (свойство Caption очищать не обязательно, все равно картинка закроет надпись на кнопке).
— рисуем картинку. Проще всего открыть какой-нибудь ресурс в Интернете, посвященный иконкам, например http://www.iconsfree.org/free-icons/language/eng/c/categoriesRating/icons-categories-rating.html, выбрать нужную иконку и прямо с экрана скопировать в буфер обмена растр картинки (для этого очень рекомендую программу Kleptomania — копирует с экрана и графику, и текст), а затем вставить содержимое буфера прямо в редакторе ресурсов Visual Studio.
— к кнопке, в которую будем вставлять картинку, привязываем переменную. Для этого на кнопке в контекстном меню выбираем Add Variable…, в окно Variable name: подставляем что-то типа varMyBtn
— в процедуре инициализации формы диалога OnInitDialog() добавляем следующий код (процедура WLog пишет ошибки в текстовый файл):

HBITMAP bmMyBtn;
bmMyBtn = LoadBitmap(theApp.m_hInstance, MAKEINTRESOURCE(IDB_MYBUTTON));
CString csMsg;char* lpMsgBuf;if (NULL == bmMyBtn){
   FormatMessage(
           FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
           NULL,
           GetLastError(),
           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
           (LPTSTR) &lpMsgBuf,
           0,
           NULL);
   csMsg = (char*)lpMsgBuf;
   csMsg.Trim();
   WLog("error load bitmap for button: " + csMsg);}
varMyBtn.SetBitmap( bmMyBtn );
CString csFileName = "C:boot.ini";
ShellExecute(NULL, "open", "notepad.exe", csFileName, NULL, SW_SHOWNORMAL);

— скачиваем ZipArchive Library с сайта http://www.artpol-software.com/Download.aspx, это 2 файла — ziparchive.zip (Sources, Documentation and Samples) и setup.zip (Installation Setup).

— запускаем файл setup.exe (из архива setup.zip), указываем директорию для установки C:Program FilesMicrosoft Visual Studio .NET 2003ZipArchive library. Если у Вас не MSDN версии 6, то галочку «интегрировать help» не ставим.

— теперь нам надо получить откомпилированную библиотеку ZipArchive.lib той версии, которая подходит к нашей версии Visual Studio 7.0. Для этого из архива ziparchive.zip, который мы скачали, распаковываем 2 файла ZipArchive.vcproj и ZipArchive.sln в папку C:Program FilesMicrosoft Visual Studio .NET 2003ZipArchive libraryZipArchive. Те файлы, что там есть (версии 8.0), можно спокойно стереть, поскольку в ziparchive.zip есть их копии в папке _projectsVisual Studio 2005ZipArchive. Двойным щелчком открываем файл C:Program FilesMicrosoft Visual Studio .NET 2003ZipArchive libraryZipArchiveZipArchive.vcproj, выбираем конфигурацию Release, компилируем. В результате получаем файл C:Program FilesMicrosoft Visual Studio .NET 2003ZipArchive libraryZipArchiveReleaseZipArchive.lib.

— создаем новый проект в Visual Studio — Visual C++ ProjectsWin32Win32 Console Project, поддержку ATL и MFC не добавляем.

— в свойствах проекта, раздел C/C++Additional Include Directories добавляем путь к папке, где лежат h-файлы:

«C:Program FilesMicrosoft Visual Studio .NET 2003ZipArchive libraryZipArchive»

— в свойствах проекта, раздел LinkerAdditional Library Directories добавляем путь к папке, где лежит откомпилированная библиотека ZipArchive.lib:
«C:Program FilesMicrosoft Visual Studio .NET 2003ZipArchive libraryZipArchiveRelease»

— в свойствах проекта, в раздел LinkerInputAdditional Dependencies добавляем ZipArchive.lib.

070502 — 2 мая 2007

theApp.m_lpCmdLine — указатель на командную строку, в которой только опции, разделенные пробелами (без имени приложения).

MessageBox(theApp.m_lpCmdLine, "", MB_OK);

090421

Ругань началась при попытке компиляции c-кода в cpp-проекте на строку *HidDevices = calloc (*NumberDevices, sizeof (HID_DEVICE)):
путь_до_проектаusbhid.cpp(70): error C2440: ‘=’ : cannot convert from ‘void *’ to ‘PHID_DEVICE’

Причина — переменная *HidDevices имела тип PHID_DEVICE, а calloc возвращает тип void *. Дело в том, что в проекте CPP компилятор более строго проверяет соответствие типов, чем в проекте на чистом C. Вариантов решения 2 — либо поменять тип проекта (с CPP на чистый C), либо применить явное преобразование типа, например так:
*HidDevices = (PHID_DEVICE) calloc (*NumberDevices, sizeof (HID_DEVICE));

Решение проблемы было найдено на http://winprog.org/tutorial/errors.html

exit(код_возврата)

или

CDialog* pDlg;
pDlg = (CDialog*)theApp.m_pMainWnd;
...pDlg->EndDialog(код_возврата);

ExitProcess() полностью, немедленно завершает программу, даже если ExitProcess() вызвать из потока, запущенного в программе. Причем функция, настроенная на обработку выхода с помощью atexit(), не срабатывает.

Библиотека позволяет делать красивый современный дизайн для проекта, добавляет новые возможности.

— официальный сайт — http://www.prof-uis.com/, скачать отсюда — http://www.prof-uis.com/download/profuis264_freeware.zip , документация здесь — http://www.prof-uis.com/download/help/profuishelp.zip (если скачали profuis264_freeware.zip, то доку можно не скачивать), дока по настройке (Getting started with Prof-UIS) здесь — http://www.prof-uis.com/ArticleRead.aspx?AID=220

— из архива profuis264_freeware.zip распаковать каталог Prof-UIS в каталог c:Program FilesMicrosoft Visual Studio .NET 2003

— как настраивать тут — http://www.prof-uis.com/FAQView.aspx?CID=101

— внутри Visual Studio идем ToolsOptions…ProjectsVC++ Directories, Show directories for настраиваем по таблице (здесь $(VCInstallDir) равно c:Program FilesMicrosoft Visual Studio .NET 2003Vc7):
Include files    …/Prof-UIS/Include или $(VCInstallDir)..Prof-UISInclude
                 …/Prof-UIS/Src     или $(VCInstallDir)..Prof-UISSrc
Source files     …/Prof-UIS/Include или $(VCInstallDir)..Prof-UISInclude
                 …/Prof-UIS/Src     или $(VCInstallDir)..Prof-UISSrc
Library files    …/Prof-UIS/Bin_710 или $(VCInstallDir)..Prof-UISBin_710

— скачать Prof-UIS Application Wizard отсюда — http://www.prof-uis.com/download/wizards/ProfUisAppWizard_2003.ZIP (страница закачки http://www.prof-uis.com/FAQView.aspx?CID=101 )

— распаковать в папку c:Program FilesMicrosoft Visual Studio .NET 2003Vc7VCWizards папку ProfUISAppWizard из архива ProfUisAppWizard_2003.ZIP

— файлы ProfUISAppWizard.ico, ProfUISAppWizard.vsdir и ProfUISAppWizard.vsz из архива ProfUisAppWizard_2003.ZIP положить в папку c:Program FilesMicrosoft Visual Studio .NET 2003Vc7vcprojects

— теперь сразу, без перегрузки Visual Studio будет доступен новый визард по адресу FileNewProject…Visual C++ ProjectsProfUISAppWizard

— нужно откомпилировать все версии библиотеки ProfUIS264*.lib, для этого откройте c:Program FilesMicrosoft Visual Studio .NET 2003Prof-UISWorkspaceProfUIS_710.sln, выберите проект ProfUISLIB и откомпилируйте его со всеми возможными конфигурациями:

ANSI Debug, Static ANSI Debug
ANSI Debug RDE, Static ANSI Debug RDE
ANSI Debug RDE with MFC DLL, Static ANSI Debug RDE with MFC DLL
ANSI Debug with MFC DLL, Static ANSI Debug with MFC DLL
ANSI Release, Static ANSI Release
ANSI Release RDE, Static ANSI Release RDE
ANSI Release RDE with MFC DLL, Static ANSI Release RDE with MFC DLL
ANSI Release with MFC DLL, Static ANSI Release with MFC DLL
MBCS Debug, Static MBCS Debug
MBCS Debug RDE, Static MBCS Debug RDE
MBCS Debug RDE with MFC DLL, Static MBCS Debug RDE with MFC DLL
MBCS Debug with MFC DLL, Static MBCS Debug with MFC DLL
MBCS Release, Static MBCS Release
MBCS Release RDE, Static MBCS Release RDE
MBCS Release RDE with MFC DLL, Static MBCS Release RDE with MFC DLL
MBCS Release with MFC DLL, Static MBCS Release with MFC DLL
Unicode Debug, Static Unicode Debug
Unicode Debug RDE, Static Unicode Debug RDE
Unicode Debug RDE with MFC DLL, Static Unicode Debug RDE with MFC DLL
Unicode Debug with MFC DLL, Static Unicode Debug with MFC DLL
Unicode Release, Static Unicode Release
Unicode Release RDE, Static Unicode Release RDE
Unicode Release RDE with MFC DLL, Static Unicode Release RDE with MFC DLL
Unicode Release with MFC DLL, Static Unicode Release with MFC DLL

Для этого идем в BuildBatch Build…, ставим галки на конфигурациях ProfUISLIB, жмем Build. После того, как все выбранные конфигурации откомпилируются (это надолго, можно пойти попить кофейку), в каталоге c:Program FilesMicrosoft Visual Studio .NET 2003Prof-UISBin_710 появится куча файлов ProfUIS264*.lib.

— для того, чтобы отлаживаемые программы запускались, нужно добавить в переменную Path системы путь до библиотек c:Program FilesMicrosoft Visual Studio .NET 2003Prof-UISBin_710, для этого открываем Control PanelSystemAdvancedEnvironment Variables…System variables, выбираем переменную Path и нажимаем кнопку Edit…, в строке Variable Value: в конец добавляем ;c:Program FilesMicrosoft Visual Studio .NET 2003Prof-UISBin_710

Перелогиниваться при этом не нужно, просто надо перезапустить приложение (Visual Studio), из которого запускаем программу. Другой способ — скопировать нужную dll в каталог отлаживаемой программы, или задать в свойствах проекта линковать библиотеки статически — в свойствах проекта программы, в разделе Configuration PropertiesGeneral указать Use of MFC в Use MFC in a Static Library.

090606 — 6 июня 2009

Пример:

log.obj : error LNK2001: unresolved external symbol «class ATL::CStringT -> LogFileName» (?LogFileName@@3V?$CStringT@DV?$StrTraitMFC_DLL@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@A) .Debug/UsbHidDemoCode.exe : fatal error LNK1120: 1 unresolved externals

Такая ошибка у меня часто возникает, когда я беру модуль *.cpp (из другого старого проекта) без хедера и пытаюсь вставить в новый проект. На переменные вставляемого модуля, объявленные с директивой extern (в этом примере так была объявлена переменная LogFileName) будет в этом случае будет происходить ошибка LNK2001 и следующая за ней общая фатальная ошибка LNK1120. Проблема устраняется объявлением CString LogFileName в любом другом модуле.

110721 — 21 июля 2011

Иногда это нужно сделать, если файл кода используется совместно с embedded-проектами для микроконтроллеров. Правой кнопкой щелкаем на нужном C-файле в дереве проекта, выбираем Properties -> Configuration Properties -> C/C++ -> Advanced -> Compile As -> Compile as C++ Code (/TP).

120705 — 5 июля 2012

Получить путь до запускаемого файла приложения вместе с именем *.exe файла можно вызовом ExecutablePath, а полный путь до запускаемого файла приложения без самого имени *.exe можно вызовом StartupPath. Пример:

[STAThreadAttribute]int main(array<System::String ^> ^args){
   // Включение визуальных эффектов Windows XP до создания
   // каких-либо элементов управления
   Application::EnableVisualStyles();
   Application::SetCompatibleTextRenderingDefault(false); 
 
   // создание файла лога
   applog = new Log("myapp.log");
   // Создание главного окна и его запуск
   applog->Write("[START]");
   applog->Write(Application::ExecutablePath); //полный путь до *.exe вместе с именем *.exe
   applog->Write(Application::StartupPath);    //полный путь до *.exe без с имени *.exe
   Application::Run(gcnew Form1());
   applog->Write("[EXIT]");
   delete applog;
   return 0;}

Простое преобразование из char* в System::String может быть выполнено с помощью конструктора. Пример:

char srcstr [] = "ASCIIZ char string";
String^ dststr1 = gcnew System::String(srcstr);
String^ dststr2 = gcnew String (srcstr);

Обратное преобразование из System::String в char* может быть выполнено либо с помощью функции sprintf_s, либо с помощью объекта Marshal. Метод с помощью sprintf_s:

String^ srcstr = gcnew String ("System::String example");char dststr [512];
sprintf_s(dststr, sizeof(dststr), "%s", srcstr);

Метод с помощью объекта Marshal:

char* STRING2CHAR (System::String ^strval){
   IntPtr ptr = Marshal::StringToHGlobalAnsi(strval);
   char* char_str = (char*)ptr.ToPointer();
   return char_str;}
 
String^ srcstr = gcnew String ("System::String example");char dststr [512];
strcpy(dststr, STRING2CHAR(srcstr));

120709 — 9 июля 2012

Предположим, что у нас есть кнопка MyBtn, и есть обработчик события щелчка на ней MyBtn_Click:

   private: System::Void MyBtn_Click(System::Object^ sender, System::EventArgs^ e) 
      {
         //далее код действий по обработке клика по кнопке
         ...
      }

Тогда программно вызвать обработчик события MyBtn_Click можно следующим образом:

         MyBtn_Click(MyBtn, gcnew System::EventArgs);

120828 — 28 августа 2012

Иногда нужно переименовать папку проекта, чтобы сделать его работоспособную копию. Однако, если после этого открыть проект в переименованной папке, то не отображается в конструкторе форма проекта (конструктор выдает ошибку). Очистка и компиляция работают, но это не решает проблему. Чтобы полностью починить переименованный проект, нужно выйти из Visual Studio, удалить файл *.sdf в корневой папке проекта, и снова открыть проект в Visual Studio. Файл *.sdf создастся заново, конструктор форм нормально заработает и покажет форму, доступную для редактирования.

150114 — 14 января 2015

Ранее проект нормально собирался под Windows XP SP3 32-бита в среде разработки Microsoft Visial C++ 2010 со встроенной библиотекой VS 2010 NET 4.0. После перехода на Windows 7 в той же среде Microsoft Visial C++ 2010, но со встроенной библиотекой VS 2010 NET 4.5 начала выскакивать ошибка:

LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt. 

(LINK : fatal error LNK1123: сбой при преобразовании в COFF: файл недопустим или поврежден). Ошибка исчезла после дополнительной установки пакета обновления SP1 для Microsoft Visual Studio 2010 (KB983509).

Пример кода, который дает такую ошибку:

public class SerialGate
{public:
   enum IN_LINES_NAME {CTS, DSR, RING, RLSD};
   enum OUT_LINES_NAME {DTR, RTS};
   SerialGate();
   ~SerialGate();    
   bool Open(int port, int baud);
   int Send(char* buff, int szBuff);
   int Recv(char* buff, int szBuff);
   void SetLine(OUT_LINES_NAME ln, bool state);
   bool GetLine(IN_LINES_NAME ln);
   void GetPortsInfo(PortInfo* pi);
   void Close();
   void Clean();private:
   HANDLE m_hFile;
   bool state;
   SerialPort^ _serialPort;   //здесь ошибка C3265
};

Ошибку можно устранить, если подключить vcclr.h, объявить _serialPort с использованием шаблона gcroot:

#include < vcclr.h >
 
...
 
   //SerialPort^ _serialPort;
   gcroot< SerialPort^ > _serialPort;    //ошибка C3265 исчезла

Создавать экземпляр _serialPort надо теперь с помощью gcnew:

bool SerialGate::Open(int port, int baud)
{
   bool opened = false;
   _serialPort = gcnew SerialPort();
   ...
   return opened;
}

Можно использовать функцию Format, у которой синтаксис аналогичен синтаксису printf:

int port = 1;
_serialPort->PortName  = "COM" + String::Format("%i", port);

150115 — 15 января 2015

error C2664: CreateFileW: cannot convert parameter 1 from ‘char[]’ to ‘LPCWSTR’
error C2664: CreateFileW: невозможно преобразовать параметр 1 из «char []» в «LPCWSTR»

Пример кода, который порождает ошибку:

char comportpath[20];
sprintf(comportpath,"\.COM%d", port);
m_hFile = CreateFile(comportpath, GENERIC_READ|GENERIC_WRITE, 0, NULL,
                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);  // Ошибка C2664

Как исправить:

   wchar_t comportpath[20];
   swprintf(comportpath, L"\.COM%d", port);
   m_hFile = CreateFile(comportpath, GENERIC_READ|GENERIC_WRITE, 0, NULL,
                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);

Строковый литерал: это обычная строка текста, которая напрямую указывается в коде программы:

char myText [] = "Hello, World!";

Здесь был приведен пример обычной ASCIIZ строки, где каждый символ представлен 1 байтом. Некоторые функции Win API требуют на входе UNICODE-строк типа wchar_t. Для представления строковых литералов как строк из символов wchar_t используют макросы _T(), TEXT() и модификатор L. Примеры:

wchar_t myText1 [] = L"строка 1";wchar_t myText2 [] = _T("строка 2");wchar_t myText3 [] = TEXT("строка 3");

После загрузки данных (методами Row -> Add()) таблица DataGridView начинает себя вести непредсказуемо. Во-первых, полоса прокрутки справа от таблицы не соответствует количеству данных в таблице. Во-вторых, при прокрутке таблицы вниз клавишей со стрелкой «вниз» выскакивает исключение ArgumentOutOfRangeException. Пример полного сообщения об ошибке:

Необработанное исключение типа "System.ArgumentOutOfRangeException" произошло
в System.Windows.Forms.dll". Дополнительные сведения: Значение '154' недопустимо
для 'Value'. 'Value' должно лежать в диапазоне от 'minimum' до 'maximum'.

Решение проблемы: после заполнения таблицы данными нужно вызвать метод PerformLayout(). Пример:

void Form1::dgvCalibrScenarioFill (char* xmlfilename)
{
   IrrXMLReader* xml = createIrrXMLReader(xmlfilename);
   while(xml && xml->read())
   {
      switch(xml->getNodeType())
      {
      case EXN_TEXT:
         break;
      case EXN_ELEMENT:
         Node = xml->getNodeName();
         if (!strcmp("OBJECT", Node))
         {
            if ( (dgvCalibrScenario->RowCount - 1) < i )
            {
               dgvCalibrScenario->Rows->Add();
               for (int clmn=0; clmnColumnCount; clmn++)
                  dgvCalibrScenario->Rows[i]->Cells[clmn]->Value = spaceStr;
            }
            memset(Str,0,sizeof(Str));
            Str1 = xml->getAttributeValue("K");
            if(Str1 != NULL)
            {
               dgvCalibrScenario->Rows[i]->Cells[1]->Value       = gcnew String(Str1);
               dgvCalibrScenario->Rows[i]->Cells[1]->ToolTipText = gcnew String("K");
            }
            fFild = xml->getAttributeValueAsFloat("D");
            if(fFild>0)
            {
               sprintf_s(Str, sizeof(Str), "%1.1f", fFild);
               dgvCalibrScenario->Rows[i]->Cells[2]->Value = gcnew String(Str);
               dgvCalibrScenario->Rows[i]->Cells[1]->ToolTipText = gcnew String("D");
            }
            ++i;
         }//if (!strcmp("OBJECT", Node))
         break;
      }//switch(xml->getNodeType())
   }//while(xml && xml->read())
   delete xml;
   dgvCalibrScenario->PerformLayout();
   if (xmlfilereaded)
      strcpy_s(CFG.F_Calibr, sizeof(CFG.F_Calibr), xmlfilename);
}

В файле sdf сохраняется информация для работы подсистемы Visual Studio Intellisense (подсветка синтаксиса, рекомендации об устранении ошибок, предупреждения и т. п.). Этот файл занимает много места на диске (от 20 мегабайт и больше). Можно ли как-то безопасно удалить sdf-файл, чтобы при повторном открытии решения он создавался заново (или можно ли как-то вообще избавиться от этого файла)?

Опытным путем выяснил, что удаление файла на работоспособность проекта и Visual Studio не влияет. Файл *.sdf будет заново создан, когда Вы откроете проект.

[Каталог для размещения SDF-файла]

Можно также настроить место для сохранения этого файла (например в папке C:TEMP), что может быть полезным, когда Вы не хотите замусоривать Ваши каталоги с проектами лишними временными файлами. Перейдите в меню Tools -> Options -> Text Editor -> C/C++ -> Advanced, в разделе Fallback Location установите «Always Use Fallback Location» в True и «Do Not Warn If Fallback Location Used» в True. В разделе Fallback Location Вы можете ввести путь наподобие C:Temp, либо оставить путь пустым, тогда Visual Studio в качестве каталога будет использовать директорию временных файлов в папке AppData.

[Как запретить создание SDF-файла]

Можно совсем отключить базу данных Intellisense: меню Tools -> Options -> Text Editor -> C/C++ -> Advanced -> Disable Database выставьте в true.

C:Program Files (x86)Microsoft Visual Studio 10.0VCatlmfcincludeafx.h(24): fatal error C1189:
 #error :  Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version.
 Please #define _AFXDLL or do not use /MD[d]

Как исправить: открыть свойства конфигурации, опцию Общие -> Использование MFC -> задать в «Использовать MFC в общей DLL».

VisualStudio fix stdafx

По умолчанию все поля в структурах обычно имеют выравнивание на 4 байта (32-битное слово). Но как быть, если надо получить упакованную структуру, без пустот?

[GCC]

struct TLdrBlock
{
   u32 ADDRESS;
   u32 COUNT;
   u16 FLAG;
   char FLASHCRC16 [10];
   u32 sizeldrfile;
   u16 crc16;
}__attribute__((packed));

[Visual Studio C++]

#pragma pack(push)
#pragma pack(1)
struct TLdrBlock
{
   u32 ADDRESS;
   u32 COUNT;
   u16 FLAG;
   char FLASHCRC16 [10];
   u32 sizeldrfile;
   u16 crc16;
};
#pragma pack(pop)

[CString -> char*]

Получение массива символов char* из CString с помощью функции CStringA и метода CString::GetString:

static void Usage (void)
{
   CString csExe;
   csExe = AfxGetAppName();
   printf("Utility for add CRC (CRC16 CCITT) to Blackfin LDR-file. Usage:n");
   printf("%s srcfile.ldr [firmware.bin]n", CStringA(csExe.GetString()));
}

[char* -> CString]

Получение CString из массива символов char* еще проще — все делается вызовом конструктора:

char src [] = "HelloWorld";CString dst = CString(src);
void WLog (CString S)
{
   CStdioFile file;
   WORD Year, Month, Day, HH, MM, SS;
   CString asYear, asMonth, asDay, asHH, asMM, asSS;
 
   //Получить текущее время.
   CTime t = CTime::GetCurrentTime();
   Year  = t.GetYear();
   Month = t.GetMonth();
   Day   = t.GetDay();
   HH    = t.GetHour();
   MM    = t.GetMinute();
   SS    = t.GetSecond();
 
   asYear  = t.Format( "%Y" );
   asMonth = t.Format( "%m" );
   asDay   = t.Format( "%d" );
   asHH    = t.Format( "%H" );
   asMM    = t.Format( "%M" );
   asSS    = t.Format( "%S" );
 
   //Открыть файл лога на добавление и записать строку.
   if(file.Open(csExeName + CString(".log"),
                CFile::modeCreate
               |CFile::modeNoTruncate
               |CFile::modeWrite|CFile::typeText))
   {
      file.Seek(0L, CFile::end);
      file.WriteString(asYear + asMonth + asDay
                     + CString(" ") 
                     + asHH + CString(":") + asMM + CString(":")+ asSS + CString(", ") 
                     + S
                     + CString("n"));
   }
}

[Получение размера файла]

static u64 filesize (CString filename)
{
   u64 result = 0;
 
   try
   {
      CStdioFile file( filename,
         CFile::modeRead|CFile::typeBinary );
      result = file.GetLength();
      file.Close();
   }
   catch(CFileException* pe)
   {
      TRACE(_T("File could not be opened, cause = %dn"),
         pe->m_cause);
      pe->Delete();
   }
   return result;
}

[Чтение файла в двоичном режиме]

static UINT fileread (u8* data, CString filename, UINT size)
{
   UINT result = 0;
 
   try
   {
      CStdioFile file( filename,
         CFile::modeRead|CFile::typeBinary );
      result = file.Read(data, size);
      file.Close();
   }
   catch(CFileException* pe)
   {
      TRACE(_T("File could not be opened, cause = %dn"),
         pe->m_cause);
      pe->Delete();
   }
   return result;
}

[Запись файла в двоичном режиме]

Если файл filename не существует, то он будет создан, если существует, то он будет уничтожен и перезаписан.

static bool filewrite (u8* data, CString filename, UINT size)
{
   bool result = true;
   try
   {
      CStdioFile file( filename,
         CFile::modeCreate|CFile::modeWrite|CFile::typeBinary );
      file.Write(data, size);
      file.Close();
   }
   catch(CFileException* pe)
   {
      TRACE(_T("File could not be opened, cause = %dn"),
         pe->m_cause);
      pe->Delete();
      result = false;
   }
   return result;
}

[Запись файла в текстовом режиме на добавление]

В этом примере файл записывается как текстовый лог. Если файл csExeName.log не существует, то он будет создан, если существует, то содержимое строки S будет дописано в конец файла csExeName.log с добавлением метки текущего времени.

void WLog (CString S)
{
   CStdioFile file;
   WORD Year, Month, Day, HH, MM, SS;
   CString asYear, asMonth, asDay, asHH, asMM, asSS;
 
   //Получить текущее время.
   CTime t = CTime::GetCurrentTime();
   Year  = t.GetYear();
   Month = t.GetMonth();
   Day   = t.GetDay();
   HH    = t.GetHour();
   MM    = t.GetMinute();
   SS    = t.GetSecond();
 
   asYear  = t.Format( "%Y" );
   asMonth = t.Format( "%m" );
   asDay   = t.Format( "%d" );
   asHH    = t.Format( "%H" );
   asMM    = t.Format( "%M" );
   asSS    = t.Format( "%S" );
 
   //Открыть файл лога на добавление и записать строку.
   if(file.Open(csExeName + CString(".log"),
                CFile::modeCreate
               |CFile::modeNoTruncate
               |CFile::modeWrite|CFile::typeText))
   {
      file.Seek(0L, CFile::end);
      file.WriteString(asYear + asMonth + asDay
                     + CString(" ") 
                     + asHH + CString(":") + asMM + CString(":")+ asSS + CString(", ") 
                     + S
                     + CString("n"));
   }
}

Обе директивы подключают заголовочные файлы (с расширением *.h), где находятся определения типов, констант, макросов, внешних переменных. Но заголовочные файлы бывают разные — некоторые поставляются вместе с системой программирования (такой как Visual Studio или Qt) и предназначены для подключения кода «стандартных» библиотек, а некоторые создает сам пользователь.

Готовые загловочные файлы называются predefined, т. е. «уже определенные», и они указываются в угловых скобках (иногда без расширения). Например:

Заголовочные файлы, созданные пользователем, указываются в двойных кавычках:

Чтобы вызвать функцию, написанную на языке C, из кода на языке C++, нужно использовать ключевое слово extern «C», когда декларируется функция C. Тогда можно вызывать эту функцию точно так же, как вызов любой другой функции. Пример:

/* Это код C++ для декларации функции foo,
   которая где-то определена в коде C: */
extern "C" void foo( );

После этой декларации функция foo может быть вызвана в коде C++, примерно так:

extern "C" void foo();
 
void main()
{
   // Вызов функции:
   foo( );
}

А что если нам нужно декларировать сразу несколько функций в коде C++? Для этого лучше всего использовать для них группу, вот так:

/* Это код C++, где декларируется доступ к нескольким
   функциям C: */
extern "C" {
   int foo( );
   double foobar();
};

Когда событие исключения выброшено, но не обработано, то это означает, что не определен подходящий обработчик для вида выброшенного исключения. Это означает также, что вообще не найден никакой замещающий обработчик исключения (ellipsis catch handler, так называемый обработчик последнего шанса).

Итак, что произойдет в таком сценариии? На C++ есть заранее определенная функция terminate, которая будет вызвана, когда для исключение нет подходящего обработчика. Функция terminate затем вызовет другую функцию с именем abort. Функция abort остановит выполнение программы.

Однако также стоит отметить, что функция terminate может быть переопределена для вызова некоторой другой функции – которая не вызовет abort – перед выходом из приложения. Для этого просто используйте функцию set_terminate, и передайте ей имя функции, которую хотите вызвать вместо terminate. Для того, чтобы переданная функция работала стандартным образом, лучше всего в ней вызвать функцию exit для завершения работы приложения.

[Что такое ellipsis catch handler]

На C++ ellipsis catch handler очень прост. Все, что он делает — перехватывает любые не обработанные исключения. Поэтому ellipsis catch handler работает как обработчик последнего шанса, когда нет никакого другого подходящего обработчика. Вот пример того, как может выглядеть ellipsis catch handler:

try
{
   throw "Что-то там произошло";
}
// Это ellipsis catch handler:
catch(...)
{
   cout << "Для этого сценария нет подходящего обработчика";
}

Откуда пошло название ellipsis catch handler для такого обработчика? Причина тривиальна — многоточие «…», которое также называется ellipsis, и обычно оно используется в смысле «et cetera» (и так далее).

error C2146: синтаксическая ошибка: отсутствие ";" перед идентификатором "ulong64"

В данном случае неправильно задан оператор typedef для типа ulong64. Само собой, такая ошибка может возникнуть и при неправильном определени любого типа. Пример ошибочного определения типа:

typedef unsigned _uint64 ulong64;

В этом примере ошибка C2146 произошла из-за отсутствия определения типа _uint64. Для Visual Studio правильным определением 64-битного типа без знака может быть замена _uint64 на __int64, ошибка C2146 пропадет:

typedef unsigned __int64 ulong64;
error C2059: синтаксическая ошибка: неправильный суффикс для числа

Пример кода, который дает такую ошибку:

static const unsigned __int64 textkeys[256] = {
   15498727785010036736LLU,
   7275080914684608512LLU,
   ...

Причина в том, что Visual Studio (в зависимости от версии) может не полно поддерживать современные стандарты C++. Языки C++ и C оба определяют суффикся «ULL» и «LLU» как допустимые для целочисленных литералов. Однако VS2010 эти суффиксы не поддерживает, а VS2012 поддерживает только суффикс ULL.

Устранить ошибку C2059 для данного случая можно заменой суффикса LLU на LU:

static const unsigned __int64 textkeys[256] = {
   15498727785010036736LU,
   7275080914684608512LU,
   ...
error C2589: (: недопустимая лексема справа от "::"

Такая ошибка возникала в следующем коде:

double m = std::min(lof,hif);

Устранить ошибку можно, заключив std::min в круглые скобки:

double m = (std::min)(lof,hif);

В системе программирования MSVC используйте ключевое слово __inline или _inline вместо inline. Ключевое слово inline определено стандартом c99, и этот стандарт (пока) не полностью поддерживается в MSVC.

Цитата из источника [1]: «Ключевое слово inline доступно только в C++. Ключевые слова __inline и __forceinline доступны в обоих языках C и C++. Для совместимости с предыдущими версиями _inline является синонимом __inline».

На платформе MSVC (Visual Studio C++) замените __func__ на __FUNCTION__:

#if defined(_WIN32) || defined(_WIN64)
  #define __func__ __FUNCTION__
#endif

Здесь __FUNCTION__ это так называемый предопределенный макрос, который в Visual Studio C++ разворачивается в строковый литерал, который содержит имя функции, где встретился макрос __FUNCTION__ (подробнее см. [2]).

Следующие ошибки:

error C2143: синтаксическая ошибка: отсутствие ";" перед "тип
error C2275: LINEAR_DATA: недопустимое использование этого типа в качестве выражения

происходят из-за того, что переменная была определена в неправильном месте.

[Пример 1]

Переменная была определена в инициализации переменной цикла for, и код компилировался как код C (не C++), пример:

// Следующая строка давала ошибку компиляции C2143:
for (int i = 0; i < 8; i++)
{
   //Тут тело цикла:
   ...

Исправить ошибку можно, если компилировать код как C++. Или если вынести определение переменной из инициализации цикла:

int i;
for (i = 0; i < 8; i++)
{
   //Тут тело цикла:
   ...

[Пример 2]

static int linear_copy (SRC_PRIVATE *from, SRC_PRIVATE *to)
{
   if (from->private_data == NULL)
      return SRC_ERR_NO_PRIVATE;
 
   LINEAR_DATA *to_priv = NULL; // ошибка C2275
   ...

Здесь ошибка C2275 происходит потому, что переменная to_priv определена не в начале функции. Устранение ошибки:

static int linear_copy (SRC_PRIVATE *from, SRC_PRIVATE *to)
{
   LINEAR_DATA *to_priv;
 
   if (from->private_data == NULL)
      return SRC_ERR_NO_PRIVATE;
   to_priv = NULL;
   ...

IDE Visual Studio не может найти файл заголовка, который находится в корневой папке проекта. Откройте свойства проекта, зайдите в раздел Свойства конфигурации -> Каталоги VC++ и в раздел «Каталоги включения» добавьте $(ProjectDir). Иногда $(ProjectDir) надо также добавить в раздел «Справочные каталоги».

[Ссылки]

1. Inline Functions (C++) site:docs.microsoft.com.
2. Predefined Macros site:docs.microsoft.com.

Понравилась статья? Поделить с друзьями:
  • Ошибка невнимательного 9 букв сканворд
  • Ошибка недопозиционирования означает что
  • Ошибка неверный формат файла обновления
  • Ошибка недоделка 5 букв сканворд
  • Ошибка неверный формат отчета