Секция 2 из 3 - Предыдущая - Следующая
Все секции
- 1
- 2
- 3
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):
Категорически не согласен !!!
Попpобовал я эту TLB - все клево, только тоpмоза жуткие пpи компиляции.
(header TLB огpомный, пpекомпиляция не спасает) Вполне можно pаботать на
базе <comobj.hpp>
Вот пpимеp, котоpый у меня pаботает, и никаких "особенностей pеализации"
#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));
}
Все пpовеpено в бою на BCB3 с пачиком: BCB3P1CS.EXE. До пачика были
замечены слеты пpи возникновении Exception-ов.
A(SE):
По поводу использования TLB. Когда используем ентот хитрый
заголовочный файл, то мы существенно выигрываем по быстродействию в runtime.
Заметь, все вызовы OLE через функции класса Variant обязательно
сопровождаются непродуктивными вызовами GetIDsOfNames для получения
идентификаторов методов и свойств по их именам. Эта избитая тема обсуждается
во всех книгах по OLE. Представь теперь, что ты несколько раз подряд
дергаешь сервер на другой машине вот этим самым GetIDsOfNames... Жуть Ж:-(.
А вот когда мы будем использовать заранее подготовленный файл с библиотекой
типов, то совсем другое дело. Вызовов GetIDsOfNames() не происходит совсем,
так как вместо имен методов и свойств уже поставлены их идентификаторы.
Я согласен, что компиляция может несколько и удлиняется, но лучше подождать
на сборке, чем заставлять ждать пользователя, когда он работает с готовой
программой.
Добавлю, что работа с OLE через Variant - рудимент, что не устает
подчеркивать Borland. Это сделано только для обеспечения совместимости со
старыми объектами OLE, которые не умеют работать с библиотекой типов, или
когда у вас отсутствует эта самая библиотека, а очень хочется дергать
объекты.
Что касается примера с <comobj.hpp>, прошу уточнить, Какой Excel? Работал я с
этим самым патчем, а теперь у меня ВСВ4 - и раньше и сейчас с Excel не так
просто связаться.
A(ASm): Пример работы с Excel. Пробовалось все на связке builder 3 и
Excel разных версий.
Для успешной работы с русским excel надо подправить файлы comobj.pas и
oleauto.pas (они лежат в sourcevcl), после чего подключить их к проекту.
У меня по какой-то причине затребовался 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 <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: Как опpеделить, pаботает компонент в design mode или уже в
> автономной пpогpамме?
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):
Вот 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<count;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'а. Или вызывать руками через
ProgramsBorland C++ BuilderHelpMS SDK Help FilesWin32 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 =
Секция 2 из 3 - Предыдущая - Следующая
|