Архів теґу: программирование

Жизнь разработчика в картинках

Жизнь программиста-разработчика в картинках и сценах.

1. Когда я берусь писать код без спецификации

жизнь разработчика в картинках. Программирование без спецификации

2. Когда демонстрируешь окончательно исправленный баг

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

Перечисление сетевых интерфейсов

перечисление сетевых интерфейсов В процессе работы твоей программы нередко надо получить список сетевых адресов доступных на данном компьютере, что бы в дальнейшем этот список использовать для своих задач.
Способов как это реализовать существует несколько – и наиболее распространенный – это использовать API операционной системы. Этого вполне хватит за глаза для большинства задач. Правда есть одна проблема – операционных систем много, и Windows – всего лишь одна из них. Есть еще и, так называемое семейство *nix-подобных систем, к которым относится Linux, MacOS и еще множество других. А хороший программист (а ты ведь хороший программист, не так ли) должен учитывать такие нюансы.
Но на самом деле ничего страшного в этом нет. Во первых, есть языки (например Java, Perl, PHP, Python etc), которым вообще не важна  ОС – главное что бы, была соответствующая виртуальная машина или интерпретатор. Но об этом позже. Будет настроение – я уделю этим языкам отдельную статью, в связи с тем что это совершенно другая идеология и методы. Продовжувати читання Перечисление сетевых интерфейсов

[Qt] QListView – как реализовать множественный выбор.

Компонент, о котором пойдет в этой статье, используется часто в самых различных ситуациях. И это в принципе не удивительно, QListView во первых позволяет удобно отображать самые разные типы данных, во вторых – в полной мере реализует принцип Model-View (модель-представление).
Но начинающих часто может Продовжувати читання [Qt] QListView – как реализовать множественный выбор.

Использование DllEntryPoint

В данной статье я хотел бы рассмотреть два вопроса – во первых, рассмотреть пример использования точки входа библиотеки (DllEntryPoint), во вторых – продемонстрировать один из способов, как определить версию файла библиотеки из ее самой. Собственно определение версии – это задача достаточно частная – на самом деле используя подобную технологию можно например маппить в память образ длл, модифицировать и… ну впрочем ограничимся получением версии.
И так начнем с точки входа (Dll Entry Point). Хочу обратить внимание, что я рассматриваю сейчас только случай когда загрузка библиотеки происходит динамически, если вам нужна статическия линковка – поэкспериментируйте самостоятельно.
Точка входа (DllEntryPoint) очень удобный иструмент для настройки загрузки и выгрузки вашей библиотеки. Функция точки входа вызывается при каждой загрузке и выгрузке библиотеки и получает три параметра – дескриптор библиотеки (HINSTANCE), флаг причины вызова(DWORD fwdreason) и детализация вызова (LPVOID lpvReserved). Хочу отметить, что если вы не используете VC-стиль для dll, то наименование и типы могут немного отличаться.
Как это использовать? Дескриптор библиотеки может быть использован при вызове различных функций – например той же функции получения версии файла.
Флаг загрузки может принимать следующие значения:

DLL_PROCESS_ATTACH При присоединении к адресному пространству текущего процесса, в результате его запуска или вызова функции LoadLibrary
DLL_THREAD_ATTACH Данный процесс создает новый поток
DLL_PROCESS_DETACH Завершение процесса либо вызов FreeLibrary
DLL_THREAD_DETACH Завершение потока

Параметр lpvReserved позволяет определить каким образом загружена библиотека – статически или динамически. Если параметр имеет значение отличное от NULL – библиотека загружена статически, если же NULL – то динамически (с использованием LoadLibrary/FreeLibrary).
Как это использовать? В качестве примера я приведу код, который позволяет получить номер версии библиотеки и вывести его в заголовке модального окна. Для этого вы должны создать новый проект типа DllWizard, Source Type – C++, Use VCL, VC++Style Dll. В проект добавьте юнит (File/New/Unit), сохраните его под названием loadforms.cpp. Так же добавьте форму, дайте ей название fmMain, файл сохраните как main.cpp. Из файла с DllEntryPoin можете прочесть и удалить обширный комментарий и сохранить файл как maindll.cpp, а сам проект – так как нравится вам – например versiontest. В принципе наименования файлов могут быть такими как нравится вам, в коде я буду придерживаться указанной схемы. В прикрепленном файле вы найдете исходные коды проекта.
Для получения версии файла используется функция, получающая в качестве параметра путь к файлу библиотеки и ссылку на строку, куда нужно записать результат. Код функции:
[code]
void FileVersion(char* file,String &version){

VS_FIXEDFILEINFO pvsf;
DWORD dwHandle;
DWORD cchver;
BOOL bret;
cchver = GetFileVersionInfoSize( file, &dwHandle );
if( cchver != 0 )
{
char* pver = new char[ cchver ];
bret = GetFileVersionInfo( file, dwHandle, cchver, pver );
if( bret )
{
UINT uLen;
void *pbuf;
bret = VerQueryValue( pver, “\\”, &pbuf, &uLen );
if( bret )
{
memcpy( &pvsf, pbuf, sizeof( VS_FIXEDFILEINFO ) );
char* fileVersion = new char[ cchver ];

sprintf( fileVersion,
“%01.1d.%01.1d.%01.1d.%01.1d”,
HIWORD( pvsf.dwFileVersionMS ),
LOWORD( pvsf.dwFileVersionMS ),
HIWORD( pvsf.dwFileVersionLS ),
LOWORD( pvsf.dwFileVersionLS ) );
version = (String)fileVersion;
delete [] fileVersion;
}
}
delete[] pver;
}
}

