Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Программы Обои   Экспорт RSS E-Books
 
 

   Программирование -> C++ Builder -> FAQ C++ Builder


FAQ по C++Builder



                               Вопросы


Q1.  Как показать ProgressBar на StatusBar'е ?
Q2.  Как использовать CTreeCtrl для построения дерева каталогов диска, как в
     Проводнике ?
Q3.  Есть класс - потомок CListView. Как изменить стиль у объекта CListCtrl,
     принадлежащего к этому *view (например установить стиль Report)?
Q4.  Как CString привести к char *?
Q5.  Какие библиотеки (Freeware/Commercial) существуют для Visual C++ ?
Q6.  А можно пример консольной программы ?
Q7.  В созданном мастером (VC 6.0) win32 Console Application попытка вывести
     русский текст дает кракозяблики.Что делать ?
Q8.  Пытаюсь из своей программы вызвать Word97, для это делаю несколько
     импортов и в результате имею кучу ошибок. Как правильно ?
Q9.  А как отредактировать ресурсы .exe файла ?
Q10. Как программно получить номер билда своего приложения в VC++?
Q11. Какой функцией можно переключить видеорежим ?
Q12. Как вызвать окно выбора папки ?



                                Ответы

==============================================================================
Q1. Как показать ProgressBar на StatusBar'е ?

A1.

Предположим, что вы хотите показать CProgressCtrl на весь StatusBar.
Для этого необходимо проделать следующее:
- Выберите пункт меню View - Resource Symbols. Нажмите кнопку New и
  добавьте новое имя, в нашем примере это будет ID_PROGRBAR.
- В файле MainFrm.cpp найдите объявление массива indicators (он
  находиться сразу после END_MESSAGE_MAP) и отредактируйте его к
  следующиему виду
  static UINT indicators[] =
             {
                 ID_PROGRBAR
              };
- В файле _MainFrm.h создайте protected  переменную m_bCreated  типа
  BOOL и public переменную m_progress типа CProgressCtl.
- В файле MainFrm.cpp отредактируйте конец функции
  int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) таким образом:

                  к участку  кода:

                    if (!m_wndStatusBar.Create(this ) ||
                       !m_wndStatusBar.SetIndicators(indicators,
                       sizeof(indicators)/sizeof (UINT)))
                   {
                       TRACE0("Failed to create status bar\n" );
                       return -1; // fail to create
                   }

   добавьте следующую строку:

          else {
                m_wndStatusBar.SetPaneInfo(0,ID_PROGRBAR,SBPS_STRETCH,10);
               }

Кроме того, добавьте инициализацию нашей переменной m_bCreated

                    .........
                     m_bCreated=FALSE;
                    ..........

- Теперь мы можем использовать ProgressBar в строке статуса, естественно не
  забыв создать этот объект. Предположим, у нас есть функция
  CMainFrame::OnWork(). Она будет выглядеть примерно так:
   void CMainFrame::OnWork()
            {
              RECT rc;
                m_wndStatusBar.GetItemRect(0,&rc);
               if (m_bCreated==FALSE)
               {
                 // создаем  m_progress
                 m_progress.Create(WS_VISIBLE|WS_CHILD, rc,&m_wndStatusBar, 1);
// Устанавливаем размер от 0 до 100
                 m_progress.SetRange(0,100);
                 m_progress.SetStep(1);
                 m_bCreated=TRUE;
                }
                for (int I = 0; I < 100; I++)
                {
                  Sleep(20);
                  m_progress.StepIt();
                }
            }
-Если откомпилировать проект на этой фазе, то все будет работать, но при
изменении размера окна линейка ProgressBar'а размеры менять не будет, поэтому
необходимо перекрыть событие OnSize:
            void CMainFrame::OnSize(UINT nType, int cx, int cy)
            {
                CFrameWnd::OnSize(nType, cx, cy);
                 if (m_bCreated)
                  {
                      RECT rc;
                      m_wndStatusBar.GetItemRect(0,&rc);
                      m_progress.SetWindowPos(&wndTop, rc.left, rc.top,
                      rc.right - rc.left,rc.bottom - rc.top, 0);
                    }
              }

- Вот теперь все /-))))) Откомпилируйте проект и убедитесь, что все
работает.

==============================================================================

Q2. Как использовать CTreeCtrl для построения дерева каталогов диска, как в
Проводнике ? Неужели необходимо рекурсивно просмотреть диск, а потом прописать
ручками все Итемы данного контрола ??

