Возникла необходимость заюзать winapi-шную функцию в приложении Windows Forms на C++
Я потратил около шести часов, чтобы найти решение, потому что просто так написать
SendMessage(Handle, WM_CLOSE, 0, 0);
не достаточно. А интуицией догадаться может только экстрасенс.
Короче. В файл stdafx.h после тудушечки добавляем инклюд:
// TODO: Установите здесь ссылки на дополнительные заголовки...
#include "windows.h"
В свойствах проекта идем в Свойства конфигурации – Компоновщик – Ввод, щелкаем по свойству Дополнительные зависимости (у правильных пацанов это называется Linker – Input – Additional dependencies) и выбираем из раскрывающегося списка <наследовать от родителя или от свойств проекта по умолчанию>. Возможно, придется выбрать пункт <Изменить...> и поставить там галку:

И только теперь мы можем вызывать тот же SendMessage(), но с обязательными предшествующими двойными двоеточиями и преобразованием численного значения указателя к структуре HWND. Вот так:
::SendMessage((HWND)this->Handle.ToInt32(), WM_SYSCOMMAND, SC_MONITORPOWER, 2);
Ура! И главное совершенно очевидно, особенно с настройкой проекта.
При копировании объемных файлов функцией CopyFileEx() [1] возможно сообщать пользователю о прогрессе выполнения операции, при помощи callback-функции (обратного вызова). Например, посредством прогрессбара (полоски загрузки).

