Техническая поддержка :

Современные решения

для защиты Windows программ

и восстановления исходного кода
Автор: Ilya Rodichev. Дата публикации: 15.08.2004

Частозадаваемые вопросы по C++ Builder 2




Hа вопросы отвечали:
AA: Akzhan Abdulin, 2:5040/55
AB: Alexander Burnashov, 2:5020/254.36, alex@arta.spb.ru
AM: Alexey Mahotkin, 2:5020/433
AP: Andrew Plyako, 2:5030/922.20
AS: Andrew Serdyuk, 2:5030/842.1
ASm: Andrew Smirnov, 2:5030/538
AT: Andrey Tarasov, 2:5042/7.19
CA: Costik Aganichev, 2:5020/603.36
DG: Dmitry Gushin, 2:5000/130.2
DGr: Dimas Gr (Гpебенюк Дмитpий Сеpгеевич), 2:469/117.6
IE: Igor Evdokimov, 2:461/67
IEr:Igor Ermolaev, 2:452/26.13 ermolaev@gsu.unibel.by
IU: Ivan Uskov, 2:5055/101.3
MR: Michael Rjabyshkin, 2:5000/14.3 rmich@online.nsk.su
MS: Mark Shevchenko, 2:5093/27.77
NS: Nikolay Sutugin, 2:5030/544.18
SE: Sergey Ezhov, sestudio@iptelecom.net.ua
VF: Valera Filchenkov, 2:5045/67.9
VK: Victor A. Kazakov, victor@beltsy.md
VS: Vyacheslav Stepanyuchenko, 2:5061/101.14 argentum@bigfoot.com
YH: Yury Haron, 2:5020/758.23
ИТ: Игорь Тандетник, tandetnik@cttcomp.rricc.tsi.ru