A2. (A. Лисеев Дмитрий. 

dimik@infopro.spb.su

)

 Это тормозно и глючно. На больших дисках это займет несколько минут. Если
каталоги добавляются или удалются другими приложениями во время работы твоего
контрола, то будешь весь в проблемах. Все гораздо проще. Никаких рекурсий.
Просматриваем корневой каталог на предмет наличия подкаталогов и создаем итемы
первого уровня, в которых создаем по одному фиктивному итему (чтобы крестик
был и итем можно было раскрыть).
 + Каталог 1
 + Каталог 2
 + Каталог 3
 Как только юзер пытается раскрыть итем, соответствующий некому каталогу, мы
удаляем из него фиктивный итем, просматриваем этот подкаталог и добавляем
соответствующие итемы со своими фиктивными внутри.
 -Каталог 1
    + Каталог 4
    + Каталог 5
    + Каталог 6
 + Каталог 2
 + Каталог 3
 Как только юзер закрывает итем, мы удаляем из него все дочерние итемы и
обратно добавляем фиктивный. Если структура каталогов изменилась, для
обновления юзеру достаточно просто закрыть и открыть соответствующую ветку.
Именно так и работает "Проводник".

==============================================================================

Q3. Есть класс - потомок CListView. Как изменить стиль у объекта CListCtrl,
    принадлежащего к этому *view (например установить стиль Report) ?

A3.

Для этого пишите в OnInitialUpdate вашего вида

