Hungry Mind , Blog about everything in IT - C#, Java, C++, .NET, Windows, WinAPI, ...

Top 10 New Year intimate presents for your ladies

Не силен в сексе - сделай подарок [:-)].

Топ 10 новогодних подарков для женщин

Десять самых ярких эротических подарков по версии интернет-магазина В постели. C бесплатной доставкой по Киеву в день заказа, без выходных.

10

1
Изящная пробочка для утонченных любительниц удовольствий. Стильная штучка откроет двери к новым эротическим переживаниям в новом году!
89 грн

9

2
Для настоящих сладкоежек – отличный подарок к новому году! Девочки, которые уже выросли из возраста шоколадных зайчиков и Дедов Морозов, будут в восторге от шоколадного достоинства!
95 грн

8

3
Девушки просто обожают красивое белье, а уж если оно еще и дарит удовольствие – то это просто отличнейший подарок к Новому году!
151 грн

7

4
Драгоценные жемчужины для настоящей русалочки – вагинальные шарики в красивой упаковке для здоровья и удовольствия любительницы морских приключений.
194 грн

6

5
Маленькое вибрирующее сердечко легко станет приятным украшением женских трусиков, превращая их в предмет тайного удовольствия! Покажите, насколько сильна ваша любовь!
203 грн

5

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

4

7
Самый лучший подарок для меломанки – музыкальный вибратор, который подключается практически к любому МР3 плееру или компьютеру, и вибрирует в такт. Никогда еще музыка не звучала так приятно!
325 грн

3

8
2010 год по восточному календарю – год Металлического Тигра. Не забудьте подарить золотой или серебряный набор для жаркой новогодней ночи!
429 грн

2

9
Изысканный предмет удовольствия для роскошной красавицы. Этот элитный вибратор подарит множество горячих удовольствий холодной зимой.
882 грн

1

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

Опубликовано 20.12.2009в 22:11. В рубриках: Новости. Вы можете следить за ответами к этой записи через RSS 2.0. Вы можете оставить свой отзыв или трекбек со своего сайта.

Top 10 New Year intimate presents for you guys

Ну, что, ботаники-стесняшки, не стесняйтесь [:-)].

Топ 10 новогодних подарков для мужчин

Оригинальные подарки на Новый год сильной половине человечества. Все подарки можно заказать с бесплатной доставкой по Киеву, без выходных и обеденного перерыва [:-)]. Читаем полностью.

10

10
Послушная овечка для настоящего Тигра к Новому году! Невинная мордашка и рабочая попка – то, что нужно настоящему хищнику [;-)].
53 грн

9

9
Согрейте ЕГО зимой этими веселыми новогодними стрингами, и ОН отблагодарит вас веселой песенкой!
116 грн

8

8
С этими наручниками она не будет сопротивляться! Делай все, что ты хочешь со своей Снегурочкой, не останавливайся!
151 грн

7

7

Металлическое эрекционное кольцо, инкрустированное стразами – изысканное украшение для драгоценной части тела любимого мужчины! Для знающих толк в колечках.
199 грн

6

6
Нежный массаж с согревающим кремом не даст любимому замерзнуть холодными зимними ночами. Добавьте тепла в ваши отношения!
230 грн

5

5
Гладкая маленькая пробка из прозрачного стекла, словно ледяная – стоящий подарок ценителям сексуального удовольствия и искусства.
240 грн

4

4
Тонкая и стильная волшебная вибропалочка для массажа простаты и невероятного удовольствия от стимуляции самых горячих эрогенных зон.
280 грн

3

3
Мужской аромат с феромонами – для настоящего мачо, который знает, как привлечь женщин.
300 грн

2

2
Лучший подарок автомобилистам – теперь ожидание в пробках на заснеженных дорогах не будет таким томительным! Эти губки, работающие от прикуривателя, зададут жару!
368 грн

1

1
Для настоящих экспериментаторов – любовные качели, которые дают неограниченный простор для фантазии во время секса! Задайте жару в новогоднюю ночь!
1550 грн

Опубликовано 20.12.2009в 21:03. В рубриках: Новости. Вы можете следить за ответами к этой записи через RSS 2.0. Вы можете оставить свой отзыв или трекбек со своего сайта.

Mineral water quiz

Итак, сажусь в авто - на термометре -8. Стеклянная бутылка Боржоми сожержит лишь лёд - все нормально. Поллитровая пластиковая бутылка воды Софія київська содержит исключительно воду, никакого льда. Я выкручиваю крышку и наблюдаю, как с горлышка до дна это вода за секунд 10 превращается в лёд. Вода негазированная, при открытии никакого пшика не было. Вопрос - ПОЧЕМУ?