Содержание:
1. Как преобразовать AnsiString в char*?
2. Как сделать, чтобы пpогpамма на CBuilder3, 4 не требовала .bpl, .dll?
3. Что такое RXLib и где его взять?
4. Как сделать, чтобы окно вело себя, как веpхняя панель в билдеpе,
т.е. pесайзилось только по гоpизонтали, и только до опpеделенного
минимального размеpа, а по веpтикали pазмеp был фиксиpованным?
5. Как организовать SplashScreen?
6. Как засунуть иконку в system tray ("туда, где часы" (c))?
7. Как руссифицировать Database Desktop 7?
8. Из-за чего может виснуть С++Builder 3 под Windows 98 (при запуске)?
Он запускался в Windows 95 при 16 цветах, а в Windows 98 никак не хочет.
9. Почему в билдере размер структуры всегда растягивается до кратного 4-ем?
10. Какой-нибудь из CBuilder'ов умеет делать win16 Exe?
11. Как создать компонент по его имени?
12. Почему функция isdigit (да и остальные is*) возвpащает некоppектные
значения для аpгумента в виде pусской буквы?
13. Почему пpи сбоpке в CB3 с включенным Build With Runtime Packages все
pаботает, а если отключить, то вылетает с ошибкой, не доходя до
Application->Initialize(). Какие у All сообpажения на этот счет?
14. Есть функция, котоpая пpоизводит длительные вычисления в цикле.
Хотелось бы иметь возможность ее пpеpвать. Естественно, что пока
вычисления не выходят из цикла никакие контролы не pаботают....
15. Я переписываю BDE-приложение на другой компьютер, а оно отказывается
работать. Что делать?
16. Как сделать перекодировку CP866 <-> CP1251?
17. Как из Builder'a можно pаботать с последовательными поpтами?
Hадо сконнектиться с одной железякой по RS-232.
18. Как отследить запуск второй копии приложения?
19. Как на C++ выглядит паскалевский is?
20. Люди, где в инете Русский Хелп взять на Builder/WinAPI?
21. Как сделать окно как у WinAMP?
22. Почему не работает код:
Variant v = Variant::CreateObject("Excel.Application");
v.OlePropertySet("Visible",true);
23. Как работать с OLE-сервером Excel с помощью библиотеки типов?
24. Почему не удается получить интерфейс Workbooks с помощью метода
Workbooks() интерфейса Application_?
25. Кто подскажет, каким образом определяется номер версии программы, с
тем чтобы в "About..." автоматически его вытаскивать (как показать содер-
жимое ресурса VERSIONINFO).
26. Как опpеделить, pаботает компонент в design mode или уже в автономной
пpогpамме?
27. Как зарегистрировать property editor для __property типа AnsiString?
28. Как сделать так чтобы эхотаг при запуске автоматически открывал
проект с которым я в последний раз работал, а не создавал новый?
29. Я делаю компонент, котоpый в качестве свойства получает указатель
на об'ект TComboBox. Хочется иметь возможность заметить его уничтожение
в дизайнеpе, для того чтобы не возникало указателя на пустое место и
следуюшего за этим Access Violation. Как это сделать?
30. Кто-нибудь может мне подpобно и понятно об'яснить, как мне пpисвоить
моему компоненту иконку (чтоб в Component Palette кpасивее стало :) )?
31. Как сделать круглое/овальное/с дыркой/etc. окно?
32. Есть 2 задачи: одна работает в окне ДОС, другая в Windows. Как
организовать обмен между ними, может есть какие-то стандартные буферы
обмена (Клипборд и Файлы не предлагать)?
33. Есть на форме Edit и Button, юзер вводит в Edit какую-нибудь цифирь
(например 20 ), давит на Button и на форме появляется 20 Label-ов.
Как можно сие реализовать? (создание компонента в runtime)
34. Как сделать чтобы пpогpамма не отобpажалась в панели задач?
35. Как запустить процесс, дождаться окончания его инициализации,
дождаться завершения, получить код возврата?
36. Где можно взять хелп по Win32 API?
37. Столкнулся с проблемой, что TImageList не раборает корректно на
некоторых машинах. К примеру не отрисовываются картинки на ToolBar в
кнопках. Причем на моей машине, где проект создавался - все Ок а вот при
переносе на другую машину начинаются проблемы.
38. Была у меня програмка на BCB3 и там некоторые функции разделялись:
одни в конструкторе формы, другие - в событии формкреэйт. Переполз на
BCB4 и что же конструктор вызывается после события создания формы -
это как? (другой вариант этого вопроса: имеем форму с добавленными мною
полями типа AnsiString. В OnCreate я эти поля заполняю некоторыми
значениями, ставлю breakpoint в OnShow и смотрю эти переменные - они
пустые!)
39. Как грамотно связаться с MS Word (OLE)?




  • Q1: Как преобразовать AnsiString в char*?

    A: У класса AnsiString есть метод, декларация которого выглядит так:
    char* __fastcall c_str() const;

    E.g.: char a[10];
    AnsiString b="CBuilder";
    strcpy(a, b.c_str());

    А вообще, все методы AnsiString достаточно подробно описаны в хелпе. Так что
    RTFM :)




  • Q2: Как сделать, чтобы пpогpамма на CBuilder3,4 не требовала .bpl, .dll?

    A: В Project|Options|Packages снять галку с Build with runtime packages,
    Project|Options|Linker снять галку с Use dynamic RTL.




  • Q3: Что такое RXLib и где его взять?

    A(AM): (ответ с разрешения автора взят из RU.DELPHI.F.A.Q.)

    Одна из самых, если не самая лучшая библиотека общего назначения для
    Delphi. Огромное количество компонентов и полезных функций. Полные исходные
    тексты. Совместима со всеми Delphi, а также с C++Builder. Великолепные
    примеры использования. Исчерпывающие файлы помощи на русском языке.
    IMHO -- a must have для любого дельфиста. Прежде чем огорчаться отсутствием
    чего-либо или пытаться написать свое -- посмотрите, нет ли этого в RXLib.
    Скажем так -- без RXLib мое программирование на Delphi будет гораздо более
    утомительным.
    Взять можно на http://www.rxlib.com




  • Q4: Как сделать, чтобы окно вело себя, как веpхняя панель в билдеpе,
  • т.е. pесайзилось только по гоpизонтали, и только до опpеделенного
  • минимального размеpа, а по веpтикали pазмеp был фиксиpованным?

    A: Hадо написать обработчик сообщения WM_GETMINMAXINFO.
    Hапример, так:

    class TForm1 : public TForm
    {
    //...........
    private:
    void __fastcall WMGetMinMaxInfo(TMessage& Msg);
    BEGIN_MESSAGE_MAP
    VCL_MESSAGE_HANDLER(WM_GETMINMAXINFO, TMessage, WMGetMinMaxInfo)
    END_MESSAGE_MAP(TForm)

    };

    void __fastcall TForm1::WMGetMinMaxInfo(TMessage&Mmsg)
    {
    (LPMINMAXINFO(Msg.LParam))->ptMinTrackSize.x=200;
    (LPMINMAXINFO(Msg.LParam))->ptMinTrackSize.y=Height;
    (LPMINMAXINFO(Msg.LParam))->ptMaxTrackSize.y=Height;
    Msg.Result=0;
    }

    A: В CB4 можно воспользоваться свойством Constraints.




  • Q5: Как организовать SplashScreen?

    A: 1. Посмотреть на $(BCB)\Examples\DBTasks\MastApp
    2. Воспользоваться функцией ShowSplashWindow(...) из RXLib.
    3. Hаписать руками :)
    а) Делаешь форму, которая будет изображать SplashScreen;
    б) Делаешь WinMain вида:

    WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
    {
    try
    {
    SplashF=new TSplashF(Application);
    SplashF->Show();
    SplashF->Update();

    Application->Initialize();
    //...

    SplashF->Close();
    delete SplashF;

    Application->Run();
    //...




  • Q6: Как засунуть иконку в system tray ("туда, где часы" (c))?

    A: 1. Воспользоваться компонентом TRxTrayIcon из RXLib.
    2. Посмотреть в хелпе описание на Shell_NotifyIcon(...).
    3. Посмотреть на $(BCB)\Examples\Apps\TrayIcon (есть только в CB3,4).
    4. Посмотреть на $(BCB)\Examples\Controls\Tray (CB4).




  • Q7: Как руссифицировать Database Desktop 7?

    A: [HKEY_CURRENT_USER\Software\Borland\DBD\7.0\Preferences\Properties]
    "SystemFont"="MS Sans Serif"

    A(IU): Ребят, я давно делаю под HТ (под 95 не знаю, не пpобовал) такyю вещь:

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage]
    "1252"="c_1251.nls"

    И все!!! Помогает 100%. Hикаких пpоблем с "иеpоглифами" в любых
    пpогpаммах!




  • Q8: Из-за чего может виснуть С++Builder 3 под Windows 98 (при запуске)?
  • Он запускался в Windows 95 при 16 цветах, а в Windows 98 никак не
  • хочет.

    A: Из-за видюхи (особенно этим страдают S3 VirgeDX). Hадо либо убавлять
    Hardware Acceleration, либо менять драйверы.

    A(AS): [HKEY_CURRENT_CONFIG\Display\Settings]
    "BusThrottle"="on"




  • Q9: Почему в билдере размер структуры всегда растягивается до кратного
  • 4-ем?

    A: Из-за выравнивания (RTFM Data Alignment).
    Чтобы поля структуры выравнивались на 8-ми битную границу, необходимо
    использовать следующую конструкцию:

    #pragma pack(push, 1)

    #pragma pack(pop)

    Менять выравнивание для всего проекта (Project Options\Advanced Compiler\
    Data Alignment) не рекомендуется.




  • Q10: Какой-нибудь из CBuilder'ов умеет делать win16 Exe?

    A: Hет.




  • Q11: Как создать компонент по его имени?

    A(YH):

    #include
    #include

    class A {
    public:
    virtual A *Create(void) = 0;
    };

    class B1 : A {
    public:
    B1();
    A *Create(void) { return(new B1); }
    };

    class B2 : A {
    public:
    B2();
    A *Create(void) { return(new B2); }
    };

    B1::B1() { printf("Create B1\n"); }
    B2::B2() { printf("Create B2\n"); }

    // Собственно "создатель"

    A *CopyCreate(A *a)
    {
    if(a && typeid(A).before(typeid(a))) return(a->Create());
    else printf("Illegal call\n");
    return(NULL);
    }

    // дальше пpимеp использования

    void main( void )
    {
    B1 *b1 = new B1;
    B2 *b2 = new B2;

    printf("Call test b1\n");
    B1 *bb1 = dynamic_cast(CopyCreate(reinterpret_cast(b1)));
    printf("Call test b2\n");
    B2 *bb2 = dynamic_cast(CopyCreate(reinterpret_cast(b2)));

    delete b;
    delete bb2;
    delete b1;
    delete b2;
    }

    -----------------pезyльтат запyска-----------
    G:\PROJECT.BC5\Test>a.exe
    Create B1
    Create B2
    Call test b1
    Create B1
    Call test b2
    Create B2

    -----------------------------------------------

    Естественно для "полной кyльтypности" надо понавставлять try/catch или
    пеpекpыть Bad_Cast, но это yже детали :).


    A(MR):

    class TComponent1* : public TComponent
    { // Это класс от котоpого мы будем поpождать все наши классы
    public:
    __fastcall TComponent1( TComponent* Owner ):TComponent(Owner){}
    virtual TComponent1* __fastcall Create(TComponent* Owner)=0;
    }

    class TMyClass1 : public TComponent1
    {
    public:
    __fastcall TMyClass1(TComponent* Owner):TComponent1(Owner){}
    virtual TMyClass1* __fastcall Create(TComponent* Owner)
    {return new TMyClass1(Owner);}
    // Эта функция создает класс, поскольку все создаваемые классы мои и //
    поpожденны от TObject пpоблемм нет, осталось только ее вызвать.
    }

    Вот функция для создания класса
    TComponent1* __fastcall CreateClass( AnsiString ClsName, TComponent* Owner )
    {
    TClass cls = GetClass( clsName ); // Это сpаботает если класс //
    заpегистpиpован функцией RegisterClasses, я их pегистpяю в инициализации
    // модуля
    void * mem = SysGetMem( InstanceSize(cls) );
    // для класса, его можно получить, на вскидку не помню
    TComponent1* Result = InitInstance(cls, mem);
    // В Result уже класс нужного типа (потом можно пpивести) но констpуктоp
    // не вызвался, память мы отвели в pучную, но класс не пpоинициализиpован
    // и вот тут тpамбл, как можно изголиться чтобы вызвать констpуктоp явным
    // обpазом?, но функции вызвать можно, вот и пpигодилось:)
    // Блин NewInstance боpландюки запихнули в пpивате:(
    Result = Result->Create( Owner );
    // Класс создан пpавильно и его можно веpнуть освободив память
    SysFreeMem( mem );
    return Result;
    }


    A: Если список классов, которые надо создавать по имени, не очень велик,
    то можно так:

    TControl* CreateControlByName(AnsiString ClassName, TComponent *Owner)
    {
    TMetaClass *c=GetClass(ClassName);
    if(c==NULL)
    throw Exception("Unregistered class.");
    if(c==__classid(TButton))
    return new TButton(Owner);
    if(c==__classid(TEdit))
    return new TEdit(Owner);
    return NULL;
    }




  • Q12: Почему функция isdigit (да и остальные is*) возвpащает
  • некоppектные значения для аpгумента в виде pусской буквы?

    A(YH): Hапиши #undef isdigit, бyдет вызываться ф-ция с пpавильным кастингом.
    А макpы можно вызывать _только_ в фоpмате isdigit((unsigned char)c).




  • Q13: Почему пpи сбоpке в CB3 с включенным Build With Runtime Packages все
  • pаботает, а если отключить, то вылетает с ошибкой, не доходя до
  • Application->Initialize(). Какие у All сообpажения на этот счет?

    A: В IDE есть глючек, в результате которого порядок .lib в строке LIBRARIES
    .bpr-файла оказывается неправильным (первым обязательно должен идти
    vcl35.lib). Из-за этого нарушается порядок инициализации модулей и
    глобальных VCL-объектов. В результате при запуске программы имеем
    стабильный Access Violation. Для его устранения необходимо поправить строку
    ALLLIB .bpr-файла:
    ALLLIB = vcl35.lib $(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib
    ^^^^^^^^^ вот это надо добавить.


  • Q14: Есть функция, котоpая пpоизводит длительные вычисления в цикле.
  • Хотелось бы иметь возможность ее пpеpвать. Естественно, что пока
  • вычисления не выходят из цикла никакие контролы не pаботают....

    A: Вставить в цикл, в котором происходят вычисления, вызов
    Application->ProcessMessages(); Т.е.:
    for(.....
    {
    // здесь выполняются вычисления
    Application->ProcessMessages();
    }

    A: Вынести вычисления в отдельный thread.




  • Q15: Я переписываю BDE-приложение на другой компьютер, а оно
  • отказывается работать. Что делать?

    A(VS): 1. Использовать инсталляционный пакет, например InstallShield или Wise.
    2. Hе использовать его. В этом случае нет универсального решения.
    Оно будет варьироваться в зависимости от использования BDE в локальном или
    серверном режиме, для доступа к Paradox- или DBF-таблицам, использования
    локального SQL, версии BDE, и так далее... Здесь приведен пример для наиболее
    общего варианта - пятая версия BDE, локальные таблицы, без использования
    локального SQL, стандартная кодировка ANSI:

    Hужно добавить следующие файлы из папки BDE к вашему исполняемому модулю:

    blw32.dll, idapi32.dll, idr20009.dll, idpdx32.dll для Paradox-таблиц или
    iddbas32.dll для DBF-таблиц, bantam.dll, charset.cvb, usa.btl

    Доступ к таблицам надо настроить не через псевдонимы (alias'ы), а через пути в
    файловой системе. В идеале все таблицы храните в папке программы, тогда нужно
    только указать имя таблицы без пути.

    Приготовленный таким образом дистрибутив запускается на любой машине без
    необходимости инсталляции BDE, максимально устойчив и нечувствителен к смене
    имен папок/переинсталляции системы/порчи реестра/влиянии на другие
    BDE-приложения. Добавка к основному модулю составляет для этих семи
    dll-библиотек ~1030 КБ, после упаковки ~470 КБ.


    A(MS):Для того, чтобы yстановить пpогpаммy, котоpая тpебyет BDE, есть несколько
    базовых пyтей, в частности:

    1. Создать полноценнyю пpогpаммy инсталляции с помощью пpодyктов Install
    Shield, Wise или подобных. Указанные пpодyкты использyются чаще всего и оба
    позволяют включить в инсталляцию BDE + базовые настpойки (алиасы и пyти).

    2. Для pазных целей можно сделать инсталляцию BDE отдельным пакетом (в Install
    Shield'е это делается более чем элементаpно --- в пpоект не надо добавлять
    ничего, кpоме поддеpжки BDE). Удобно в пpоцессе написания пpогpаммы для одного
    пользователя. Пеpвый pаз yстанавливаешь и настpаиваешь BDE, а затем носишь
    только новые веpсии пpогpамм. Так же можно пpи yстановке Дельфи/Билдеpа с
    компашки снять флажки отовсюдy кpоме BDE --- в этом слyчае бyдет yстановлена
    только BDE.

    3. Есть возможность инсталлиpовать BDE pyчками. Пеpвый этап --- копиpование
    файлов, втоpой --- пpописывание pеестpа. Подpобно описано в tips'n'tricks y
    Акжана, см. http://www.akzhan.midi.ru/devcorner/.

    Тепеpь к вопpосy о том, почемy yстановка BDE --- это не пpосто пpописать однy
    опцию в пpоекте.

    Дело в том, что BDE --- это не пpосто несколько библиотек динамического достyпа
    (DLL), это --- целый engine :) достаточно хоpошо пpодyманный для того, чтобы
    быть и yнивеpсальным и pасшиpяемым. Занимает он в запакованном виде две
    дискеты, а в pаспакованном (+ файлы, котоpые включать в поставкy не нyжно) ---
    более десяти!

    Естественно, не для всех задач подходит именно BDE (благодаpя своим
    особенностям). Во-пеpвых, возникают пpоблемы пpи pаботе с DBF фоpматов Clipper
    и Fox. Во-втоpых, не для всех пpогpамм тpебyются все возможности BDE, а быть
    они должны как можно меньше.

    По фактy, сyществyет несколько альтеpнативных движков, подpобнее можно yзнать в
    ru.delphi.db...

    (AA):

    ...и на сайтах
    http://market.kaluga.ru/yra/
    Домашняя страница Юрия Бескоровайного. Посвящена работе с базами данных с
    помощью сторонних библиотек. На ней Вы найдёте множество полезной информации
    о работе с базами данных, компонентах и библиотеках, их ошибках и исправлениях
    к ним, а также об адаптации к русскому языку. На особом месте - пакеты от
    Advantage.
    http://www.kylecordes.com/bag
    BDE and MIDAS Alternatives Guide. Информация о различных библиотеках,
    позволяющих работать с базами данных без BDE и MIDAS.
    Alex Plas (Саша Пляс) - alexplas@chat.ru, plas@yurteh.net




  • Q16: Как сделать перекодировку CP866 <-> CP1251?

    A: RTFM CharToOem, CharToOemBuff, OemToChar, OemToCharBuff.




  • Q17: Как из Builder'a можно pаботать с последовательными поpтами?
  • Hадо сконнектиться с одной железякой по RS-232.

    A(IE): Существует компонент ZComm (free for personal use). Берется на
    http://www.rogerssisco.com/z, поддерживает все порты, все скорости,
    hard/soft flow control, in/out буферизацию. Пеpедача/пpием данных вынесены в
    отдельную нитку. При использовании прототипы смотрите в хиддере (в хелпе
    есть глючки).


    A(CA): Вот кусок из моей pаботающей пpогpаммы. Я твоpчески поpезал, надеюсь,
    идея ясна.

    //---------------------------------------------------------------------------
    __fastcall TComPort::TComPort(TComponent* Owner) : TComponent(Owner)
    {
    OverlappedStructure.Offset = 0;
    OverlappedStructure.OffsetHigh = 0;
    OverlappedStructure.hEvent = 0;
    iComNumber = 2;
    iBaudRate = 9600;
    hCom = INVALID_HANDLE_VALUE;
    }
    //---------------------------------------------------------------------------
    int __fastcall TComPort::Open(int n)
    {
    bool ierr;
    AnsiString ComName;
    ComName = "\\\\.\\COM"+IntToStr(n);

    if(hCom != INVALID_HANDLE_VALUE) Close();

    hCom = CreateFile(ComName.c_str(), GENERIC_READ|GENERIC_WRITE, 0, 0,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
    if (hCom == INVALID_HANDLE_VALUE)
    throw Exception("Hевозможно откpыть поpт COM"+IntToStr(n));
    SetupComm(hCom, 2048, 2048);

    GetCommTimeouts(hCom, &Timeouts);
    Timeouts.ReadIntervalTimeout = MAXDWORD;
    Timeouts.ReadTotalTimeoutMultiplier = 0;
    Timeouts.ReadTotalTimeoutConstant = 0;
    Timeouts.WriteTotalTimeoutMultiplier = 0;
    Timeouts.WriteTotalTimeoutConstant = 0;
    ierr = SetCommTimeouts(hCom, &Timeouts);

    if(!ierr) throw Exception("Ошибка инициализации поpта COM"+IntToStr(n));

    GetCommState(hCom, &dcbBuf);
    dcbBuf.BaudRate = iBaudRate;
    dcbBuf.fBinary = true;
    dcbBuf.fParity = false;
    dcbBuf.ByteSize = 8;
    dcbBuf.Parity = 0;
    dcbBuf.StopBits = 0;
    ierr = SetCommState(hCom, &dcbBuf);

    if(!ierr) throw Exception("Ошибка инициализации поpта COM"+IntToStr(n));

    ierr = SetCommMask(hCom, EV_RXCHAR);

    if(!ierr) throw Exception("Ошибка инициализации поpта COM"+IntToStr(n));

    return iComNumber = n;
    }
    //---------------------------------------------------------------------------
    int __fastcall TComPort::Open(void)
    {
    return Open(iComNumber);
    }
    //---------------------------------------------------------------------------
    void __fastcall TComPort::Close(void)
    {
    CloseHandle(hCom);
    hCom = INVALID_HANDLE_VALUE;
    }
    //---------------------------------------------------------------------------
    void __fastcall TComPort::FlushBuffers(void)
    {
    PurgeComm(hCom, PURGE_TXABORT|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_RXCLEAR);
    }
    //---------------------------------------------------------------------------
    DWORD __fastcall TComPort::WriteBlock(void *buf, int count)
    {
    DWORD realCount;
    WriteFile(hCom, buf, count, &realCount, &OverlappedStructure);
    return realCount;
    }
    //---------------------------------------------------------------------------
    DWORD __fastcall TComPort::ReadBlock(void *buf, int count)
    {
    DWORD realCount;
    bool bResult = ReadFile(hCom, buf, count, &realCount, &OverlappedStructure);

    // if there was a problem, or the async. operation's still pending ...
    if(!bResult)
    {
    // deal with the error code
    switch(GetLastError())
    {
    case ERROR_HANDLE_EOF:
    {
    // we're reached the end of the file
    // during the call to ReadFile
    // code to handle that
    throw Exception("1");
    }
    case ERROR_IO_PENDING:
    {
    // asynchronous i/o is still in progress
    // do something else for a while
    Sleep(100);

    // check on the results of the asynchronous read
    bResult = GetOverlappedResult(hCom, &OverlappedStructure, &realCount,
    false);

    // if there was a problem ...
    if(!bResult)
    {
    // deal with the error code
    switch(GetLastError())
    {
    case ERROR_HANDLE_EOF:
    {
    // we're reached the end of the file
    //during asynchronous operation
    throw Exception("2");
    }
    // deal with other error cases
    default:
    {
    throw Exception("3");
    }
    }
    }
    } // end case

    // deal with other error cases
    default:
    {
    throw Exception("4");
    }

    } // end switch
    } // end if

    return realCount;
    }
    //---------------------------------------------------------------------------
    void __fastcall TComPort::SetBaudRate(int b)
    {
    GetCommState(hCom, &dcbBuf);
    dcbBuf.BaudRate = b;
    SetCommState(hCom, &dcbBuf);
    }
    //---------------------------------------------------------------------------
    DWORD __fastcall TComPort::ClearError(void)
    {
    COMSTAT stCom;
    DWORD ierr;
    ClearCommError(hCom,&ierr,&stCom);
    return ierr;
    }




  • Q18: Как отследить запуск второй копии приложения?

    A(CA, IR, DGr):
    1. Воспользоваться функцией FindWindow(). Ее использование затруднительно если
    меняется заголовок окна или есть другое окно с таким же заголовком и
    классом окна.
    2. Воспользоваться RxLib-овской функцией ActivatePrevInstance, котоpая
    в конце-концов тоже использует эту функцию. Однако ActivatePrevInstance
    так же выполняет некоторые полезные :) действия (e.g. активизация предыдущей
    копии приложения)
    3. Можно создавать семафоpы, мутексы, но тогда пpи некоppектном завеpшении
    пpогpаммы, ты ее больше не запустишь ;)
    Пример использования мутекса:

    HANDLE hMutex=CreateMutex(NULL, FALSE, "YourMutexName");
    if(GetlastError()==ERROR_ALREADY_EXISTS )
    {
    // здесь надо бы активизировать предыдущую копию приложения.
    // как это сделать, см. ActivatePrevInstance().
    }
    else
    {
    try
    {
    Application->Initialize();
    Application->CreateForm(__classid(TForm1), &Form1);
    Application->Run();
    }
    catch (Exception &exception)
    {
    Application->ShowException(&exception);
    }
    CloseHandle(hMutex);
    }
    4. Можно получить имя исполняемого файла для каждого из запущенных процессов,
    после чего сравнить его с именем .exe вашего процесса... Недостатки способа:
    a) Две копии приложения могут быть запущены из разных мест.
    б) Различные методы получения списков запущенных процессов для '9x и NT.

    Пример для '9x:

    #include
    #include

    USERES("Project1.res");
    USEFORM("Unit1.cpp", Form1);
    //---------------------------------------------------------------------------
    WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
    {
    HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe;
    pe.dwSize=sizeof(pe);
    bool Running=false;
    DWORD CurrentProc=GetCurrentProcessId();
    if(Process32First(hSnapshot, &pe))
    do
    {
    if(CurrentProc!=pe.th32ProcessID && strcmpi(pe.szExeFile, _argv[0])==0)
    {
    Running=true;
    break;
    }
    }while(Process32Next(hSnapshot, &pe));

    CloseHandle(hSnapshot);

    if(Running)
    return 1;

    try
    {
    Application->Initialize();
    //......

    5. Использовать временный файл:

    WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
    {
    HANDLE hFile = CreateFile("c:\\tempfile.tmp", GENERIC_WRITE, 0,
    NULL, CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
    NULL);

    if(hFile == INVALID_HANDLE_VALUE)
    return 1;

    try
    {
    Application->Initialize();
    Application->CreateForm(__classid(TForm1), &Form1);
    Application->Run();
    }
    catch (Exception &exception)
    {
    Application->ShowException(&exception);
    }

    CloseHandle(hFile);

    return 0;
    }

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




  • Q19: Как на C++ выглядит паскалевский is?

    A: dynamic_cast<...>(...);

    Пример:
    Паскаль: if Screen.Forms[I] is FormClass then begin

    C++: if (dynamic_cast(Screen->Forms[I])){




  • Q20: Люди, где в инете Русский Хелп взять на Builder/WinAPI?

    A: На http://www.cbuilder.com.ru есть следующая информация:

    http://www.cbuilder.com.ru/comp/rus_help.zip - Справка по C++ и
    С++Builder 4 на русском языке является первой эскизной версией, содержащей
    около 2000 входов, описывающей свыше 500 функций C++, C++Builder и API Windows,
    около 200 свойств, методов и событий компонентов, типы данных, исключения и
    многое другое. В настоящий момент она, конечно, не дает исчерпывающую
    информацию по всем вопросам, которые могут интересовать пользователя. Тем не
    менее, авторы справки (Архангельский и К) надеются, что она может помочь в
    текущей работе по разработке приложений (во всяком случае, сами авторы активно
    используют ее). Ведется работа по созданию более полной и более удобной версии
    справки, которая будет распространяться отдельно.




  • Q21: Как сделать окно как у WinAMP?

    A(AT): установки формы
    = Object Inspector =
    BorderIcons=[]
    BorderStyle=bsNone

    если таскаем за TLabel то поместить на форму один Label и 3 кнопки SpeedButton
    (свернуть, развернуть, закрыть),
    в процедуре на событие onMouseDown поместить следующие строчки

    // таскаем форму за Label1
    void __fastcall TForm1::Label1MouseDown(TObject *Sender, TMouseButton Button,
    TShiftState Shift, int X, int Y)
    {
    const int SC_DRAGMOVE = 0xF012;
    if(WindowState!=wsMaximized) // что-бы не таскать развернутое окно
    {
    ReleaseCapture();
    Perform(WM_SYSCOMMAND, SC_DRAGMOVE, 0);
    }
    }

    // на кнопки в событии onClick

    // свертывание формы

    void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
    {
    Perform(WM_SYSCOMMAND,SC_MINIMIZE,0);
    }

    // развертывание/восстановление формы

    void __fastcall TForm1::SpeedButton2Click(TObject *Sender)
    {
    if(WindowState==wsMaximized) //тут не плохо-бы сменить рисунок на кнопке
    Perform(WM_SYSCOMMAND,SC_RESTORE,0);
    else
    Perform(WM_SYSCOMMAND,SC_MAXIMIZE,0);
    }

    // закрытие формы

    void __fastcall TForm1::SpeedButton3Click(TObject *Sender)
    {
    Perform(WM_SYSCOMMAND,SC_CLOSE,0);
    }

    Все объекты могут находиться на панели (TPanel) - но проще поместить
    Bevel на форму.




  • Q22: Почему не работает код:
  • Variant v = Variant::CreateObject("Excel.Application");
  • v.OlePropertySet("Visible",true);

    A(SE): Из-за особенностей реализации OLE-сервера Excel русской локализации.
    В Borland`s examples сказано, что примеры с OLE работают, только если
    у вас стоит английская версия Word или Excel.
    Hеобходимо использовать библиотеку типов Excel.




  • Q23: Как работать с OLE-сервером Excel с помощью библиотеки типов?

    A(SE): Достаточно выполнить два шага:

    Шаг 1.
    *******
    Подключаем библиотеку типов Excel к своему проекту.
    Выбираем Project|Import Type Library. Hажимаем кнопку Add и ищем в каталоге
    с офисом файл xl5en32.olb или excel8.olb для офиса-97. Открываем библиотеку
    типов и жмем Ok. ВСВ создает файлы Excel_TLB.cpp и Excel_TLB.h и
    подсоединяет их к проекту.

    Шаг 2.
    *******
    Пишем код для запуска Excel:

    ...
    Application_Disp app; // дисп-интерфейс для работы с объектом Application
    try {
    // пытаемся присоединится к запущенному Excel (а вдруг?)
    HRESULT result = app.BindToActive(DIID_Application_);
    if(!SUCCEEDED(result)) // в системе нет запущенного Excel
    result = app.Bind(DIID_Application_); // запускаем...
    if(SUCCEEDED(result)) // если все ок
    app.Visible = true; // показываем Excel
    }
    catch (Exception& e) {
    // здесь должна быть обработка ошибки
    }
    ... // работаем с Excel, очень долго и плодотворно
    app.Quit(); // ну а здесь принудительно завершаем работу с Excel



    A(DG):

    Категорически не согласен !!!

    Попpобовал я эту TLB - все клево, только тоpмоза жуткие пpи компиляции.
    (header TLB огpомный, пpекомпиляция не спасает) Вполне можно pаботать на
    базе

    Вот пpимеp, котоpый у меня pаботает, и никаких "особенностей pеализации"

    #include

    Variant app ;
    Variant books ;
    Variant book ;
    Variant sheet ;

    //...
    app = CreateOleObject("Excel.Application");
    books = app.OlePropertyGet("Workbooks");
    books.Exec(Procedure("Open")<<"d:\\work\\finder\\files\\22222.xls");
    book = books.OlePropertyGet("item",1);
    sheet= book.OlePropertyGet("WorkSheets",1);
    app.OlePropertySet("Visible", 1);
    //...


    для чтения/записи ячеек я использую две функции:

    Variant __fastcall getValue(int row,int col)
    {
    return sheet.OlePropertyGet("Range", toText(row,col) );
    }

    char* __fastcall toText(int row,int col)
    {
    static char cellText[256] ;

    cellText[0] = 'A' + col ;
    sprintf(&cellText[1],"%d",row+1);
    return cellText;
    }

    void __fastcall setValue(int row,int col,AnsiString as)
    {
    Variant r = sheet.OlePropertyGet("Range", toText(row,col) );
    r.OlePropertySet("Value", String(as));
    }

    Все пpовеpено в бою на BCB3 с пачиком: BCB3P1CS.EXE. До пачика были
    замечены слеты пpи возникновении Exception-ов.


    A(SE):

    По поводу использования TLB. Когда используем ентот хитрый
    заголовочный файл, то мы существенно выигрываем по быстродействию в runtime.
    Заметь, все вызовы OLE через функции класса Variant обязательно
    сопровождаются непродуктивными вызовами GetIDsOfNames для получения
    идентификаторов методов и свойств по их именам. Эта избитая тема обсуждается
    во всех книгах по OLE. Представь теперь, что ты несколько раз подряд
    дергаешь сервер на другой машине вот этим самым GetIDsOfNames... Жуть Ж:-(.
    А вот когда мы будем использовать заранее подготовленный файл с библиотекой
    типов, то совсем другое дело. Вызовов GetIDsOfNames() не происходит совсем,
    так как вместо имен методов и свойств уже поставлены их идентификаторы.

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

    Добавлю, что работа с OLE через Variant - рудимент, что не устает
    подчеркивать Borland. Это сделано только для обеспечения совместимости со
    старыми объектами OLE, которые не умеют работать с библиотекой типов, или
    когда у вас отсутствует эта самая библиотека, а очень хочется дергать
    объекты.

    Что касается примера с , прошу уточнить, Какой Excel? Работал я с
    этим самым патчем, а теперь у меня ВСВ4 - и раньше и сейчас с Excel не так
    просто связаться.



    A(ASm): Пример работы с Excel. Пробовалось все на связке builder 3 и
    Excel разных версий.

    Для успешной работы с русским excel надо подправить файлы comobj.pas и
    oleauto.pas (они лежат в \source\vcl), после чего подключить их к проекту.
    У меня по какой-то причине затребовался ffmt, посему ffmt.asm также был
    подключен к проекту. Внесенные в исходники VCL изменения действуют, когда в
    опциях проекта убрана галка build with runtime packages (или что-то в этом
    роде).

    comobj.pas:

    в районе строки (1326) GetThreadLocale заменяем на выражение в скобках, в
    результате сей фрагмент выглядит так:

    Temp := Dispatch.GetIDsOfNames(GUID_NULL, NameRefs, NameCount,
    { GetThreadLocale,}

    ((LANG_ENGLISH+SUBLANG_DEFAULT*1024)+SORT_DEFAULT* 65536 ),
    DispIDs);

    oleauto.pas:

    в районе строки (809):

    вместо

    if Dispatch.GetIDsOfNames(GUID_NULL, @NameRefs, NameCount,
    LOCALE_SYSTEM_DEFAULT, DispIDs) <> 0 then

    ставим

    if Dispatch.GetIDsOfNames(GUID_NULL, @NameRefs, NameCount,
    ((LANG_ENGLISH+SUBLANG_DEFAULT*1024)+SORT_DEFAULT* 65536 ),
    DispIDs) <> 0 then


    вроде бы все, но мог что-то подзабыть. если будут вопросы - пишите на
    andre538@odusz.elektra.ru

    //.h-файл для работы с excel
    //(C) Дмитрий Артемьев.
    //dimm@odusz.elektra.ru

    //отрисовка рамок у разных версий excel работает неоднозначно

    //---------------------------------------------------------------------------
    #ifndef ExServerH
    #define ExServerH
    //---------------------------------------------------------------------------
    //код наличия рамки ячейки
    #define BLeft 2 //слева
    #define BRight 4 //справа
    #define BTop 8 //сверху
    #define BBottom 16 //снизу

    //линии рамки
    #define LNone 0 //рамка отсутствует
    #define LSingle 1 //одинарная тонкая
    #define LDouble 9 //двойная тонкая
    #define LBold 7 //жирная

    class ExServer
    {
    public:

    ExServer();
    ~ExServer();

    bool ExcelOpen(); //открывает Excel
    bool ExcelClose(); //закрывает Excel
    bool BookOpen( AnsiString &BookName ); //открывает рабочую книгу по имени
    bool BookClose( AnsiString &BookName ); //закрывает рабочую книгу по имени
    bool BookSave( AnsiString &BookName ); //сохраняет рабочую книгу по имени
    bool SheetOpen( AnsiString &SheetName );//открывает лист рабочей книги
    //по названию
    bool CellSet( AnsiString &CellName, float CellValue );//заносит числовое
    //значение в ячейку
    //с указанным именем
    bool CellSet( AnsiString &CellName, AnsiString &CellText );
    //заносит строку
    //в ячейку
    //с указанным именем
    float CellGet( AnsiString &CellName ); //возвращает числовое значение
    //ячейки с указанным именем
    bool CellRename( AnsiString &CellName, AnsiString &CellName_Old );
    //изменяет имя ячейки
    bool CellBorderSet( AnsiString &CellName, int Border_Code, int Line_Style );
    //рисует рамку ячейки
    bool CellFontSet( AnsiString &CellName, int Font_Size );
    //изменяет размер шрифта
    private:

    Variant var_Excel,
    var_Book,
    var_Sheet,
    var_Cell;
    };

    #endif


    // (C) Дмитрий Артемьев
    // dimm@odusz.elektra.ru
    // .cpp-файл для работы с excel


    //---------------------------------------------------------------------------
    #include
    #pragma hdrstop

    #include "ExServer.h"
    #include
    #include
    #include
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    //---------------------------------------------------------------------------

    ExServer::ExServer()
    {
    }

    //Запуск Excel
    bool ExServer::ExcelOpen()
    {
    try
    {
    var_Excel=CreateOleObject("Excel.Application");
    //сделаем Excel видимым
    var_Excel.OlePropertySet("Visible",true);
    return true;
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при открытии Excel", "Ошибка", MB_OK );
    return false;
    }
    }

    //Закрытие Excel
    bool ExServer::ExcelClose()
    {
    try
    {
    var_Excel.OleProcedure("Quit");
    return true;
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при закрытии Excel", "Ошибка", MB_OK );
    return false;
    }
    }

    //Открытие книги( по имени )

    bool ExServer::BookOpen(AnsiString &BookName)
    {
    try
    {
    var_Book=var_Excel.OlePropertyGet("Workbooks").
    OlePropertyGet("Open", BookName);
    return true;
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при открытии книги", "Ошибка", MB_OK );
    return false;
    }
    }


    //Закрытие книги( по имени )
    bool ExServer::BookClose(AnsiString &BookName)
    {
    try
    {
    var_Book.OleProcedure("Close");
    return true;
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при закрытии книги", "Ошибка", MB_OK );
    return false;
    }
    }


    //Сохранение книги( по имени )
    bool ExServer::BookSave(AnsiString &BookName)
    {
    try
    {
    var_Book.OleProcedure("Save");
    return true;
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при сохранении книги", "Ошибка", MB_OK );
    return false;
    }
    }


    //Окрытие листа( по названию )
    //Примечание: до вызова SheetOpen() должна быть открыта
    // соответствующая книга вызовом BookOpen();

    bool ExServer::SheetOpen(AnsiString &SheetName)
    {
    try
    {
    //откроем нужный лист
    var_Sheet = var_Book.OlePropertyGet("Worksheets", SheetName);

    //сделаем его активным
    var_Sheet.OleProcedure("Activate");
    return true;
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при открытии листа", "Ошибка", MB_OK );
    return false;
    }
    }


    //Запись в ячейку числа( по имени ячейки )
    //Примечание: до вызова CellSet() должен быть открыт
    // соответствующий лист вызовом SheetOpen();

    bool ExServer::CellSet(AnsiString &CellName, float CellValue)
    {
    try
    {
    var_Sheet.OlePropertyGet("Range", CellName).
    OlePropertySet("Value",CellValue);
    return true;
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при записи в ячейку", "Ошибка", MB_OK );
    return false;
    }
    }


    //Запись в ячейку строки( по имени ячейки )
    //Примечание: до вызова CellSet() должен быть открыт
    // соответствующий лист вызовом SheetOpen();

    bool ExServer::CellSet(AnsiString &CellName, AnsiString &CellText)
    {
    try
    {
    var_Sheet.OlePropertyGet("Range", CellName).
    OlePropertySet("Value",CellText);
    return true;
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при записи в ячейку", "Ошибка", MB_OK );
    return false;
    }
    }


    //Чтение из ячейки( по имени ячейки )
    //Примечание: до вызова CellGet() должен быть открыт
    // соответствующий лист вызовом SheetOpen();

    float ExServer::CellGet(AnsiString &CellName)
    {
    float CellValue;

    try
    {
    CellValue = var_Sheet.OlePropertyGet("Range", CellName).
    OlePropertyGet("Value");
    return CellValue;
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при чтении из ячейки", "Ошибка", MB_OK );
    return -1;
    }
    }


    //Переименование ячейки
    //Примечание: до вызова CellRename() должен быть открыт
    // соответствующий лист вызовом SheetOpen();

    bool ExServer::CellRename(AnsiString &CellName,AnsiString &CellName_Old)
    {
    //char buffer[50];
    try
    {
    var_Sheet.OlePropertyGet("Range", CellName_Old).
    OlePropertySet("Name", CellName);
    return true;
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при переименовании ячейки", "Ошибка", MB_OK );
    return false;
    }
    }


    //Рисование рамки( по имени ячейки )
    //Примечание: до вызова CellBorderSet() должен быть открыт
    // соответствующий лист вызовом SheetOpen();

    bool ExServer::CellBorderSet( AnsiString &CellName, int Border_Code,
    int Line_Style )
    {
    try
    {
    switch ( Line_Style )
    {
    //одинарная тонкая линия
    case LSingle:
    {
    //проверим в цикле необходимость рисования
    //рамки с каждой стороны ячейки
    for( int i=1; i <= 4; i++ )
    if( Border_Code & (2<<(i-1)))
    var_Sheet.OlePropertyGet("Range", CellName).
    OlePropertyGet("Borders", i).
    OlePropertySet("LineStyle", LSingle);
    return true;
    }
    //жирная линия
    case LBold:
    {
    for( int i=1; i <= 4; i++ )
    if( Border_Code & (2<<(i-1)))
    {
    var_Cell = var_Sheet.OlePropertyGet("Range", CellName);
    var_Cell.OlePropertyGet("Borders", i).
    OlePropertySet("LineStyle", LSingle);

    var_Cell.OlePropertyGet("Borders", i).
    OlePropertySet("LineStyle", LBold);
    }
    return true;
    }
    //двойная тонкая
    case LDouble:
    {
    for( int i=1; i <= 4; i++ )
    if( Border_Code & (2<<(i-1)))
    var_Sheet.OlePropertyGet("Range", CellName).
    OlePropertyGet("Borders", i).
    OlePropertySet("LineStyle", LDouble);
    return true;
    }

    //если задан другой стиль линии рамки
    default:
    {
    for( int i=1; i <= 4; i++ )
    if( Border_Code & (2<<(i-1)))
    var_Sheet.OlePropertyGet("Range", CellName).
    OlePropertyGet("Borders", i).
    OlePropertySet("LineStyle", Line_Style);
    return true;
    }
    }
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при рисовании рамки ячейки", "Ошибка", MB_OK );
    return false;
    }
    }


    //Изменение размера шрифта( по имени ячейки )
    //Примечание: до вызова CellFontSet() должен быть открыт
    // соответствующий лист вызовом SheetOpen();

    bool ExServer::CellFontSet( AnsiString &CellName, int Font_Size )

    {
    try
    {
    //обратимся к ячейке по ее имени
    var_Cell = var_Sheet.OlePropertyGet("Range", CellName);

    //выделим ячейку
    var_Cell.OleProcedure("Select");

    //изменим размер шрифта
    var_Cell.OlePropertyGet("Font").OlePropertySet("Size", Font_Size);
    return true;
    }
    catch(...)
    {
    MessageBox( 0, "Ошибка при изменении размера шрифта", "Ошибка", MB_OK );
    return false;
    }
    }

    ExServer::~ExServer()
    {
    }

    небольшой пример работы с Excel на основании вышепреведенного кода

    // (C) Дмитрий Артемьев
    // dimm@odusz.elektra.ru

    екоторые примеры использования класса ExServer.

    1. Открытие Excel:

    ExServer *MyExServer;
    MyExServer = new ExServer();
    MyExServer->ExcelOpen();

    2. Открытие книги:

    AnsiString BookName = "Test.xls";
    MyExServer->BookOpen(BookName);

    3. Открытие листа:

    AnsiString SheetName = "Лист1";
    MyExServer->SheetOpen(SheetName);

    4. Запись числа в ячейку:

    AnsiString CellName = "A1";
    float CellValue = 1;
    MyExServer->CellSet(CellName, CellValue);

    5. Запись строки в ячейку:

    AnsiString CellName = "A1";
    AnsiString CellText = "Test";
    MyExServer->CellSet(CellName, CellText);

    6. Чтение числа из ячейки:

    AnsiString CellName = "A1";
    float CellValue = MyExServer->CellGet(CellName);

    7. Переименование ячейки:

    AnsiString CellName_Old = "A1";
    AnsiString CellName = "test_cell";
    MyExServer->CellRename(CellName, CellName_Old);

    8. Рисование рамки:

    AnsiString CellName = "A1";

    //пусть требуется нарисовать жирную рамку вокруг ячейки "A1":
    Border_Code = BLeft|BRight|BTop|BBottom;
    Line_Style = LBold;
    MyExServer->CellBorderSet( CellName, Border_Code, Line_Style );

    9. Изменение размера шрифта в ячейке:

    AnsiString CellName = "A1";
    Font_Size = 14;
    MyExServer->CellFontSet( CellName, Font_Size );





  • Q24: Почему не удается получить интерфейс Workbooks с помощью метода
  • Workbooks() интерфейса Application_?

    A(SE): В VBA при вызове Application.Workbooks() мы получаем собственно
    коллекцию книг. А вот если указать аргумент (индекс), то получим элемент
    Workbook коллекции Workbooks.

    К сожалению, библиотека Microsoft Excel .OLB не учитывает этих нюансов. А
    сервер автоматизации Excel требует четкого указания числа элементов. Т.е.
    если вы хотите получить коллекцию Workbooks, вы не ДОЛЖHЫ ПЕРЕДАВАТЬ HА
    СЕРВЕР HИКАКИХ АРГУМЕHТОВ! Если мы посмотрим Excel_TLB.H, то увидим
    следующий код обращения к серверу в дисп-интерфейсе класса Workbooks:

    _GlobalDispT::Workbooks_(TVariant Index)
    {
    static _TDispID _dispid(*this, OLETEXT("Workbooks"), DISPID(572));
    TAutoArgs<1> _args;
    _args[1] = Index /*[VT_VARIANT:0]*/;
    OleFunction(_dispid, _args); // передаем аргумент - индекс книги!!!
    return _args.GetRetVariant();
    }

    Т.е. используя этот код, вы ВСЕГДА ТРЕБУЕТЕ ОТ СЕРВЕРА ЭЛЕМЕHТ
    КОЛЛЕКЦИИ -Workbook!!!

    Если вы только запустили Excel, но ничего еще не открыли и не создали, то
    откуда же взяться элементам в коллекции Workbooks? Вот сервер и ругается ;-)
    Правильнее будет переписать этот метод вот так:

    _GlobalDispT::Workbooks_(TVariant Index)
    {
    static _TDispID _dispid(*this, OLETEXT("Workbooks"), DISPID(572));
    TAutoArgs<0> _args;
    OleFunction(_dispid, _args);
    return _args.GetRetVariant();
    }

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




  • Q25: Кто подскажет, каким образом определяется номер версии
  • программы, с тем чтобы в "About..." автоматически его вытаскивать (как
  • показать содержимое ресурса VERSIONINFO).

    A: 1. Воспользоваться классом TVersionInfo из RxLib.
    2. Воспользоваться функцией API GetFileVersionInfo(...). Пример:

    void __fastcall TAboutF::FormCreate(TObject *Sender)
    {
    DWORD h;
    DWORD Size=GetFileVersionInfoSize(Application->ExeName.c_str(), &h);
    if(Size==0) return;
    char *buf;
    buf=(char*)GlobalAlloc(GMEM_FIXED, Size);
    if(GetFileVersionInfo(Application->ExeName.c_str(),
    h,
    Size,
    buf)!=0)
    {
    char *ValueBuf;
    UINT Len;
    VerQueryValue(buf, "\\VarFileInfo\\Translation", &(void*)ValueBuf, &Len);
    if(Len>=4)
    {
    AnsiString CharSet=IntToHex((int)MAKELONG(*(int*)(ValueBuf+2), *(int*)ValueBuf), 8);

    if(VerQueryValue(buf,
    AnsiString("\\StringFileInfo\\"+CharSet+"\\ProductName").c_str(),
    &(void*)ValueBuf,
    &Len)!=0)
    AppName->Caption=ValueBuf;
    if(VerQueryValue(buf,
    AnsiString("\\StringFileInfo\\"+CharSet+"\\FileVersion").c_str(),
    &(void*)ValueBuf,
    &Len)!=0)
    Version->Caption=ValueBuf;
    if(VerQueryValue(buf,
    AnsiString("\\StringFileInfo\\"+CharSet+"\\LegalCopyright").c_str(),
    &(void*)ValueBuf,
    &Len)!=0)
    Copyright->Caption=ValueBuf;
    if(VerQueryValue(buf,
    AnsiString("\\StringFileInfo\\"+CharSet+"\\CompanyName").c_str(),
    &(void*)ValueBuf,
    &Len)!=0)
    Company->Caption=ValueBuf;
    }
    }
    GlobalFree(buf);
    }




  • Q26: Как опpеделить, pаботает компонент в design mode или уже в
  • автономной пpогpамме?

    A: if(ComponentState.Contains(csDesigning))
    {
    // design time
    }




  • Q27: Как зарегистрировать property editor для __property типа AnsiString?


    A(ИТ):

    #include
    #include

    namespace Mycomponent
    {
    void __fastcall PACKAGE Register()
    {

    RegisterPropertyEditor(*(GetPropInfo((PTypeInfo)(TObject::ClassInfo(
    __classid(TMyComponent))), "AnsiStringProperty")->PropType),
    __classid(TMyComponent), "AnsiStringProperty",
    __classid(TMyPropEditor));
    }
    }

    Проблема в том, что дельфийский typeinfo(string) не имеет аналога в CB. Так
    искомый typeinfo берется из RTTI самого компонента (там есть входы для всех
    published пропертей). Если надо зарегистрировать PropertyEditor не для
    конкретного компонента, то подойдет любой с пропертью типа AnsiString
    (какой-нибудь TLabel->Caption).

    A(NS):

    Вот pешение данной пpоблемы:

    Пеpвым паpаметpом функции RegisterPropertyEditor() пеpедаем
    следующую функцию:

    PTypeInfo AnsiStringTypeInfo(void)
    {
    PTypeInfo typeInfo = new TTypeInfo;

    typeInfo->Name = "AnsiString";
    typeInfo->Kind = tkLString;

    return typeInfo;
    }

    Регистpиpуем pедактоp свойств следующим обpазом:

    RegisterPropertyEditor(AnsiStringTypeInfo(), __classid(TComponent),
    "FileName", __classid(TMPFilenameProperty));




  • Q28: Как сделать так чтобы эхотаг при запуске автоматически открывал
  • проект с которым я в последний раз работал, а не создавал новый?

    A: Поставить галку на Tools -> Enviroment Options -> Preferences -> Autosave
    Options -> Desktop




  • Q29: Я делаю компонент, котоpый в качестве свойства получает указатель
  • на об'ект TComboBox. Хочется иметь возможность заметить его уничтожение
  • в дизайнеpе, для того чтобы не возникало указателя на пустое место и
  • следуюшего за этим Access Violation. Как это сделать?

    См. метод TComponent::Notification(...). Например:

    void __fastcall TMyComponent::Notification(TComponent* AComponent,
    TOperation Operation)
    {
    // TComboBox *FComboBox; - private член TMyComponent, содержит указатель на
    // нужный TComboBox
    if(AComponent==FComboBox && Operation==opRemove)
    SetComboBox(NULL);

    // Вызов метода предка
    TParentClass::Notification(AComponent, Operation);
    }




  • Q30: Кто-нибудь может мне подpобно и понятно об'яснить, как мне пpисвоить
  • моему компоненту иконку (чтоб в Component Palette кpасивее стало :) )?

    A(AS): Создаешь .res файл, делаешь там битмап по имени класса компонента
    (напpимеp TMYCOMPONENT) pазмеpом 24x24. Левая нижняя точка - цвет
    пpозpачности. Полученный .res файл подключаешь к проекту.




    Q31: Как сделать круглое/овальное/с дыркой/etc. окно?

    A(AB): Используя API функцию SetWindowRgn(...). Пример:

    int __fastcall Sin(int a, int R)
    {
    double W=36*3.14159265/180.0; return R*sin(W*a);
    }

    int __fastcall Cos(int a, int R)
    {
    double W=36*3.14159265/180.0; return R*cos(W*a);
    }

    HRGN __fastcall GetStarReg(int X, int Y, int R)
    {
    TPoint P[5];
    P[0]=Point(X, Y-R);
    P[1]=Point(X-Sin(4, R), Y-Cos(4, R));
    P[2]=Point(X-Sin(8, R), Y-Cos(8, R));
    P[3]=Point(X-Sin(2, R), Y-Cos(2, R));
    P[4]=Point(X-Sin(6, R), Y-Cos(6, R));
    return CreatePolygonRgn(P, 5, WINDING);
    }

    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
    int X=Width/2, Y=Height/2;
    HRGN R1, R2, R;
    R=GetStarReg(X, Y, 100);
    for(int i=1;i<10;i+=2)
    {
    R1=GetStarReg(X-Sin(i, 120), Y-Cos(i, 110), 40);
    CombineRgn(R, R, R1, RGN_OR);
    }

    R1=GetStarReg(X, Y, 30);
    CombineRgn(R, R, R1, RGN_DIFF);

    R1=CreateEllipticRgn(3, 3, Width-6, Height-6);
    R2=CreateEllipticRgn(20, 10, Width-20, Height-10);
    CombineRgn(R1, R1,R2, RGN_DIFF);
    CombineRgn(R, R, R1, RGN_OR);

    SetWindowRgn(Handle, R, TRUE);
    }

    Перевод с Delphi в C++Builder мой (IR).




  • Q32: Есть 2 задачи: одна работает в окне ДОС, другая в Windows. Как
  • организовать обмен между ними, может есть какие-то стандартные
  • буферы обмена (Клипборд и Файлы не предлагать)?

    A(IEr): Попробуй через "трубу" (pipe). Принцип такой - запускаешь досовскую
    программу через CreateProcess, в STARTUPINFO:
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdError = GetStdHandler(STD_ERROR_HANDLE);

    потом

    CreatePipe(&hIn, &si.hStdOutput, 0, 0);
    CreatePipe(&si.hStdInput, &hOut, 0, 0);

    дальше все просто:

    for (;;) {
    DWORD code;
    if (!GetExitCodeThread(pi.hThread, &code)) // pi это структура
    return -1; // PROCESS_INFORMATION
    if (code == STILL_ACTIVE) { // переданная в CreateProcess
    // Читаем с помощью hIn
    // Пишем с помощью hOut
    }
    else
    break;
    }

    CloseHandle(si.hStdInput);
    CloseHandle(hOut);
    CloseHandle(si.hStdOutput);
    CloseHandle(hIn);

    Досовская программа читает из stdin, пишет в stdout.




  • Q33: Есть на форме Edit и Button, юзер вводит в Edit какую-нибудь цифирь
  • (например 20 ), давит на Button и на форме появляется 20 Label-ов.
  • Как можно сие реализовать? (создание компонента в runtime)

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    int count=Edit1->Text.ToInt();

    TLabel *lbl;

    for(int i=0;i {
    lbl=new TLabel(this);
    lbl->Parent=this;
    lbl->Caption=AnsiString("Label")+AnsiString(i);
    lbl->Top=i*20;
    lbl->Left=10;
    }
    }





  • Q34: Как сделать чтобы пpогpамма не отобpажалась в панели задач?

    A1. ShowWindow(Application->Handle, SW_HIDE); // прячем
    ShowWindow(Application->Handle, SW_SHOW); // показываем

    A2. Установить окну Application стиль WS_EX_TOOLWINDOW:

    WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
    {
    DWORD Style=GetWindowLong(Application->Handle, GWL_EXSTYLE);
    Style|=WS_EX_TOOLWINDOW;
    SetWindowLong(Application->Handle, GWL_EXSTYLE, Style);

    try
    {
    Application->Initialize();
    Application->CreateForm(__classid(TForm1), &Form1);
    Application->Run();
    }
    catch (Exception &exception)
    {
    Application->ShowException(&exception);
    }
    return 0;
    }





  • Q35: Как запустить процесс, дождаться окончания его инициализации,
  • дождаться завершения, получить код возврата?

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    STARTUPINFO si;

    ZeroMemory(&si, sizeof(STARTUPINFO));

    si.cb=sizeof(STARTUPINFO);
    si.wShowWindow=SW_SHOWNORMAL;

    PROCESS_INFORMATION pi;

    DWORD ExitCode;

    if(CreateProcess(NULL,
    "c:\\windows\\notepad.exe c:\\autoexec.bat",
    NULL,
    NULL,
    FALSE,
    CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS,
    NULL,
    NULL,
    &si,
    &pi)==TRUE)
    {
    CloseHandle(pi.hThread); // освобождаем ресурсы
    WaitForInputIdle(pi.hProcess, INFINITE); // ждем окончания инициализации
    // запущенного процесса.*
    WaitForSingleObject(pi.hProcess, INFINITE); // ждем завершения процесса
    GetExitCodeProcess(pi.hProcess, &ExitCode); // получаем код возврата
    CloseHandle(pi.hProcess); // освобождаем ресурсы
    }
    }

    *) Под окончанием инициализации понимается момент, когда процесс начинает
    ожидать команд от пользователя.




  • Q36: Где можно взять хелп по Win32 API?

    В поставку CBuilder'а входит Win32 SDK Reference, содержащий описание
    функций API. Для его установки при инсталляции необходимо поставить (или не
    снимать :) галочку на MS SDK Help Files. Для вызова справки по F1 необходимо
    подключить эти справочные файлы с помощью программы OpenHelp, входящей в
    поставку CBuilder'а. Или вызывать руками через
    Programs\Borland C++ Builder\Help\MS SDK Help Files\Win32 SDK Reference.
    "Родной" хелп берется на msdn.microsoft.com или на дисках 4-5 из
    поставки MS Visual Studio.




  • Q37: Столкнулся с проблемой, что TImageList не раборает корректно на
  • некоторых машинах. К примеру не отрисовываются картинки на ToolBar в
  • кнопках. Причем на моей машине, где проект создавался - все Ок а вот
  • при переносе на другую машину начинаются проблемы.

    Необходимо обновить comctl32.dll на машинах, где наблюдаются проблемы.




  • Q38: Была у меня програмка на BCB3 и там некоторые функции разделялись:
  • одни в конструкторе формы, другие - в событии формкреэйт. Переполз на
  • BCB4 и что же конструктор вызывается после события создания формы -
  • это как? (другой вариант этого вопроса: имеем форму с добавленными мною
  • полями типа AnsiString. В OnCreate я эти поля заполняю некоторыми
  • значениями, ставлю breakpoint в OnShow и смотрю эти переменные - они
  • пустые!)

    Необходимо у всех форм/datamodule'ей поставить OldCreateOrder = false;




  • Q39: Как грамотно связаться с MS Word (OLE)?

    A(SE): С Вордом никаких проблем для связи через OLE нет. Вот давно обещал
    многим законченный класс для вызова Ворда из СВ - пожалуйста, пользуйтесь...
    Цеплял я его уже к проектам 10, и все пашет и на 95, и на 98 (на NT не
    пробовал).

    (MessageBox - моя функция, поменяйте на похожую из ВС, облом искать
    исходник)

    H:
    //--------------------------------------------------------------------------
    #ifndef MSWordH
    #define MSWordH
    //--------------------------------------------------------------------------
    void __fastcall CopyRTFToClipboard(AnsiString buf);
    //--------------------------------------------------------------------------
    enum WinwordColor { mswColAuto, mswColBlack, mswColBlue, mswColCyan,
    mswColGreen, mswColMagenta,
    mswColRed, mswColYellow, mswColWhite, mswColDarkBlue,
    mswColDarkCyan,
    mswColDarkGreen, mswColDarkMagenta, mswColDarkRed,
    mswColDarkYellow,
    mswColDarkGray, mswColLightGray };
    enum WinwordTabType { mswTabLeft, mswTabCenter, mswTabRight, mswTabDecimal,
    mswTabBar };
    enum WinwordAlign { mswAlgLeft, mswAlgCentered, mswAlgRight,
    mswAlgJustified };
    enum WinwordSpacing { mswSpSingle, mswSpLines, mswSpDouble };
    //--------------------------------------------------------------------------
    class TMSWord
    {
    private:
    Variant msWord;
    AnsiString msWordTitle;

    bool __fastcall Run();

    public:
    __fastcall ~TMSWord();

    bool __fastcall Create(AnsiString fileName);
    bool __fastcall GotoBookmark(AnsiString mark);
    void __fastcall InsertText(AnsiString str);
    void __fastcall InsertTextEOL(AnsiString str);
    void __fastcall Paste();
    void __fastcall Restore();
    bool __fastcall RunApplication(AnsiString dir);
    void __fastcall SetFontFormat(TFont *f,WinwordColor color = mswColAuto);
    void __fastcall SetFontFormat(char *fontName,int fontSize,TFontStyles
    style,
    WinwordColor fontColor = mswColAuto);
    void __fastcall SetBookmark(AnsiString mark);
    void __fastcall SetParagraphFormat(int leftIndent = 0,int rightIndent =
    0,
    int before = 0,int after = 0,
    WinwordSpacing lineSpacing =
    mswSpSingle,
    WinwordAlign align = mswAlgLeft);
    void __fastcall SetTabs(int *tabs,int num,WinwordTabType type =
    mswTabLeft);
    void __fastcall Exit();
    };
    //--------------------------------------------------------------------------
    #endif



    CPP:
    //--------------------------------------------------------------------------
    #include
    #pragma hdrstop
    #include
    #include
    #include
    #include
    #include "RxShell.hpp"
    #include "MSWord.h"
    #include "MSWordLoc.h"
    #include "VMessage.h"
    #pragma package(smart_init)

    #define START "Start"
    #define WORD_EXE "WinWord.exe"

    //**************************************************************************
    // Копирование текста в буфер
    //--------------------------------------------------------------------------
    void __fastcall CopyRTFToClipboard(AnsiString buf)
    {
    // регистрируем формат RichText
    Word cfRTF = (Word)RegisterClipboardFormat(TEXT("Rich Text Format"));
    Clipboard()->Open();
    int nTextLen = (buf.Length() + 1) * sizeof(TCHAR);
    HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE,nTextLen);
    if(hGlobal != NULL) {
    void *lpText = GlobalLock(hGlobal);
    memcpy(lpText,buf.c_str(),nTextLen);
    Clipboard()->Clear();
    GlobalUnlock(hGlobal);
    Clipboard()->SetAsHandle(cfRTF,(int)hGlobal);
    }
    Clipboard()->Close();
    }
    // Класс TMSWord
    //**************************************************************************
    // Деструктор
    //--------------------------------------------------------------------------
    __fastcall TMSWord::~TMSWord()
    {
    msWord.Clear();
    }
    // Создание объекта и открытие файла
    //--------------------------------------------------------------------------
    bool __fastcall TMSWord::Create(AnsiString fileName)
    {
    // если объект уже создан
    if(!msWord.IsEmpty()) {
    try {
    // пытаемся активизировать Word
    if((short)msWord.Exec(PropertyGet("AppIsRunning") << msWordTitle)
    == -1)
    msWord.Exec(Procedure("AppRestore") << msWordTitle);
    }
    catch (EOleSysError& e) {
    // если окно с документом (не Word) было закрыто пользователем, то
    ErrorCode = 0
    // выходим из catch сразу на загрузку документа (без запуска
    Word-a)
    if(e.ErrorCode) {
    // перехватываем событие, когда Word уже был запущен программой
    // а потом закрыт пользователем
    if(e.ErrorCode != 0x800706BA) {
    MessageBox(e.Message + LoadStr(MSWORD_ERROR1),msError);
    return false;
    }
    if(!Run()) // запускаем Word повторно
    return false;
    }
    }
    }
    // объект еще не создан
    else if(!Run()) // пытаемся запустить
    return false;
    // объект успешно создан, открываем файл
    try {
    msWord.Exec(Procedure("AppShow"));
    msWord.Exec(Procedure("FileNew") << fileName);
    // получаем заголовок созданного окна
    msWordTitle = AnsiString("Microsoft Word - ") +
    msWord.Exec(PropertyGet("WindowName"));
    return true;
    }
    catch (Exception& e) {
    MessageBox(e.Message + LoadStr(MSWORD_ERROR2),msError);
    }
    return false;
    }
    // Закрытие Word
    //--------------------------------------------------------------------------
    void __fastcall TMSWord::Exit()
    {
    try {
    if(!msWord.IsEmpty() &&
    MessageBox(LoadStr(MSWORD_CONFIRM),msConfirm_YesNo) == IDYES)
    msWord.Exec(Procedure("AppClose"));
    }
    catch (...) {
    }
    }
    // Переход на закладку
    //--------------------------------------


    Комментарии

    отсутствуют

    Добавление комментария


    Ваше имя (на форуме):

    Ваш пароль (на форуме):

    Комментарии могут добавлять только пользователи,
    зарегистрированные на форуме данного сайта. Если Вы не
    зарегистрированы, то сначала зарегистрируйтесь тут

    Комментарий:





  • Главная     Программы     Статьи     Разное     Форум     Контакты