void CMyListView::OnInitialUpdate()
{
 ......
        CListView::OnInitialUpdate();

    CListCtrl& theCtrl = GetListCtrl();
    DWORD dwStyle=GetWindowLong(theCtrl.m_hWnd,GWL_STYLE);
    SetWindowLong(theCtrl.m_hWnd,GWL_STYLE,dwStyle|LVS_REPORT);
 ....

A3. (by Pavel Nazin 2:5020/1053.21)
Гораздо проще перекрыть PreCreateWindow (лучше всего воспользоваться
ClassWizard-ом) и поковырять переданный по ссылке CREATESTRUCT типа такого:

BOOL CMyListView::PreCreateWindow(CREATESTRUCT& cs)
{
    cs.style|=LVS_REPORT;//так мы добавляем стиль
    cs.style&=LVS_REPORT;//а вот так снимаем

    return CMyListView::PreCreateWindow(cs);
}




==============================================================================

Q4. Как CString привести к char * ? _

A4. (by Yuri Khodin 2:5020/1200.20)

#include <atlbase.h>
USES_CONVERSION;
 CString strData(_T("Some Data"));
 char* lpszString = T2A((LPTSTR)(LPCTSTR)strData);

A2. (by Paul Kalyakin 2:5029/3.29 

hjobyf@mail.ru

)

CString tmp_str;
char* st;

st=tmp_str.GetBuffer(tmp_str.GetLength())

важно то, что если с tmp_str что-либо сделать, то необходимо опять получить
указатель на внутренний буфер CString.

==============================================================================
Q5. Какие библиотеки Freeware/Commercial существуют для Visual C++ ? _

A5.

1- BCG Control Library (freeware)
    

http://msnhomepages.talkcity.com/WindowsWay/stasl/index.html


2- CJLibrary (freeware)
    

http://www.codejock.com/


Stringray Software (commercial)  www.stingray.com
Фирма Stringray Software производит библиотеки для Visual C++ (MFC, ATL):
1. Stingray Objective Toolkit (PRO) - набор различных компонентов для
   MFC и ATL
2. Stingray Objective Grid (PRO) - мощная сетка данных с возможностями,
   близкими к Excel. Дружит с базами данных (через DAO,ADO,ODBC). Можно
   использовать для ввода данных в таблицы БД и для вывода/печати простых
   отчётов.
3. Stingray Objective Chart - средство для построения диаграмм
4. Stingray Objective Views - средство для создания Visio-подобных
   интерфейсов (при помощи векторной графики)
5. Stingray Objective Edit - текстовый редактор с подсветкой синтаксиса

кроме этих, есть и другие продукты


-
Dundas Software (commercial) 

http://www.dundas.com/

Фирма Dundas Software производит библиотеки для Visual C++ (MFC):
1. Dundas Ultimate Toolbox - набор компонентов для MFC, по составу
   несколько отличающийся от Stingray Objective Toolkit.
2. Dundas Ultimate Grid - сетка данных, конкурент Stingray Objective Grid.
3. Dundas TCP/IP - реализация протоколов POP3,NEWS и т.п.
4. Dundas Chart - диаграммы
и другие продукты




==============================================================================

Q6.А можно пример консольной программы ? _

A6. by Alexander Fedorov (2:5030/437.74)

#include <windows.h>
#include <stdlib.h>


void main()
 {
 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 SMALL_RECT srct;
 CHAR_INFO chiBuffer[160];
 COORD coord1, coord2;
 char ddd[666];
 CharToOem("2:5095/38 - злобный ламерюга", ddd);
 DWORD cWritten;
 coord1.Y = 0; coord1.X = 0;
 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 WriteConsoleOutputCharacter(hStdout, ddd, lstrlen(ddd), coord1, cWritten);
 for (int i = 0; i {
 WORD wColors = 1 + i * 3;
 coord1.X = i;
 WriteConsoleOutputAttribute(hStdout, , 1, coord1, cWritten);
 }
 srct.Top = 0; srct.Left = 0; srct.Bottom = 1; srct.Right = 79;
 coord1.Y = 0; coord1.X = 0;
 coord2.Y = 1; coord2.X = 80;
 ReadConsoleOutput(hStdout, chiBuffer, coord2, coord1, );
 for (i = 0; i {
 srct.Left = (SHORT)((double)(79 - lstrlen(ddd)) * rand() / RAND_MAX);
 srct.Top = (SHORT)((double)25 * rand() / RAND_MAX);
 srct.Bottom = srct.Top + 1;
 WriteConsoleOutput(hStdout, chiBuffer, coord2, coord1, );
 }
 Sleep(10000);

==============================================================================

Q7. В созданном мастером (VC 6.0 ) win32 Console Application попытка вывести
    русский текст дает кракозяблики.Что делать ? _

A7. by Dmitriy Reznitskiy (2:5020/1452.112)


CharToOem, OemToChar - оно?
==============================================================================

Q8. Пытаюсь из своей программы вызвать Word97, для это делаю несколько импортов
и
    в результате имею кучу ошибок. Как правильно ? _

A8. by Igor Tkachoff (2:5037/9.37)


// Office.h

#define Uses_MSO2000_

 #ifdef Uses_MSO2000
 // for Office 2000
 #import <mso9.dll>
 #import <vbe6ext.olb>
 #import <msword9.olb> rename("ExitWindows","_ExitWindows")
 #import <excel9.olb> rename("DialogBox","_DialogBox") \
 rename("RGB","_RGB") \
 exclude("IFont","IPicture")
 #import <dao360.dll> rename("EOF","EndOfFile") rename("BOF","BegOfFile")
 #import <msacc9.olb>

#else
 // for Office 97
 #import <mso97.dll>
 #import <vbeext1.olb>
 #import <msword8.olb> rename("ExitWindows","_ExitWindows")
 #import <excel8.olb> rename("DialogBox","_DialogBox") \
 rename("RGB","_RGB") \
 exclude("IFont","IPicture")
 #import <DAO350.DLL> \
 rename("EOF","EndOfFile") rename("BOF","BegOfFile")
 #import <msacc8.olb>

#endif
 Каталоги проставь сам, если надо. Просто я предпочитаю сваливать все
библиотеки в одну кучу. А еще лучше сделать #import один раз, а затем
подключать #include "тыры-пыры.tlh".
P.S. С 2000'ным аккуратнее. Некоторые методы (типа Run, Open, Add) имеют новую
версию. И если хочешь совместимость с 97 то следует вызывать старые версии,
которые называются типа RunOld и т.п.
==============================================================================

Q9. А как отредактировать ресурсы .exe файла ? _

A9.

Это возможно лишь под NT.

==============================================================================
Q10. Как программно получить номер билда своего приложения в VC++? _

A10. by Pavel Zolotuhin (2:5025/60.15)

Штатной возможности нет, поскольку не все одинаково трактуют понятие "номер
билда" и не все одинаково его используют. Однако большинство людей используют
для хранения номера билда конкретного файла ресурсы типа VERSIONINFO, откуда
эту информацию можно потом получить (для отображения в диалоге "О программе"
:-) с помощью функций из version.dll.
 Упрощенно говоря, информация о версии файла хранится в VERSIONINFO в виде
четырех чисел, значимость которых убывает слева направо. Например, для
mfc42.dll из поставки Win2k версия файла выглядит как 6.0.8665.0. Здесь первая
цифра, как я понимаю, совпадает с версией продукта (MSVC 6), вторая означает
подверсию (MSVC 6.0), третья - номер билда, а четвертая - я не знаю. В своих
dll-ках и exe-шниках Microsoft постоянно использует эту схему, я - тоже.
Обычно для автоматического увеличения номера версии используются макросы
Visual Studio (== скрипты на VBScript), ковыряющие файл ресурсов проекта. Эти
макросы либо связываются с кнопкой на тулбаре MSDev, либо вызываются из
обработчика события Application_BeforeBuildStart в файле макросов. Примеры
подобных макросов горой лежат на девелоперских сайтах, наподобие
www.codeguru.com. Для себя я сделал собственный, который реализует номер билда
в указанном выше смысле. Вот его исходник (должен работать на MSVC6SP3).

 Sub IncVersion()
 'DESCRIPTION: Increments file version
      Dim oDoc
      Dim iVer

      Set oDoc = Documents.Open(Application.ActiveProject &".rc", "Text")
      if oDoc Is Nothing Then
          Exit Sub
      End If

      oDoc.Selection.FindText "FILEVERSION", dsMatchCase
      if Len(oDoc.Selection) = 0 Then
          oDoc.Close dsSaveChangesNo
          Set oDoc = Nothing
          Exit Sub
      End If
      oDoc.Selection.EndOfLine
      oDoc.Selection.FindText ",", dsMatchBackward
      oDoc.Selection.CharLeft
      oDoc.Selection.WordLeft dsExtend
      iVer = oDoc.Selection
      iVer = iVer + 1
      oDoc.Selection = iVer

      oDoc.Selection.FindText """FileVersion""", dsMatchCase
      if Len(oDoc.Selection) = 0 Then
          oDoc.Close dsSaveChangesNo
          Set oDoc = Nothing
          Exit Sub
      End If
      oDoc.Selection.EndOfLine
      oDoc.Selection.FindText ",", dsMatchBackward
      oDoc.Selection.CharLeft
      oDoc.Selection.WordLeft dsExtend
      iVer = oDoc.Selection
      iVer = iVer + 1
      oDoc.Selection = iVer

      oDoc.Close dsSaveChangesYes
      Set oDoc = Nothing

End Sub

=============================================================================
Q11. Какой функцией можно переключить видеорежим ?

A11. by Alexander Shargin (2:5030/852.22)


Этим занимается ChangeDisplaySettings(...);

Вот тебе пример, который устанавливает разрешение 640x480 (24 bit):

=== Cut ===
   DEVMODE md;
   ZeroMemory(&md, sizeof(md));
   md.dmSize = sizeof(md);
   md.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
   md.dmBitsPerPel = 24;
   md.dmPelsWidth = 640;
   md.dmPelsHeight = 480;
   ChangeDisplaySettings(&md, 0);
=== Cut ===

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

=============================================================================
Q12. Как вызвать окно выбора папки ?


A12.

Воспользуйтесь следующей функцией:

BOOL FGetDirectory(LPTSTR szDir)
{ BOOL fRet;
   TCHAR szPath[MAX_PATH];
   LPITEMIDLIST pidl;
   LPITEMIDLIST pidlRoot;
   LPMALLOC lpMalloc;
   BROWSEINFO bi =
       {
       NULL,
       NULL,
       szPath,
       "Выберите папку",
       BIF_RETURNONLYFSDIRS,
       NULL,
       0L,
       0
      };
   if (0 != SHGetSpecialFolderLocation(HWND_DESKTOP, CSIDL_DRIVES, &pidlRoot))
     return FALSE;
   if (NULL == pidlRoot)
     return FALSE;
   bi.pidlRoot = pidlRoot;
   pidl = SHBrowseForFolder(&bi);
   if (NULL != pidl)
     fRet = SHGetPathFromIDList(pidl, szDir);
   else
     fRet = FALSE; // Get the shell's allocator to free PIDLs
   if (!SHGetMalloc(&lpMalloc) && (NULL != lpMalloc))
   {
     if (NULL != pidlRoot)
     {
       lpMalloc->Free(pidlRoot);
     }
     if (NULL != pidl)
     {
       lpMalloc->Free(pidl);
     }
lpMalloc->Release();
}
return fRet;
}

LPTSTR PszAlloc(int cch)
{
return (LPTSTR) LocalAlloc(LMEM_FIXED, sizeof(TCHAR) * (cch+1));
}

bool PszDeAlloc(HLOCAL mem_ptr)
{
return (LocalFree(mem_ptr)==NULL) ? true : false;
}

Затем, при необходимости предложить пользователю выбрать папку
используйте примерно такой код:
....
LPTSTR fname;
fname=PszAlloc(250);
FGetDirectory(fname);
......
PszDeAlloc((HLOCAL)fname);

              FAQ  RU.CBUILDER

Содержание:
1. Как преобразовать AnsiString в char*?
2. Как сделать, чтобы программа на CBuilder3, 4 не требовала .bpl, .dll?
3. Что такое RXLib и где его взять?
4. Как сделать, чтобы окно вело себя, как верхняя панель в билдере,
т.е. ресайзилось только по горизонтали, и только до определенного
минимального размера, а по вертикали размер был фиксированным?
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*) возвращает некорректные
значения для аргумента в виде русской буквы?
13. Почему при сборке в CB3 с включенным Build With Runtime Packages все
работает, а если отключить, то вылетает с ошибкой, не доходя до
Application->Initialize(). Какие у All соображения на этот счет?
14. Есть функция, которая производит длительные вычисления в цикле.
Хотелось бы иметь возможность ее прервать. Естественно, что пока
вычисления не выходят из цикла никакие контролы не работают....
15. Я переписываю BDE-приложение на другой компьютер, а оно отказывается
работать. Что делать?
16. Как сделать перекодировку CP866 <-> CP1251?
17. Как из Builder'a можно работать с последовательными портами?
Надо сконнектиться с одной железякой по RS-232.
18. Как отследить запуск второй копии приложения?
19. Как на C++ выглядит паскалевский is?
*20. Люди, где в инете Русский Хелп взять на Builder 3.0/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. Как определить, работает компонент в design mode или уже в автономной
программе?
27. Как зарегистрировать property editor для __property типа AnsiString?
28. Как сделать так чтобы эхотаг при запуске автоматически открывал
проект с которым я в последний раз работал, а не создавал новый?
29. Я делаю компонент, который в качестве свойства получает указатель
на об'ект TComboBox. Хочется иметь возможность заметить его уничтожение
в дизайнере, для того чтобы не возникало указателя на пустое место и
следуюшего за этим Access Violation. Как это сделать?
30. Кто-нибудь может мне подробно и понятно об'яснить, как мне присвоить
моему компоненту иконку (чтоб в Component Palette красивее стало :) )?
31. Как сделать круглое/овальное/с дыркой/etc. окно?
32. Есть 2 задачи: одна работает в окне ДОС, другая в Windows. Как
организовать обмен между ними, может есть какие-то стандартные буферы
обмена (Клипборд и Файлы не предлагать)?
33. Есть на форме Edit и Button, юзер вводит в Edit какую-нибудь цифирь
(например 20 ), давит на Button и на форме появляется 20 Label-ов.
Как можно сие реализовать? (создание компонента в runtime)
34. Как сделать чтобы программа не отображалась в панели задач?
*35. Как запустить процесс, дождаться окончания его инициализации,
дождаться завершения, получить код возврата?
36. Где можно взять хелп по Win32 API?
37. Столкнулся с проблемой, что TImageList не раборает корректно на
некоторых машинах. К примеру не отрисовываются картинки на ToolBar в
кнопках. Причем на моей машине, где проект создавался - все Ок а вот при
переносе на другую машину начинаются проблемы.
38. Была у меня програмка на BCB3 и там некоторые функции разделялись:
одни в конструкторе формы, другие - в событии формкреэйт. Переполз на
BCB4 и что же конструктор вызывается после события создания формы -
это как? (другой вариант этого вопроса: имеем форму с добавленными мною
полями типа AnsiString. В OnCreate я эти поля заполняю некоторыми
значениями, ставлю breakpoint в OnShow и смотрю эти переменные - они
пустые!)
39. Как грамотно связаться с MS Word (OLE)?
40. Как сделать таймер с интервалом < 1 мс?
41. Как определить количество памяти, доступной Windows и её свободный объём?
42. Как получить список запущенных задач?
43. Как получить список исполняемых процессов?
44. Как узнать загрузку процессора?
45. Нашёл в хэлпе полезную функцию ROUND, а программа не компилируется.
Пишет "Call to undefined function" :( Как же округлять?
*46. Как сменить цвет надписи у TButton?


>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: Как сделать, чтобы программа на 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: Как сделать, чтобы окно вело себя, как верхняя панель в билдере,
> т.е. ресайзилось только по горизонтали, и только до определенного
> минимального размера, а по вертикали размер был фиксированным?

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

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. Написать руками :)
а) Делаешь форму, которая будет изображать 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): Ребят, я давно делаю под НТ (под 95 не знаю, не пробовал) такую вещь:

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

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


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

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

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


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

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