Memorable Quote

Вчера такую блондинку классную на Ferrari кабриолете видел! Но я тоже типа в грязь лицом не упал... сидел на переднем сидении водителя маршрутки.

Always initialize variables

Наверное с каждым случалось, что при запуске релизной версии она вообще не работает. Недавно это опять произошло со мной. Следующий код ругался матом (assert-ом):

UErrorCode uError;
ucnv_fromUnicode(_pConverter, &pTarget, pTargetLimit, &pSource, pSourceLimit, NULL, true, &uError);
assert(U_SUCCESS(uError));

В результате была произведена модификация UErrorCode uError(U_ZERO_ERROR); и все заработало. Но самое интересное - кусок кода библиотеки ICU:

U_CAPI void U_EXPORT2
   ucnv_fromUnicode(UConverter *cnv,
                    char **target, const char *targetLimit,
                    const UChar **source, const UChar *sourceLimit,
                    int32_t *offsets,
                    UBool flush,
                    UErrorCode *err) {
      UConverterFromUnicodeArgs args;
      const UChar *s;
      char *t;

        /* check parameters */
      if(err==NULL || U_FAILURE(*err)) {
         return;
      }

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

Итог: всегда инициализируйте переменные значениями.

PS: Во всех других местах uError была инициализирован правильно. Случается.

Codekana for Visual Studio

Нашел на днях отличный плагин для Visual Studio - Codekana. Основная функция - покраска кода. Очень удобно. Я вообще считаю, что такие вещи должны поддерживаться изначально самим редактором.

Codekana

Funny parking

Заехал красиво, дупой, - к бровке максимум сантиметр остался. А вот выехать было тяжело. [:-)]

Pavement aside parking

Memorable Quote

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

Diamond 2 iGo GPS problem

Уже вторую неделю не могу разобраться с iGo на своем Diamond 2. Возникают следующие проблемы:

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

Сука...

Migration to Windows 7

Наконец решился обновиться на Windows 7. Первая попытка успешно провалилась. Тужилось часа 3 и под конец решило, что нужно сделать revert к Vista. Виной всему - Daemon Tools, о чем инсталлятор предварительно предупредил! Во второй раз я поудалял все программы, на которые ругалось и вуаля - наслаждаюсь новой ОС. Первые впечатления - супер. И работает, кстати, ощутимо быстрее!

N97 iPhone 3GS HTC Touch Diamond 2

Решил обновить мобильный телефон. В текущем E61 уже батарея умирает, да и GPS хочется. Мне в телефоне не интересны камера, музыка и прочая ерунда. Начитавшись обзоров пришел к выбору между

  1. Nokia N97

    Nokia N97

  2. Apple iPhone 3GS

    Apple iPhone 3GS

  3. HTC Touch Diamond 2

    HTC Touch Diamond 2

  4. HTC Touch Pro 2

    HTC Touch Pro 2

Начитавшись обзоров, пришел к выводам:

  • Nokia N97 - тормознутый аппарат с сырой прошивкой, стоимость у нас зашкаливает - 900$.
  • Apple iPhone 3GS - игрушка для тупых блонд. В нем даже многозадачности нет! Я уже не говорю о наличии (точнее неналичии) нужного ПО - Garmin, iGo.
  • HTC Touch Diamond 2 - понравился со всех сторон. Люблю квадратные и плоские телефончики. 600$ - вполне адекватная цена. Но от Windows Mobile меня тошнит, Symbian намного лучше.
  • HTC Touch Pro 2 - тот же Diamond 2, но с кастрированной QWERTY клавиатурой, на которую не влезут все русские и украинские буквы.

Вот если бы Nokia N97 тачскрин и аппаратную начинку, как у iPhone, плюс обилие ПО, как для WM - был бы идеальный телефон.

Tiesto in Kiev

Клёво было. Папка выдал "I just want to say: Kiev, you are the best. I will play for you all night". И играл 5 с половиной часов вместо заявленных 4-х. Садюга...

He is the boss of trance!
Not only the boss, he is the god of trance...
No... He is the boss of all gods of trance...

How to read unicode text file in C++

Не первый раз сталкиваюсь с задачей чтения UNICODE символов, строк из текстового файла стандартными средствами С++. И в очередной раз понимаю, как С++ устарел...