[/code]
Обратите внимание на точку входа:
[code]
//Глобальная переменная для имени библиотеки
char *VersionInfo = new char[512];
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved)
{
switch(fwdreason){
case DLL_PROCESS_ATTACH:
{
//Библиотека загружена через LoadLibrary?
if(lpvReserved == NULL){
//Получаем имя модуля
GetModuleFileName(hinstDLL,VersionInfo,512);

}
break;
}

case DLL_PROCESS_DETACH:
{
if(lpvReserved == NULL)
//Если вызывана FreeLibrary – очищаем память и выходим
delete[] VersionInfo;
}
}

return 1;
}

[/code]

И собственно код из модуля loadforms
[code]
//loadforms.h

#ifndef loadformsH
#define loadformsH
//—————————————————————————
#include

//—————————————————————————
extern “C” __declspec(dllexport) HWND ShowDllForm();

#endif

//loadforms.cpp
#pragma hdrstop

#include “loadforms.h”
#include “main.h”
#include

extern char *VersionInfo;

void FileVersion(char* file,String &version);
typedef DWORD(__import *pGetFileVersionInfoSize)(LPCTSTR lptstrFilename,LPDWORD lpdwHandle);
typedef DWORD(__import *pGetFileVersionInfo)(LPCTSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData);
typedef DWORD(__import *pVerQueryValue)(LPCVOID pBlock,LPCTSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen);

pGetFileVersionInfoSize fGetFileVersionInfoSize;
pGetFileVersionInfo fGetFileVersionInfo;
pVerQueryValue fVerQueryValue;

void FileVersion(char* file,String &version){

VS_FIXEDFILEINFO pvsf;
DWORD dwHandle;
DWORD cchver;
BOOL bret;
cchver = GetFileVersionInfoSize( file, &dwHandle );
if( cchver != 0 )
{
char* pver = new char[ cchver ];
bret = GetFileVersionInfo( file, dwHandle, cchver, pver );
if( bret )
{
UINT uLen;
void *pbuf;
bret = VerQueryValue( pver, “\\”, &pbuf, &uLen );
if( bret )
{
memcpy( &pvsf, pbuf, sizeof( VS_FIXEDFILEINFO ) );
char* fileVersion = new char[ cchver ];

sprintf( fileVersion,
“%01.1d.%01.1d.%01.1d.%01.1d”,
HIWORD( pvsf.dwFileVersionMS ),
LOWORD( pvsf.dwFileVersionMS ),
HIWORD( pvsf.dwFileVersionLS ),
LOWORD( pvsf.dwFileVersionLS ) );
version = (String)fileVersion;
delete [] fileVersion;
}
}
delete[] pver;
}
}

//—————————————————————————

HWND ShowDllForm()
{
fmMain = new TfmMain(Application);
String versioninfo;
FileVersion(VersionInfo,versioninfo);
fmMain->Caption = “???? ver.” + versioninfo;
fmMain->ShowModal();
delete fmMain;
return NULL;
}

#pragma package(smart_init)

//—————————————————————————

[/code]
На сегодня все.
При перепечатке ссылка на ресурс обязательна.
Обсуждение статьи на форуме

Загрузка рисунков в БД