#pragma pack(push, 1)
<structure definition>
#pragma pack(pop)

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


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

A: Нет.


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

A(YH):

#include <typeinfo.h>
#include <stdio.h>

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);
}

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

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

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

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


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

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


A(MR):

class TComponent1* : public TComponent
{ // Это класс от которого мы будем порождать все наши классы
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);}
// Эта функция создает класс, поскольку все создаваемые классы мои и //
порожденны от TObject проблемм нет, осталось только ее вызвать.
}

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

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


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

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



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

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

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


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

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

Нужно добавить следующие файлы из папки 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):Для того, чтобы установить программу, которая требует BDE, есть несколько
базовых путей, в частности:

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

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

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

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

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

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

По факту, существует несколько альтернативных движков, подробнее можно узнать в
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 можно работать с последовательными портами?
> Надо сконнектиться с одной железякой по RS-232.

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


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

//---------------------------------------------------------------------------
__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("Невозможно открыть порт 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("Ошибка инициализации порта 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("Ошибка инициализации порта COM"+IntToStr(n));

ierr = SetCommMask(hCom, EV_RXCHAR);

if(!ierr) throw Exception("Ошибка инициализации порта 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, которая
в конце-концов тоже использует эту функцию. Однако ActivatePrevInstance
так же выполняет некоторые полезные :) действия (e.g. активизация предыдущей
копии приложения)
3. Можно создавать семафоры, мутексы, но тогда при некорректном завершении
программы, ты ее больше не запустишь ;)
Пример использования мутекса:

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 <tlhelp32.h>
#include <dos.h>

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<FormClass*>(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.
Необходимо использовать библиотеку типов Excel.


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

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

Шаг 1.
*******
Подключаем библиотеку типов Excel к своему проекту.
Выбираем Project|Import Type Library. Нажимаем кнопку 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):

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

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

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