Первое решение, которое приходит в голову, - использовать классы std::wifstream и std::wstring. Но, к сожалению, результирующие строки заполнены мусором. Второй вариант - читать char-ы в режиме binary, после reinterpret_cast-ом получить wchar_t*. Но этот вариант очень неудобен, т.к. требует написания лишнего кода, нельзя пользоваться оператором >> и, как результат, istream_iterator.

Почему так? Во-первых, следует понять, что UNICODE - это не кодировка. Не совсем кодировка. UNICODE - это набор символов, а также способы их представления в 8-битной, 16-битной и 32-битной формах - кодировках UTF-8, UTF-16 и UTF-32 соответственно. Поэтому наш UNICODE-файл может содержать символы, закодированные одним из перечисленных способов.

Текущая версия стандарта насчитывает более миллиона символов. UTF-16 способен представить лишь 65536 из них. Тип wchar_t имеет разную длинну в зависимости от платформы (ОС, компилятора, ...). Для Windows - 2 байта, для Linux - 4 и т.д. В итоге мы пытаемся читать файл с неизвестной кодировкой в неизвестное представление строки символов из набора UNICODE. В результате - мусор.

Свою проблему я решил следующим способом:

  1. Сохранил текст в кодировке UTF-16.
  2. Вежливо попросил std::wifstream использовать специальный аспект (facet) для перекодирования символов.

    Стандартная библиотека содержит аспект std::codecvt. Компилятор, соответствующий стандарту, должен как минимум содержать специализацию std::codecvt<char, wchar_t, std::mbstate_t>, что позволяет читать ANSI символы в строку wchar_t. А нам нужно wchar_t в wchar_t. Для этого в библиотеке boost есть класс boost::archive::codecvt_null (#include <boost/archive/codecvt_null.hpp>).

Результирующий код:

std::wifstream &stream = ...;
std::locale loc(stream.getloc(), new boost::archive::codecvt_null<wchar_t>());
stream.imbue(loc);
std::vector<std:wstring> data(std::istream_iterator<std:wstring>(stream), std::istream_iterator<std:wstring>());

Кстати, есть еще utf8_codecvt_facet (#include <boost/detail/utf8_codecvt_facet.hpp>).

boost::random in a nutshell

Boost Random Number Library - библиотека для генерации случайных чисел. Условно поделена на 3 части:

  1. Генераторы.

    Генератор - это класс, который производит случайные числа. Некий алгоритм, который, как правило, имеет параметры. Качество генератора сильно зависит от этих параметров. Для каждого алгоритма есть специализация с правильно подобранными параметрами. Алгоритмы имеют различные требования к памяти, разное качество случайных чисел и, естественно, разную скорость.

  2. Распределения.

    Распределение - закон, который описывает область значений случайной величины и вероятности их принятия. Распределения есть дискретные, непрерывные. Чаще всего используются равномерные распределения - uniform distributions.

  3. Их комбинации - вариаторы.

    Вариатор совмещает геренатор и распределение.

Примеры.

Равномерное дискретное распределение.

boost::int32_t number;
boost::hellekalek1995 generator(GetTickCount());
number = generator();
boost::uniform_smallint<BYTE> distribution(1, 10);
BYTE result;
result = distribution(generator);
boost::variate_generator<boost::hellekalek1995, boost::uniform_smallint<BYTE>> random(generator, distribution);
result = random();

Кстати, генератору надо дать пинка - стартовое значение (seed). Я обычно использую GetTickCount.

Распределение Бернулли.

boost::int32_t number;
boost::hellekalek1995 generator(GetTickCount());
number = generator();
bool success;
boost::bernoulli_distribution<> distribution(0.2);
success = distribution(generator);
boost::variate_generator<boost::hellekalek1995, boost::bernoulli_distribution<>> random(generator, distribution);
success = random();

Windows Vista SP2 Wave 1 is out

Boost 1.39 released

New Libraries

  • Signals2 Managed signals & slots callback implementation (thread-safe version 2), from Frank Mori Hess.

ATI Catalyst Install problem solved

Решил поставить свежий Catalyst. Опять та же беда - CATALYST™ Install Manager has stopped working. Случайно открыл такое вот окошко:

Problem Reports and Solutions

Далее по второй ссылке:

KB961894: An application crashes after you install a product that updates the Mfc80.dll or Mfc80u.dll module

See related problems показывает:

CATALYST™ Install Manager Stopped working

Скачал и поставил KB961894. Теперь устанавливается без проблем.

Stinky running shoes

В штате Вермонт прошел ежегодный конкурс среди детей и подростков на самые вонючие кроссовки, сообщает BBC News. В соревновании 2009 года победителем стал семилетний мальчик из Юты.

В конкурсе Rotten Sneaker Contest приняли участие семеро победителей местных соревнований - школьники в возрасте от семи до пятнадцати лет. Жюри оценивало состояние языка, шнурков и подошв обуви, но определяющим фактором был запах. Среди членов жюри были химик из NASA и исследователь запахов из Браунского университета.

Победитель получил денежный приз в размере 2500 долларов, годовой запас дезодорантов для обуви и ног, а также поездку в Нью-Йорк. Кроссовки будут выставлены на всеобщее обозрение в Вермонте.

Конкурс на самые вонючие кроссовки проводится с 1975 года при поддержке сети магазинов спортивной одежды и производителей дезодорантов. В 2008 году победителем стал 15-летний подросток из штата Аляска, а в 2007 - 13-летняя школьница из Юты.

Солнце (13:27:03 14/04/2009)
2008 году победителем стал 15-летний подросток из штата Аляска, а в 2007 - 13-летняя школьница из Юты.
маленькие грязные дибилы блин

vadimra (13:29:53 14/04/2009)
гы мы можем киевских бомжей номинировать

Солнце (13:31:18 14/04/2009)
а то! они знаешь как завоняют все амеров - сходи в метро контрактовая в 10-11 вечера! еще и 2500 баксов приз - это скока ж водки купить можно

Sem (13:31:20 14/04/2009)
Я уверен у сантехника с очистных сооружений больше шансов

BITS Manager v1.02.005

  • Refactored General page layout.
  • Refactored Aux page layout.
  • Refactored Proxy settings dialog layout.
  • Added proxy authentication support.
  • Added HTTP authentication support.
  • Program size and distribution size are reduced.

Download BITS Manager v1.02.005

My first road accident

Firefox is a PANDA!!!

Оказалось, Firefox - это не горящая лисица, а красная панда!

Red Panda

Funny code

Надо придумать специальное название для таких вот смешных кусков кода: Control.ModifierKeys == Keys.Control.

ASP.NET MVC 1.0 released

Тихонько вышел ASP.NET MVC 1.0. Download ASP.NET MVC 1.0

WWS - How to read SOAP Fault

Сервера веб служб возвращают ошибки в элементе SOAP Fault. Здесь я объясню, как прочитать эту информацию.

Как узнать, что произошел сбой? Проверить код возврата на равенство WS_E_ENDPOINT_FAULT_RECEIVED. Дальше начинается магия.

WS_FAULT *pFault;
hr = WsGetFaultErrorProperty(pError, WS_FAULT_ERROR_PROPERTY_FAULT, &pFault, sizeof(pFault));

Структура определена следующим образом:

//  Faults structure
//
//   A Fault is a value carried in the body of a message which conveys a
//  processing failure.  Faults are modeled using the WS_FAULT structure.
//  See Faults for more information.
//
struct _WS_FAULT {
    WS_FAULT_CODE* code;
    WS_FAULT_REASON* reasons;
    ULONG reasonCount;
    WS_STRING actor;
    WS_STRING node;
    WS_XML_BUFFER* detail;
};

Наибольший интерес вызывает информация, заложенная в элементе <detail/>. WCF определяет специальные сущности с названием Fault Contract. Мы хотим их получить в удобном виде. Текущая версия WWS не генерирует код для Fault Contract-ов. Можно прочитать голый XML или вручную написать эти структуры вместе с метаданными, которые их описывают.

WS_XML_WRITER *pWriter;
hr = WsCreateWriter(NULL, 0, &pWriter, pError);

WS_XML_WRITER_TEXT_ENCODING textEncoding;
textEncoding.charSet = WS_CHARSET_UTF8;
textEncoding.encoding.encodingType = WS_XML_WRITER_ENCODING_TYPE_TEXT;

LPVOID pBuf;
ULONG nBufSize;
hr = WsWriteXmlBufferToBytes(pWriter, pFault->detail, &textEncoding.encoding, NULL, 0, _pWsHeap, &pBuf, &nBufSize, _pWsError);

WsFreeWriter(pWriter);

Этот код запишет XML в буффер pBuf (там будет строка в кодировке UTF-8). Кстати, метод WsWriteXmlBufferToBytes хочет в 3-м параметре __in_opt const WS_XML_WRITER_ENCODING* encoding, а мы ему передаем указатель на член структуры WS_XML_WRITER_TEXT_ENCODING. Учитывая значение WS_XML_WRITER_ENCODING_TYPE_TEXT в поле encodingType, WWS предполагает, что дальше в памяти содержится WS_CHARSET. В WWS многие методы работают таким вот хитрым образом - полагаются на расположение вложенных структур в оперативной памяти.

Десериализацию структуры я опишу позже. Может быть.

Beginning WWS

Не так давно появилась beta версия Windows Web Services для ОС семейства Windows XP и Vista. WWS должен войти в состав новой операционки Windows 7, но хитрые менеджеры поняли, что неплохо иметь этот функционал и на более ранних версиях ОС Windows. К тому же, уверен, WWS API будет готов гораздо раньше, чем Windows 7. Да, кстати, WWS API - это библиотека для создания веб служб на языках C/C++. Наконец то! Мне захотелось попробовать WWS API в деле, чем я и занялся на днях.

Некоторые подробности можно узнать на персональном блоге product manager'а WWS - Nikola Dudar. Там же есть ссылка на не очень полезное видео о WWS.

Для поиграться нужно скачать и поставить саму библиотеку WWS, а также Windows 7 SDK Beta, который содержит заголовочные файлы и утилиты, необходимые для программирования Windows Web Services.

WWS позволяет создавать как клиенты веб сервисов, так и сами сервисы. На первых порах я разбирался лишь с клиенткой частью, но механизм в целом одинаков. Оба сценария предполагают наличиеwsdl файла для генерации кода. Как не трудно догадаться, применен механизм WSDL First, что понятно - разобрать С++ код сложновато, а интроспекции нет.

Для примера я решил взять службу погоды - http://www.webservicex.com/globalweather.asmx. wsdl файл, как обычно, можно получить по следующему адресу: http://www.webservicex.com/globalweather.asmx?wsdl. Для генерации необходимых файлов необходимо выполнить аж одну команду:

"c:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\Wsutil.exe" WeatherService.wsdl

В результате чего должны появиться файлы WeatherService.wsdl.h и WeatherService.wsdl.c. Их необходимо добавить в проект, после чего отключить использование Precompiled Header у WeatherService.wsdl.c. А в stdafx.h не помешает добавить следующее:

#include <WebServices.h>
#pragma comment(lib, "WebServices.lib")

Сгенерированные файлы содержат

  1. структуры данных, соответствующие схеме, заложенной в секции <wsdl:types>;
  2. метаданные, необходимые WWS для взаимодействия со службой;
  3. вспомогательные методы, упрощающие взаимодействие со службой.

Чтобы начать вызывать удаленные методы, необходимо создать канал. В Microsoft решили не отходить далеко от терминологии WCF и использовать известные всем понятия - channel, endpoint и т.д. В сгенерированном коде есть для этого специальный метод:

HRESULT GlobalWeatherSoap_CreateServiceProxy(
    __in_opt WS_HTTP_BINDING_TEMPLATE* templateValue,
    __in_ecount_opt(proxyPropertyCount) const WS_PROXY_PROPERTY* proxyProperties,
    __in const ULONG proxyPropertyCount,
    __deref_out_opt WS_SERVICE_PROXY** _serviceProxy,
    __in_opt WS_ERROR* error)
{
    return WsCreateServiceProxyFromTemplate(
        WS_CHANNEL_TYPE_REQUEST,
        proxyProperties,
        proxyPropertyCount,
        WS_HTTP_BINDING_TEMPLATE_TYPE,
        templateValue,
        templateValue == NULL ? 0 : sizeof(WS_HTTP_BINDING_TEMPLATE),
        &WeatherService_wsdl.policies.GlobalWeatherSoap,
        sizeof(WeatherService_wsdl.policies.GlobalWeatherSoap),
        _serviceProxy,
        error);
}

Как видно из кода, эта функция - просто обертка над WsCreateServiceProxyFromTemplate, которая и выполняет всю работу по созданию канала. Генератор кода сообразил, что используется WS HTTP привязка, и сгенерировал соответствующий код. WWS поддерживает много привязок, о чем свидетельствует следующее перечисление:

//  Policy Support enum
//
//   An enumeration of the different security binding combinations that
//  are supported in current product.
//
typedef enum
{
    WS_HTTP_BINDING_TEMPLATE_TYPE                                         = 0,
    WS_HTTP_SSL_BINDING_TEMPLATE_TYPE                                     = 1,
    WS_HTTP_HEADER_AUTH_BINDING_TEMPLATE_TYPE                             = 2,
    WS_HTTP_SSL_HEADER_AUTH_BINDING_TEMPLATE_TYPE                         = 3,
    WS_HTTP_SSL_USERNAME_BINDING_TEMPLATE_TYPE                            = 4,
    WS_HTTP_SSL_KERBEROS_APREQ_BINDING_TEMPLATE_TYPE                      = 5,
    WS_TCP_BINDING_TEMPLATE_TYPE                                          = 6,
    WS_TCP_SSPI_BINDING_TEMPLATE_TYPE                                     = 7,
    WS_TCP_SSPI_USERNAME_BINDING_TEMPLATE_TYPE                            = 8,
    WS_TCP_SSPI_KERBEROS_APREQ_BINDING_TEMPLATE_TYPE                      = 9,
    WS_HTTP_SSL_USERNAME_SECURITY_CONTEXT_BINDING_TEMPLATE_TYPE           = 10,
    WS_HTTP_SSL_KERBEROS_APREQ_SECURITY_CONTEXT_BINDING_TEMPLATE_TYPE     = 11,
    WS_TCP_SSPI_USERNAME_SECURITY_CONTEXT_BINDING_TEMPLATE_TYPE           = 12,
    WS_TCP_SSPI_KERBEROS_APREQ_SECURITY_CONTEXT_BINDING_TEMPLATE_TYPE     = 13,
} WS_BINDING_TEMPLATE_TYPE;

Кстати, нам понадобятся объекты WS_ERROR и WS_HEAP. WS_ERROR используется для чтения ошибок на клиенте и записи их на сервере. А WS_HEAP - для выделения памяти под различные объекты, которые возникают в процессе работы с каналом:

BOOL GlobalWeatherClient::OpenConnection() {
    _hr = WsCreateError(NULL, 0, &_pWsError);
    if (FAILED(_hr)) {
        return(FALSE);
    }

    _hr = WsCreateHeap(10000000, 0, NULL, 0, &_pWsHeap, _pWsError);
    if (FAILED(_hr)) {
        PrintError(_hr, _pWsError);
        CloseConnection();
        return(FALSE);
    }

Далее необходимо заполнить структуру WS_HTTP_BINDING_TEMPLATE:

    WS_HTTP_BINDING_TEMPLATE templateValue = { };
    ULONG maxMessageSize = 2147483647;
    ULONG timeout = 1000 * 60 * 2;

    WS_CHANNEL_PROPERTY channelProperty[5];

    channelProperty[0].id = WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE;
    channelProperty[0].value = &maxMessageSize;
    channelProperty[0].valueSize = sizeof(maxMessageSize);

    channelProperty[1].id = WS_CHANNEL_PROPERTY_CONNECT_TIMEOUT;
    channelProperty[1].value = &timeout;
    channelProperty[1].valueSize = sizeof(timeout);

    channelProperty[2].id = WS_CHANNEL_PROPERTY_SEND_TIMEOUT;
    channelProperty[2].value = &timeout;
    channelProperty[2].valueSize = sizeof(timeout);

    channelProperty[3].id = WS_CHANNEL_PROPERTY_RECEIVE_RESPONSE_TIMEOUT;
    channelProperty[3].value = &timeout;
    channelProperty[3].valueSize = sizeof(timeout);

    channelProperty[4].id = WS_CHANNEL_PROPERTY_RECEIVE_TIMEOUT;
    channelProperty[4].value = &timeout;
    channelProperty[4].valueSize = sizeof(timeout);

    WS_CHANNEL_PROPERTIES channelProperties;
    channelProperties.properties = channelProperty;
    channelProperties.propertyCount = _countof(channelProperty);

    templateValue.channelProperties = channelProperties;

Из шаблона создать канал:

    _hr = GlobalWeatherSoap_CreateServiceProxy(&templateValue, NULL, 0, &_pWsServiceProxy, _pWsError);
    if (FAILED(_hr)) {
        PrintError(_hr, _pWsError);
        CloseConnection();
        return(FALSE);
    }

В конце концов, открыть канал, задав адрес сервиса:

    WS_ENDPOINT_ADDRESS address = { };
    WS_STRING url = WS_STRING_VALUE(L"http://www.webservicex.com/globalweather.asmx");
    address.url = url;

    _hr = WsOpenServiceProxy(_pWsServiceProxy, &address, NULL, _pWsError);
    if (FAILED(_hr)) {
        PrintError(_hr, _pWsError);
        CloseConnection();
        return(FALSE);
    }
    return(TRUE);
}

Для каждой операции генерируется помошничек:

// operation: GlobalWeatherSoap_GetWeather
HRESULT WINAPI GlobalWeatherSoap_GetWeather(
    __in WS_SERVICE_PROXY* _serviceProxy,
    __in __nullterminated WCHAR* CityName,
    __in __nullterminated WCHAR* CountryName,
    __out __deref __nullterminated WCHAR** GetWeatherResult,
    __in WS_HEAP* _heap,
    __in_ecount_opt(_callPropertyCount) const WS_CALL_PROPERTY* _callProperties,
    __in const ULONG _callPropertyCount,
    __in_opt const WS_ASYNC_CONTEXT* _asyncContext,
    __in_opt WS_ERROR* _error)
{
    void* _argList[3];
    _argList[0] = &CityName;
    _argList[1] = &CountryName;
    _argList[2] = &GetWeatherResult;
    return WsCall(_serviceProxy,
        (WS_OPERATION_DESCRIPTION*)&WeatherService_wsdlLocalDefinitions.contracts.GlobalWeatherSoap.GlobalWeatherSoap_GetWeather.GlobalWeatherSoap_GetWeather,
        (void **)&_argList,
        _heap,
        _callProperties,
        _callPropertyCount,
        _asyncContext,
        _error);
}

Вызвать операцию проще простого:

std::wstring GlobalWeatherClient::GetWeather(LPWSTR pszCity, LPWSTR pszCountry) {
    LPWSTR result;
    _hr = GlobalWeatherSoap_GetWeather(_pWsServiceProxy, pszCity, pszCountry, &result, _pWsHeap, NULL, 0, NULL, _pWsError);
    if (FAILED(_hr)) {
        PrintError(_hr, _pWsError);
        return(wstring());
    }
    return(result);
}

По завершению работы канал необходимо закрыть, а все остальные объекты освободить:

void GlobalWeatherClient::CloseConnection() {
    if (_pWsServiceProxy) {
        WsCloseServiceProxy(_pWsServiceProxy, NULL,  _pWsError);
        WsFreeServiceProxy(_pWsServiceProxy);
        _pWsServiceProxy = NULL;
    }
    if (_pWsHeap) {
        WsFreeHeap(_pWsHeap);
        _pWsHeap = NULL;
    }

    if (_pWsError) {
        WsFreeError(_pWsError);
        _pWsError = NULL;
    }
}

Довольно интересно автора решили проблему выделения и освобождения памяти с помощью концепции куча или просто HEAP. Память из кучи выделяется функцией WsAlloc, но функции для ее освобождения нет! Вместо этого куча просто очищается одним махом вызовом WsResetHeap. Куча, кстати, не обязательно одна. Это порождает интересные сценарии использования. Например, для метода с массивным объемом данных можно использовать отдельную кучу.

Генератор создает чистоплотный C-код, который каждый любитель ООП, уверен, захочет обернуть в удобный класс, как здесь:

#pragma once
#include "GlobalWeather/WeatherService.wsdl.h"

class GlobalWeatherClient
{

public:
    GlobalWeatherClient();
    ~GlobalWeatherClient();

public:
    BOOL OpenConnection();
    void CloseConnection();

public:
    wstring GetCitiesByCountry(LPWSTR pszCountry);
    wstring GetWeather(LPWSTR pszCity, LPWSTR pszCountry);

protected:
    void PrintError(HRESULT errorCode, WS_ERROR *error);

private:
    HRESULT _hr;
    WS_ERROR *_pWsError;
    WS_HEAP *_pWsHeap;
    WS_SERVICE_PROXY *_pWsServiceProxy;

};

#include "stdafx.h"
#include "GlobalWeatherClient.h"

GlobalWeatherClient::GlobalWeatherClient() {
    _hr = S_OK;
    _pWsError = NULL;
    _pWsHeap = NULL;
    _pWsServiceProxy = NULL;
}

GlobalWeatherClient::~GlobalWeatherClient() {
    CloseConnection();
}

BOOL GlobalWeatherClient::OpenConnection() {
    _hr = WsCreateError(NULL, 0, &_pWsError);
    if (FAILED(_hr)) {
        return(FALSE);
    }

    _hr = WsCreateHeap(10000000, 0, NULL, 0, &_pWsHeap, _pWsError);
    if (FAILED(_hr)) {
        PrintError(_hr, _pWsError);
        CloseConnection();
        return(FALSE);
    }

    WS_HTTP_BINDING_TEMPLATE templateValue = { };
    ULONG maxMessageSize = 2147483647;
    ULONG timeout = 1000 * 60 * 2;

    WS_CHANNEL_PROPERTY channelProperty[5];

    channelProperty[0].id = WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE;
    channelProperty[0].value = &maxMessageSize;
    channelProperty[0].valueSize = sizeof(maxMessageSize);

    channelProperty[1].id = WS_CHANNEL_PROPERTY_CONNECT_TIMEOUT;
    channelProperty[1].value = &timeout;
    channelProperty[1].valueSize = sizeof(timeout);

    channelProperty[2].id = WS_CHANNEL_PROPERTY_SEND_TIMEOUT;
    channelProperty[2].value = &timeout;
    channelProperty[2].valueSize = sizeof(timeout);

    channelProperty[3].id = WS_CHANNEL_PROPERTY_RECEIVE_RESPONSE_TIMEOUT;
    channelProperty[3].value = &timeout;
    channelProperty[3].valueSize = sizeof(timeout);

    channelProperty[4].id = WS_CHANNEL_PROPERTY_RECEIVE_TIMEOUT;
    channelProperty[4].value = &timeout;
    channelProperty[4].valueSize = sizeof(timeout);

    WS_CHANNEL_PROPERTIES channelProperties;
    channelProperties.properties = channelProperty;
    channelProperties.propertyCount = _countof(channelProperty);

    templateValue.channelProperties = channelProperties;

    _hr = GlobalWeatherSoap_CreateServiceProxy(&templateValue, NULL, 0, &_pWsServiceProxy, _pWsError);
    if (FAILED(_hr)) {
        PrintError(_hr, _pWsError);
        CloseConnection();
        return(FALSE);
    }

    WS_ENDPOINT_ADDRESS address = { };
    WS_STRING url = WS_STRING_VALUE(L"http://www.webservicex.com/globalweather.asmx");
    address.url = url;

    _hr = WsOpenServiceProxy(_pWsServiceProxy, &address, NULL, _pWsError);
    if (FAILED(_hr)) {
        PrintError(_hr, _pWsError);
        CloseConnection();
        return(FALSE);
    }
    return(TRUE);
}

void GlobalWeatherClient::CloseConnection() {
    if (_pWsServiceProxy) {
        WsCloseServiceProxy(_pWsServiceProxy, NULL,  _pWsError);
        WsFreeServiceProxy(_pWsServiceProxy);
        _pWsServiceProxy = NULL;
    }
    if (_pWsHeap) {
        WsFreeHeap(_pWsHeap);
        _pWsHeap = NULL;
    }

    if (_pWsError) {
        WsFreeError(_pWsError);
        _pWsError = NULL;
    }
}

wstring GlobalWeatherClient::GetCitiesByCountry(LPWSTR pszCountry) {
    LPWSTR result;
    _hr = GlobalWeatherSoap_GetCitiesByCountry(_pWsServiceProxy, pszCountry, &result, _pWsHeap, NULL, 0, NULL, _pWsError);
    if (FAILED(_hr)) {
        PrintError(_hr, _pWsError);
        return(wstring());
    }
    return(result);
}

std::wstring GlobalWeatherClient::GetWeather(LPWSTR pszCity, LPWSTR pszCountry) {
    LPWSTR result;
    _hr = GlobalWeatherSoap_GetWeather(_pWsServiceProxy, pszCity, pszCountry, &result, _pWsHeap, NULL, 0, NULL, _pWsError);
    if (FAILED(_hr)) {
        PrintError(_hr, _pWsError);
        return(wstring());
    }
    return(result);
}

void GlobalWeatherClient::PrintError(HRESULT errorCode, WS_ERROR *pError) {
    cout << "Failure errorCode=0x" << hex << errorCode << endl;

    HRESULT hr = S_OK;
    if (pError) {
        ULONG errorCount;
        hr = WsGetErrorProperty(pError, WS_ERROR_PROPERTY_STRING_COUNT, &errorCount, sizeof(errorCount));
        if (SUCCEEDED(hr)) {
              for (ULONG i = 0; i < errorCount; i++) {
                    WS_STRING errorString;
                    hr = WsGetErrorString(pError, i, &errorString);
                    if (SUCCEEDED(hr))
                        wcout << wstring(errorString.chars, errorString.chars + errorString.length) << endl;
              }
          }
     }
    if (FAILED(hr))
         cout << "Failed to get additional error information, hr=0x" << hex << hr << endl;
}

Кстати, примеры использования WWS можно найти в каталоге C:\Program Files\Microsoft SDKs\Windows\v7.0\Samples\Web\WWSAPI.

Вопросов к этой штуке гораздо больше, чем ответов. Многое непонятно. Примеров и документации - копейки. Скажем, текущая версия wsutil.exe не генерирует fault-контракты, а как прочитать обобщенную информацию об ошибке - непонятно.

Copyright 2007-2011 Chabster