Помимо вызова функции CopyFileEx() необходимо написать реализацию колбэк-функции. Допустим, что на форме Form1 у нас есть компонент ProgressBar1, в котором мы и планируем отображать прогресс копирования, тогда реализация выглядит следующим образом:
DWORD CALLBACK ProgressRoutine(
LARGE_INTEGER TotalFileSize,
LARGE_INTEGER TotalBytesTransferred,
LARGE_INTEGER StreamSize,
LARGE_INTEGER StreamBytesTransferred,
DWORD dwStreamNumber,
DWORD dwCallbackReason,
HANDLE hSourceFile,
HANDLE hDestinationFile,
LPVOID lpData
)
{
// изменяем тукущую позицию
Form1->ProgressBar1->Position =
Form1->ProgressBar1->Max * TotalBytesTransferred.QuadPart
/ TotalFileSize.QuadPart;
return PROGRESS_CONTINUE;
}
Теперь при вызове функции CopyFileEx() нам достаточно лишь передать ей имя колбэк-функции.
// здесь храним пути к исходному файлу и месту назначения копирования
const char *FileFrom = ("c:\\somewhere\\file.txt").c_str();
const char *FileTo = ("\\server\\pub\\pepyaka.ololo").c_str();
// включаем обработку сообщений для того, чтобы видеть изменения прогрессбара
Application->ProcessMessages();
// копируем с флагом защиты от перезаписи
bool copied = CopyFileEx(FileFrom, FileTo, ProgressRoutine,
NULL, 0, COPY_FILE_FAIL_IF_EXISTS);
// по значению переменной copied можно судить об успехе операции
if (copied == true) ShowMessage("Всё отменно скопировалось");
При возникновении ошибок поможет функция GetLastError() [2], которая вернет код подседней ошибки WINAPI. Значение кода поможет понять этот список.
Задача:
При наведении мыши на определенный контрол, выводить подсказку о его назначении в строке состояния (StatusBar).
Решение:
С первого взгляда на проблему хочется тут же взяться и начать писать обработчики событий OnMouseEnter и OnMouseLeave вроде этих:
void __fastcall TForm::SomeControlMouseEnter(TObject *Sender)
{
// Выводим сообщение в строку состояния
StatusBar1->SimpleText = "Вы навели мышь на вот этот контрол";
}
//---------------------------------------------------------------------------
void __fastcall TAddNewLocationForm::BInsertMouseLeave(TObject *Sender)
{
// Очищаем строку состояния
StatusBar1->SimpleText = "";
}
Конечно, это вполне работоспособный код, но если обработать таким образом нужно много элементов на форме, сразу задумываешься: а нет ли способа покороче да поуниверсальнее.
Мы может воспользоваться компонентом ApplicationEvents (группа Additional в BDS 2006), отвечающим за обработку событий приложения. Нам пригодится событие OnHint.
Оно возникает, когда курсор мыши перемещается над компонентом или элементом меню. При этом значение свойства Hint текущего компонента заносится в одноименное свойство приложения: Application->Hint.
Cначала задайте текст подсказок в свойстве Hint требуемых контролов. Дальше пишем простой обработчик события OnHint:
void __fastcall TForm::ApplicationEvents1Hint(TObject *Sender)
{
StatusBar1->SimpleText = Application->Hint;
}
Собственно, всё. Теперь при наведении мыши на компоненты, в статусной строке будут возникать подсказки, соответствующие данному компоненту.
Задача решена.
Если вы когда-нибудь пользовались компонентом TRadioGroup, то, пожалуй, знаете, насколько он удобен при динамическом формировании списка переключателей. Всего-то и нужно, что добавлять и удалять строки списка типа TStringList
RadioGroup1->Items->Clear(); // удаление всех элементов
RadioGroup1->Items->Add("Первая точка"); // добавление новых
RadioGroup1->Items->Add("Вторая точка");
Ну и конечно же, вы знаете, что определить выбранную точку можно по значению свойства ItemIndex. Нумерация начинается с нуля, как заведено.
А вот вопрос: как получить доступ к свойствам отдельных элементов, сперва вызывает проблемы. На самом деле всё просто, нужно использовать массив Controls. Вот доступ к выделенному элементу:
int idx = RadioGroup1->ItemIndex; // запоминаем индекс
RadioGroup1->Controls[idx]->Enabled = false; // делаем недоступным
RadioGroup1->Controls[idx]->Visible = false; // скрываем
Ну и так далее.
Для обхода всех элементов, воспользуемся циклом, взяв количество элементов из свойства ControlCount:
for (int i = 0; i < RadioGroup1->ControlCount; i++)
RadioGroup1->Controls[i]->Caption = IntToStr(i) + "-й элемент";
В результате все элементы списка будут переименованы.
Так же не забывайте про методы BeginUpdate() и EndUpdate(), которые позволят избежать мерцания списка при изменении состава элементов.
RadioGroup1->Items->BeginUpdate(); // отключаем обновление элементов
for (int i = 0; i < RadioGroup1->ControlCount; i++)
RadioGroup1->Controls[i]->Caption += "(" + IntToStr(i) + ")";
RadioGroup1->Items->EndUpdate(); // включаем обратно
Сканировать определенную папку и получить имена всех или определенных файлов вам позволит следующий код:
int ires;
TSearchRec SR;
AnsiString ext; // Расширение.
// Очищаем список файлов в компоненте ListBox
List->Clear();
// Задаем параметры поиска: где искать и что.
ires = FindFirst("C:\\*.*", faAnyFile | faArchive, SR);
while (ires == 0)
{
// Если нужны только определенные типы файлов,
// то ведем проверку по расширению.
ext = ExtractFileExt(SR.Name);
if ((ext == ".bmp") || (ext == ".jpg")) {
// Заносим имена файлов в список.
List->Items->Add(SR.Name);
}
// Переход к следующему файлу к каталоге.
ires = FindNext(SR);
}
// Поиск завершен.
FindClose(SR);
Основан на функциях Find.
int FindFirst (AnsiString Path, int Attr, TSearchRec & F);
Находит первый файл с заданными атрибутами в указанном каталоге.
Атрибуты передаются с помощью следующих констант: faReadOnly, faHidden, faSysFile, faVolumeID, faDirectory, faArchive.
В последний аргумент функции заносится результат поиска.
Давольно давно искал место, куда бы сваливать всякие полезные куски кода. Ведь как бывает: сталкиваешься с новой областью в программировании, начинаешь изучать. Находишь решение. И хочется, чтобы это решение не потерялось, чтобы его можно было быстро взять, если понадобиться в следующем проекте.
Сначала хотел создать отдельный сайт, но поленился, и сделал эту рубрику.
Встречайте. Code Chips — «Кусочки кода».
Первая запись про то, как преобразовать картинку jpeg в формат bmp в C++ Builder.
Функция конвертирует файл формата jpeg в bmp.
На входе полное имя файла, возвращает true в случае успешной конвертации.
bool JPEG2BMP(AnsiString FileName)
{
TJPEGImage *jpg = new TJPEGImage;
Graphics::TBitmap *bmp = new Graphics::TBitmap;
bool ok = true; // Маркер хорошего поведения.
try {
jpg->CompressionQuality = 100; // Качество сжатия.
jpg->LoadFromFile(FileName); // Загружаем jpeg.
try {
bmp->Assign(jpg); // Переносим данные в bmp.
bmp->SaveToFile(ChangeFileExt(FileName, ".bmp"));
} catch (...) {
ok = false;
}
} catch (...) {
ok = false;
}
jpg->Free();
bmp->Free();
return ok;
}
Для информирования пользователя об ошибке можно добавить перед return что-то из ряда:
if (!ok)
ShowMessage("Конвертирование не увенчалось успехом");