#include <comobj.hpp>

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));
}

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


A(SE):

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

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

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

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

A(AS): Пример работы с 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

following up a message from Andrew Smirnov to all:

//.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 <vcl.h>
#pragma hdrstop

#include "ExServer.h"
#include <ComObj.hpp>
#include <stdio.h>
#include <math.h>
//---------------------------------------------------------------------------
#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, вы не ДОЛЖНЫ ПЕРЕДАВАТЬ НА
СЕРВЕР НИКАКИХ АРГУМЕНТОВ! Если мы посмотрим Excel_TLB.H, то увидим
следующий код обращения к серверу в дисп-интерфейсе класса Workbooks:

_GlobalDispT<T>::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();
}

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

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

_GlobalDispT<T>::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: Как определить, работает компонент в design mode или уже в
> автономной программе?

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


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


A(ИТ):

#include <dsgnintf.hpp>
#include <typinfo.hpp>

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):

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

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

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

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

return typeInfo;
}

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

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


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

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


>Q29: Я делаю компонент, который в качестве свойства получает указатель
> на об'ект TComboBox. Хочется иметь возможность заметить его уничтожение
> в дизайнере, для того чтобы не возникало указателя на пустое место и
> следуюшего за этим 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: Кто-нибудь может мне подробно и понятно об'яснить, как мне присвоить
> моему компоненту иконку (чтоб в Component Palette красивее стало :) )?