В процессе работы, достаточно часто возникает ситуация, когда работать приходится не только со стандартными типами данных в базе, но и с изображениями, звуками и другими неструктурированными объектами. При этом можно выделить два основных подхода к хранению подобной информации: 1. В БД хранится только путь к файлу, сам файл хранится на жестком диске. 2. Весь объект хранится в БД в сециальном поле с типом blob
В ряде серверов БД, например Micro$oft SQL 2008 появилась возможность объединить эти подходы, отчасти устранив ряд недостатков первого и второго. Но как обычно у гибридов, решив несколько старых проблем, приобретаем несколько новых. Впрочем речь не об этом.
В этой статье я хотел бы еще раз рассмотреть тему сохранения и извлечения неструктурированной информации на примере сервера БД Firebird и Borland Builder C++ 6. Что бы не усложнять материал, я буду рассматривать работу с рисунками (точнее фотографиями) в формате bmp и jpeg. И затем расскажу как можно расширить приведенную схему.
Итак для работы на нужно создать таблицу, которая содержит идентификатор и связанное с ним изображение. Делает это следующий скрипт:
[code]
CREATE TABLE PEOPLE_PHOTOS (
PEOPLE_ID INTEGER NOT NULL,
PEOPLE_PHOTO BLOB SUB_TYPE 0 SEGMENT SIZE 80 NOT NULL
);
[/code]
Для операции вставки (модификации) служит хранимая процедура:
[code]
CREATE OR ALTER PROCEDURE PEOPLE_PHOTO_INS (
people_id integer,
people_photo blob sub_type 0 segment size 80)
as
declare variable tmp_count integer = 0;
begin
/* Procedure Text */
select count(*) from people_photos where people_id = :people_id into :tmp_count;
if (:tmp_count = 1) then
begin
update people_photos set
people_photo = :people_photo where people_id = :people_id;
end
else if (:tmp_count = 0) then
begin
insert into people_photos (people_id, people_photo) values (:people_id, :people_photo);
end

suspend;
end

[/code]
Для выборки
[code]
CREATE OR ALTER PROCEDURE PEOPLE_PHOTO_SEL (
people_id integer)
returns (
people_photo blob sub_type 0 segment size 80)
as
begin
/* Procedure Text */
select people_photo from people_photos where people_id = :people_id into :people_photo;
suspend;
end

[/code]
Добавлению изображения в базу на стороне клиента служит следующий код:
[code]
//Заносим в параметр идентификатор
dmMain->fibPhotoIns->ParamByName(“people_id”)->Value = PeopleId;
TMemoryStream *pMS = new TMemoryStream;
Graphics::TBitmap *tmpBitmap = new Graphics::TBitmap;
TJPEGImage *tmpImg = new TJPEGImage();
try{
//Загружаем изображение из файла и сохраняем его в поток
//если это JPEG
tmpImg->LoadFromFile(opOpen->FileName);
tmpImg->SaveToStream(pMS);

}catch(…){
//если нет – то обрабатываем исключение и загружаем битмеп
tmpBitmap->LoadFromFile(opOpen->FileName);
tmpBitmap->SaveToStream(pMS);

}
//Загружаем из потока в параметр и вызываем процедуру
dmMain->fibPhotoIns->ParamByName(“people_photo”)->LoadFromStream(pMS);
dmMain->fibPhotoIns->ExecProc();
delete pMS;
delete tmpBitmap;
delete tmpImg;
[/code]
Соотвественно получение изображения из базы в компонент TImage
[code]
imPhoto->Picture->Bitmap->CleanupInstance();
dmMain->fibPhoto->ParamByName(“people_id”)->Value = tmp;
dmMain->fibPhoto->Active = true;
TMemoryStream *pMS = (TMemoryStream*)dmMain->fibPhoto->CreateBlobStream(dmMain->fibPhoto->FieldByName(“people_photo”),bmRead);
if(!pMS->Size){
dmMain->fibPhoto->Active = false;
return;
}
TJPEGImage *tmpImage = new TJPEGImage();
Graphics::TBitmap *tmpBitmap = new Graphics::TBitmap;

try{
pMS->Position = 0;
tmpImage->LoadFromStream(pMS);
imPhoto->Picture->Bitmap->Assign(tmpImage);

}
catch(…){
pMS->Position = 0;
tmpBitmap->LoadFromStream(pMS);
imPhoto->Picture->Bitmap->Assign(tmpBitmap);

}
delete pMS;
delete tmpImage;
delete tmpBitmap;
dmMain->fibPhoto->Active = false;
[/code]
Обращаю ваше внимание – не забывайте устанавливать позицию потока в 0. Если вы получаете ошибку “JPEG error #52” – значит либо вы забыли это сделать, либо ваш файл не JPEG.
Если в работе вам надо использовать более чем два типа файлов, то генерация исключений будет достаточно накладным решением. В таком случае нужно дополнительно вводить поле типа файла и обрабатывать его, оставляя исключения только для ошибок, либо же пытаться распознавать тип файла по сигнатуре.

Обсудить статью на форуме

Как перенести мою программу на другой компьютер? (С++Builder)

Способ первый
1. Открываете меню Project/Options
2. На вкладке Compiler устанавливаете Release
3. На вкладке Packages убираете флажок “Build with runtime packages”
4. На вкладке Linker убираете Use Dynamic RTL
5. Перекомпилируете проект. Продовжувати читання Как перенести мою программу на другой компьютер? (С++Builder)