A(AS): Создаешь .res файл, делаешь там битмап по имени класса компонента
(например TMYCOMPONENT) размером 24x24. Левая нижняя точка - цвет
прозрачности. Полученный .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<count;i++)
{
lbl=new TLabel(this);
lbl->Parent=this;
lbl->Caption=AnsiString("Label")+AnsiString(i);
lbl->Top=i*20;
lbl->Left=10;
}
}



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

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 <vcl.h>
#pragma hdrstop
#include <comobj.hpp>
#include <clipbrd.hpp>
#include <utilcls.h>
#include <vclutils.hpp>
#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 (...) {
}
}
// Переход на закладку
//--------------------------------------------------------------------------
bool __fastcall TMSWord::GotoBookmark(AnsiString mark)
{
try {
msWord.Exec(Procedure("EditGoto") <<
NamedParm("Destination",mark.c_str()));
return true;
}
catch (Exception& e) {
MessageBox(e.Message + "\nBookmark: " + mark,msError);
}
return false;
}
// Вставка текста в текущую позицию курсора
//--------------------------------------------------------------------------
void __fastcall TMSWord::InsertText(AnsiString str)
{
msWord.Exec(Procedure("Insert") << str);
}
// Вставка текста в текущую позицию курсора с переходом на новую строку
//--------------------------------------------------------------------------
void __fastcall TMSWord::InsertTextEOL(AnsiString str)
{
msWord.Exec(Procedure("Insert") << (str + '\n'));
}
// Вставка текста в текущую позицию курсора
//--------------------------------------------------------------------------
void __fastcall TMSWord::Paste()
{
msWord.Exec(Procedure("EditPaste"));
}
// Восстановление (активация) Word
//--------------------------------------------------------------------------
void __fastcall TMSWord::Restore()
{
try {
msWord.Exec(Procedure("AppRestore") << msWordTitle);
msWord.Exec(Procedure("AppMaximize") << msWordTitle << 1); //
максимизируем
}
catch (EOleSysError&) {
MessageBox(LoadStr(MSWORD_INFO),msInfo);
}
}
// Собственно запуск Word-a как OLE-сервера
//--------------------------------------------------------------------------
bool __fastcall TMSWord::Run()
{
bool isWordRunning = true;
// сначала пытаемся переключиться на активный Word
try {
msWord = Variant::GetActiveObject("Word.Basic");
}
catch (EOleSysError& e) {
isWordRunning = false;
}
if(!isWordRunning) { // нет запущенного Word
try {
msWord = Variant::CreateObject("Word.Basic");
msWord.Exec(Procedure("AppMaximize") << 1); // максимизируем
}
catch (EOleSysError& e) {
MessageBox(e.Message + LoadStr(MSWORD_ERROR1),msError);
return false;
}
}
return true;
}
// Запуск Word-a как приложения
//--------------------------------------------------------------------------
bool __fastcall TMSWord::RunApplication(AnsiString dir)
{
if(FileExecute(START,WORD_EXE,dir,esNormal) <= 32) {
MessageBox(LoadStr(MSWORD_ERROR1),msError);
return false;
}
Delay(20000);
return true;
}
// Задание характеристик шрифта
//--------------------------------------------------------------------------
void __fastcall TMSWord::SetFontFormat(TFont *f,WinwordColor color)
{
msWord.Exec(Procedure("FormatFont") <<
NamedParm("Points",f->Size) <<
NamedParm("Font",f->Name.c_str()) <<
NamedParm("Color",color));
if(f->Style.Contains(fsBold))
msWord.Exec(Procedure("Bold") << 1);
if(f->Style.Contains(fsItalic))
msWord.Exec(Procedure("Italic") << 1);
if(f->Style.Contains(fsUnderline))
msWord.Exec(Procedure("Underline") << 1);
if(f->Style.Contains(fsStrikeOut))
msWord.Exec(Procedure("Strikethrough") << 1);
}
// Задание характеристик шрифта
//--------------------------------------------------------------------------
void __fastcall TMSWord::SetFontFormat(char *fontName,int
fontSize,TFontStyles style,WinwordColor fontColor)
{
TFont *f = new TFont();
f->Name = fontName;
f->Size = fontSize;
f->Style = style;
SetFontFormat(f,fontColor);
delete f;
}
// Задание имени закладки
//--------------------------------------------------------------------------
void __fastcall TMSWord::SetBookmark(AnsiString mark)
{
msWord.Exec(Procedure("EditBookmark") << NamedParm("Name",mark) <<
NamedParm("Add",1));
}
// Задание характеристик абзаца
//--------------------------------------------------------------------------
void __fastcall TMSWord::SetParagraphFormat(int leftIndent,int rightIndent,
int before,int after,
WinwordSpacing lineSpacing,
WinwordAlign align)
{
msWord.Exec(Procedure("FormatParagraph") <<
NamedParm("LeftIndent",AnsiString(leftIndent).c_str()) <<
NamedParm("RightIndent",AnsiString(rightIndent).c_str()) <<
NamedParm("Before",before) <<
NamedParm("After",after) <<
NamedParm("LineSpacing",lineSpacing) <<
NamedParm("Alignment",align));
}
// Установка позиций табуляции
//--------------------------------------------------------------------------
void __fastcall TMSWord::SetTabs(int *tabs,int num,WinwordTabType type)
{
for(int i = 0;i < num;i++)
msWord.Exec(Procedure("FormatTabs") <<
NamedParm("Position",AnsiString(tabs[i]).c_str()) <<
NamedParm("Align",type) <<
NamedParm("Set",1));
}


>Q40: Как сделать таймер с интервалом < 1 мс?

A(VK): Использовать Performance Counter.

Функцией QueryPerformanceFrequency получаем частоту счётчика,
которая, как правило, выше 1Мгц, создаём отдельный поток и в цикле
функцией QueryPerformanceCounter считываем его значение.

Практически, на P200 достаточно точно определяются интервалы в 20 мкс.


>Q41: Как определить количество памяти, доступной Windows и её свободный объём?

A(VK): Использовать функцию API GlobalMemoryStatus(...).


>Q42: Как получить список запущенных задач?

A(VK): Надо составить список главных окон приложений (top-level windows). Окно
считается главным если:
0. Имеет заголовок
1. Видимо
2. Не имеет родителя
Приходим к следующему коду:

bool __stdcall EnumProc(HWND hWnd,long) {
char buffer[100];

if(hWnd==NULL)
return false;
GetWindowText(hWnd,buffer,sizeof(buffer));
if (buffer[0]
&& IsWindowVisible(hWnd)
&& GetWindowLong(hWnd,GWL_HWNDPARENT)==0) {
// Ваш код
};
return true;
}

В нужном месте вызываем его
EnumWindows((WNDENUMPROC)EnumProc,0);


>Q43: Как получить список исполняемых процессов?

A(VK): Можно посмотреть в $(BCB)\Examples\Apps\Procview, а можно и по другому.

Под W95/98:

#include <tlhelp32.h>

PROCESSENTRY32 PC32;

hnd=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if ((int)hnd==-1)
return;
PC32.dwSize=sizeof(PC32);
i=Process32First(hnd,&PC32);
while (i) {
// Ваш код
// PID процесса берётся из PC32.th32ProcessID;
// Имя файла через ExtractFileName(PC32.szExeFile);
i=Process32Next(hnd,&PC32);
};
CloseHandle(hnd);

Под NT:

DWORD PIDStack[512];
DWORD modNeeded;
EnumProcesses(PIDStack,sizeof(PIDStack),&modNeeded);


>Q44: Как узнать загрузку процессора?

A(VK): Под W95/98 :

HKEY CPULoadKey;
int CPULoad;
ULONG Type = REG_DWORD;
DWORD CPULoadSize = sizeof (CPULoad);

Один раз в начале программы:

RegOpenKey(HKEY_DYN_DATA,"PerfStats\\StartStat",&CPULoadKey);
RegQueryValueEx(CPULoadKey,"KERNEL\\CPUUsage",NULL, &Type, (LPBYTE)&CPULoad,
&CPULoadSize);
RegCloseKey(CPULoadKey);
RegOpenKey(HKEY_DYN_DATA,"PerfStats\\StatData",&CPULoadKey);

По мере необходимости
RegQueryValueEx(CPULoadKey,"KERNEL\\CPUUsage",NULL, &Type, (LPBYTE)&CPULoad,
&CPULoadSize);
CPULoad содержит результат в процентах.

Один раз в конце
RegCloseKey(CPULoadKey);
RegOpenKey(HKEY_DYN_DATA,"PerfStats\\StopStat",&CPULoadKey);
RegQueryValueEx(CPULoadKey,"KERNEL\\CPUUsage",NULL, &Type, (LPBYTE)&CPULoad,
&CPULoadSize);
RegCloseKey(CPULoadKey);

Под NT либо использем PDH.dll, но она мало у кого есть, либо начинаем
шаманские пляски вокруг performance keys в реестре. Пример есть на
www.codepile.com, файл ntcounters.cpp.

 


>45: Нашёл в хэлпе полезную функцию ROUND, а программа не компилируется.
Пишет "Call to undefined function" :( Как же округлять?

A(VK): Функция ROUND (как, впрочем, и TRUNC) принадлежит OCX-контролу
F1Book. Пишем свою:

#include <math.h>

double Round(double Argument, int Precision)
{
double div = 1.0;
if(Precision >= 0)
while(Precision--)
div *= 10.0;
else
while(Precision++)
div /= 10.0;
return floor(Argument * div + 0.5) / div;
}

Hint: точность может быть отрицательной. Round(1234,-2)==1200.

 

>46: Как сменить цвет надписи у TButton?

Никак. Используйте, например, TBitBtn.

 


 



 

 
Интересное в сети
 
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full


Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
Реклама на сайте. Размещая рекламу у нас, вы получите новых посетителей, которые могут стать вашими клиентами.
 
Это интересно
 

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.
 
Rambler's Top100