Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 8 мая!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

БОЛЬШОЙ FAQ ПО DELPHI



Иерархия классов



 unit InfoForm;
 
 interface
 
 uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
   StdCtrls, ExtCtrls, Buttons, Clipbrd, Comctrls, Db, Dbcgrids,
   Dbctrls, Dbgrids, Dblookup, Dbtables, Dialogs,
   Filectrl, Grids, Mask, Menus, Mplayer, Oleconst, Olectnrs,
   Olectrls, Outline, Tabnotbk, Tabs, IniFiles, Printers,
   Registry, DsgnIntf, Provider, BdeProv, DBClient,
   ComObj, ActiveX, DDEMan, IBCtrls, Math, Nsapi, Isapi,
   ScktComp, Axctrls, Calendar, CgiApp, checklst,
   ColorGrd, ComServ, syncobjs, httpapp, dbweb, DirOutln,
   Gauges, DsIntf, ToolIntf, EditINtf, ExptIntf, VirtIntf,
   istreams, isapiapp, dblogdlg, masks, ExtDlgs, Spin;
 
 type
   TForm1 = class(TForm)
     ListBox1: TListBox;
     Label1: TLabel;
     Edit1: TEdit;
     Label2: TLabel;
     Panel1: TPanel;
     TreeView1: TTreeView;
     ProgressBar1: TProgressBar;
     Button1: TButton;
     Button2: TButton;
     procedure Button1Click(Sender: TObject);
     procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
     procedure Button2Click(Sender: TObject);
   private
     function AddClass (NewClass: TClass): TTreeNode;
     function GetNode (BaseClass: TClass): TTreeNode;
   public
     { Public declarations }
   end;
 
 var
   Form1: TForm1;
 
 implementation
 
 {$R *.DFM}
 
 type
   TClassArray = array [1..498] of TClass;
 
 const
   ClassArray: TClassArray = (
 EAbort,
 EAccessViolation,
 EAssertionFailed,
 EBitsError,
 EClassNotFound,
 EComponentError,
 EControlC,
 EConvertError,
 EDatabaseError,
 EDateTimeError,
 EDBClient,
 EDBEditError,
 EDBEngineError,
 EDivByZero,
 EExternalException,
 EFCreateError,
 EFilerError,
 EFOpenError,
 EIBError,
 EInOutError,
 EIntError,
 EIntfCastError,
 EIntOverflow,
 EInvalidArgument,
 EInvalidCast,
 EInvalidContainer,
 EInvalidGraphic,
 EInvalidGraphicOperation,
 EInvalidGridOperation,
 EInvalidImage,
 EInvalidInsert,
 EInvalidOp,
 EInvalidOperation,
 EInvalidPointer,
 EListError,
 EMathError,
 EMCIDeviceError,
 EMenuError,
 EMethodNotFound,
 ENoResultSet,
 EOleCtrlError,
 EOleError,
 EOleException,
 EOleException,
 EOleSysError,
 EOutlineError,
 EOutOfMemory,
 EOutOfResources,
 EOverflow,
 EPackageError,
 EParserError,
 EPrinter,
 EPrivilege,
 EPropertyError,
 EPropReadOnly,
 EPropWriteOnly,
 ERangeError,
 EReadError,
 EReconcileError,
 ERegistryException,
 EResNotFound,
 ESocketError,
 EStackOverflow,
 EStreamError,
 EStringListError,
 EThread,
 ETreeViewError,
 EUnderflow,
 EUpdateError,
 EVariantError,
 EWin32Error,
 EWriteError,
 Exception,
 EZeroDivide,
 OutlineError,
 TActiveForm,
 TActiveFormControl,
 TActiveFormFactory,
 TActiveXControl,
 TActiveXControlFactory,
 TActiveXPropertyPage,
 TActiveXPropertyPageFactory,
 TAdapterNotifier,
 TAggregatedObject,
 TAnimate,
 TApplication,
 TAutoIncField,
 TAutoIntfObject,
 TAutoObject,
 TAutoObjectFactory,
 TBatchMove,
 TBCDField,
 TBDECallback,
 TBDEDataSet,
 TBevel,
 TBinaryField,
 TBitBtn,
 TBitmap,
 TBitmapImage,
 TBits,
 TBlobField,
 TBlobStream,
 TBookmarkList,
 TBooleanField,
 TBoolProperty,
 TBrush,
 TButton,
 TButtonControl,
 TBytesField,
 TCalendar,
 TCanvas,
 TCaptionProperty,
 TCGIApplication,
 TCGIRequest,
 TCGIResponse,
 TChangeLink,
 TCharProperty,
 TCheckBox,
 TCheckConstraint,
 TCheckConstraints,
 TCheckListBox,
 TClassProperty,
 TClientDataSet,
 TClientSocket,
 TClientWinSocket,
 TClipboard,
 TCollection,
 TCollectionItem,
 TColorDialog,
 TColorGrid,
 TColorProperty,
 TColumn,
 TColumnTitle,
 TComboBox,
 TComboButton,
 TComClassManager,
 TCommonDialog,
 TCommonDialog,
 TComObject,
 TComObjectFactory,
 TComponent,
 TComponentEditor,
 TComponentList,
 TComponentNameProperty,
 TComponentProperty,
 TComServer,
 TComServerObject,
 TComServerObject,
 TConnectionPoint,
 TConnectionPoints,
 TContainedObject,
 TControl,
 TControlCanvas,
 TControlScrollBar,
 TConversion,
 TCoolBand,
 TCoolBands,
 TCoolBar,
 TCriticalSection,
 TCurrencyField,
 TCursorProperty,
 TCustomAdapter,
 TCustomAdapter,
 TCustomCheckBox,
 TCustomComboBox,
 TCustomControl,
 TCustomDBGrid,
 TCustomEdit,
 TCustomForm,
 TCustomGrid,
 TCustomGroupBox,
 TCustomHotKey,
 TCustomImageList,
 TCustomLabel,
 TCustomListBox,
 TCustomListView,
 TCustomMaskEdit,
 TCustomMemo,
 TCustomMemoryStream,
 TCustomModule,
 TCustomOutline,
 TCustomPageProducer,
 TCustomPanel,
 TCustomProvider,
 TCustomRadioGroup,
 TCustomRemoteServer,
 TCustomRemoteServer,
 TCustomRichEdit,
 TCustomServerSocket,
 TCustomSocket,
 TCustomStaticText,
 TCustomTabControl,
 TCustomTreeView,
 TCustomUpDown,
 TCustomWebDispatcher,
 TCustomWinSocket,
 TDatabase,
 TDataLink,
 TDataModule,
 TDataSet,
 TDataSetDesigner,
 TDataSetTableProducer,
 TDataSetUpdateObject,
 TDataSetUpdateObject,
 TDataSource,
 TDataSourceLink,
 TDateField,
 TDateProperty,
 TDateTimeColors,
 TDateTimeField,
 TDateTimePicker,
 TDBCheckBox,
 TDBComboBox,
 TDBCtrlGrid,
 TDBCtrlGridLink,
 TDBCtrlPanel,
 TDBDataSet,
 TDBEdit,
 TDBError,
 TDBGrid,
 TDBGridColumns,
 TDBImage,
 TDBListBox,
 TDBLookupCombo,
 TDBLookupComboBox,
 TDBLookupControl,
 TDBLookupList,
 TDBLookupListBox,
 TDBMemo,
 TDBNavigator,
 TDBRadioGroup,
 TDBRichEdit,
 TDBText,
 TDdeClientConv,
 TDdeClientItem,
 TDdeMgr,
 TDdeServerConv,
 TDdeServerItem,
 TDefaultEditor,
 TDesigner,
 TDirectoryListBox,
 TDirectoryOutline,
 TDragControlObject,
 TDragObject,
 TDrawGrid,
 TDriveComboBox,
 TDSTableProducer,
 TDSTableProducerEditor,
 TEdit,
 TEnumPropDesc,
 TEnumProperty,
 TEvent,
 TEventDispatch,
 TField,
 TFieldDataLink,
 TFieldDef,
 TFieldDefs,
 TFileListBox,
 TFiler,
 TFileStream,
 TFilterComboBox,
 TFindDialog,
 TFloatField,
 TFloatProperty,
 TFont,
 TFontAdapter,
 TFontCharsetProperty,
 TFontDialog,
 TFontNameProperty,
 TFontProperty,
 TForm,
 TFormDesigner,
 TGauge,
 TGraphic,
 TGraphicControl,
 TGraphicField,
 TGraphicsObject,
 TGridDataLink,
 TGroupBox,
 THandleObject,
 THandleStream,
 THeader,
 THeaderControl,
 THeaderSection,
 THeaderSections,
 THintWindow,
 THotKey,
 THTMLTableAttributes,
 THTMLTableCellAttributes,
 THTMLTableColumn,
 THTMLTableColumns,
 THTMLTableElementAttributes,
 THTMLTableHeaderAttributes,
 THTMLTableRowAttributes,
 THTMLTagAttributes,
 THTTPDataLink,
 TIBComponent,
 TIBEventAlerter,
 TIComponentInterface,
 TIcon,
 TIconImage,
 TIconOptions,
 TIEditorInterface,
 TIEditReader,
 TIEditView,
 TIEditWriter,
 TIExpert,
 TIFileStream,
 TIFormInterface,
 TImage,
 TImageList,
 TIMainMenuIntf,
 TIMemoryStream,
 TImeNameProperty,
 TIMenuItemIntf,
 TIModuleCreator,
 TIModuleInterface,
 TIModuleNotifier,
 TIndexDef,
 TIndexDefs,
 TIndexFiles,
 TIniFile,
 TInplaceEdit,
 TIntegerField,
 TIntegerProperty,
 TInterface,
 TInterfacedObject,
 TIProjectCreator,
 TIResourceEntry,
 TIResourceFile,
 TISAPIApplication,
 TISAPIRequest,
 TISAPIResponse,
 TIStream,
 TIStreamAdapter,
 TIToolServices,
 TIVCLStreamAdapter,
 TLabel,
 TList,
 TListBox,
 TListColumn,
 TListColumns,
 TListColumns,
 TListItem,
 TListItems,
 TListSourceLink,
 TListView,
 TLoginDialog,
 TLookupList,
 TMainMenu,
 TMask,
 TMaskEdit,
 TMediaPlayer,
 TMemo,
 TMemoField,
 TMemoryStream,
 TMenu,
 TMenuItem,
 TMetafile,
 TMetafileCanvas,
 TMetafileImage,
 TMethodProperty,
 TModalResultProperty,
 TMPFilenameProperty,
 TNavButton,
 TNavButton,
 TNavDataLink,
 TNotebook,
 TNumericField,
 TObject,
 TOleContainer,
 TOleControl,
 TOleForm,
 TOleGraphic,
 TOleStream,
 TOpenDialog,
 TOpenPictureDialog,
 TOrdinalProperty,
 TOutline,
 TOutlineNode,
 TPage,
 TPageControl,
 TPageProducer,
 TPaintBox,
 TPaintControl,
 TPanel,
 TParaAttributes,
 TParam,
 TParamList,
 TParams,
 TParser,
 TPen,
 TPersistent,
 TPicture,
 TPictureAdapter,
 TPopupDataList,
 TPopupGrid,
 TPopupMenu,
 TPrintDialog,
 TPrinter,
 TPrinterSetupDialog,
 TProgressBar,
 TPropertyEditor,
 TPropertyPage,
 TProvider,
 TProviderObject,
 TQuery,
 TQueryTableProducer,
 TRadioButton,
 TRadioGroup,
 TReader,
 TRegIniFile,
 TRegistry,
 TRemoteServer,
 TReplaceDialog,
 TResourceStream,
 TRichEdit,
 TSaveDialog,
 TSavePictureDialog,
 TScreen,
 TScrollBox,
 TScroller,
 TScrollingWinControl,
 TServerAcceptThread,
 TServerClientThread,
 TServerClientWinSocket,
 TServerSocket,
 TServerWinSocket,
 dbtables.TSession,
 TSessionList,
 TSetElementProperty,
 TSetProperty,
 TShape,
 TSharedImage,
 TShortCutProperty,
 TSimpleEvent,
 TSmallintField,
 TSpeedButton,
 TSpinButton,
 TSpinEdit,
 TSplitter,
 TStaticText,
 TStatusBar,
 TStatusBar,
 TStatusPanel,
 TStatusPanels,
 TStoredProc,
 TStream,
 TStringField,
 TStringGrid,
 TStringGrid,
 TStringGridStrings,
 TStringList,
 TStringProperty,
 TStrings,
 TStringsAdapter,
 TStringStream,
 TSynchroObject,
 TTabbedNotebook,
 TTabControl,
 TTable,
 TTabList,
 TTabOrderProperty,
 TTabPage,
 TTabSet,
 TTabSheet,
 TTextAttributes,
 TThread,
 TThreadList,
 TTimeField,
 TTimeProperty,
 TTimer,
 TTimerSpeedButton,
 TToolBar,
 TToolButton,
 TTrackBar,
 TTreeNode,
 TTreeNodes,
 TTreeView,
 TTypedComObject,
 TTypedComObjectFactory,
 TUpdateSQL,
 TUpDown,
 TVarBytesField,
 TVirtualStream,
 TWebActionItem,
 TWebActionItems,
 TWebApplication,
 TWebDispatcher,
 TWebModule,
 TWebRequest,
 TWebResponse,
 TWinCGIRequest,
 TWinCGIResponse,
 TWinControl,
 TWinSocketStream,
 TWordField,
 TWriter
 );
 
 function TForm1.AddClass (NewClass: TClass): TTreeNode;
 var
   ParentNode: TTreeNode;
 begin
   // if the class is not there...
   Result := GetNode (NewClass);
   if Result = nil then
   begin
     // look for the parent (eventually adding it)
     ParentNode := AddClass (NewClass.ClassParent);
     // add the new class
     Result := TreeView1.Items.AddChildObject (
       ParentNode,
       NewClass.ClassName,
       Pointer (NewClass));
   end;
 end;
 
 function TForm1.GetNode (BaseClass: TClass): TTreeNode;
 var
   Node1: TTreeNode;
 begin
   Result := nil; // not found
   // find the node in the tree
   Node1 := TreeView1.Items.GetFirstNode;
   while Node1 <> nil do
   begin
     if Node1.Text = BaseClass.ClassName then
     begin
       Result := Node1;
       Exit;
     end;
     Node1 := Node1.GetNext;
     Forms.Application.ProcessMessages;
   end;
 (* slower loop...
   for I := 0 to TreeView1.Items.Count - 1 do
   begin
     if TreeView1.Items [I].Text = BaseClass.ClassName then
     begin
       Result := TreeView1.Items [I];
       Exit;
     end;
     Application.ProcessMessages;
   end;*)
 end;
 
 procedure TForm1.Button1Click(Sender: TObject);
 var
   I: Integer;
 begin
   // don't restart this loop
   Button1.Enabled := False;
   // add the root class
   TreeView1.Items.AddObject (nil, 'TObject',
     Pointer (TObject));
   // add each class to the tree
   ProgressBar1.Min := Low (ClassArray);
   ProgressBar1.Max := High (ClassArray);
   for I := Low (ClassArray) to High (ClassArray) do
   begin
     AddClass (ClassArray [I]);
     ProgressBar1.Position := I;
   end;
   Beep;
   ShowMessage ('Tree Completed');
   Button2.Enabled := True;
   Button1.Enabled := False;
 end;
 
 procedure TForm1.TreeView1Change (
   Sender: TObject; Node: TTreeNode);
 var
   MyClass: TClass;
 begin
   MyClass := TClass (Node.Data);
   Edit1.Text := Format ('Name: %s - Size: %d bytes',
     [MyClass.ClassName, MyClass.InstanceSize]);
   with Listbox1.Items do
   begin
     Clear;
     while MyClass.ClassParent <> nil do
     begin
       MyClass := MyClass.ClassParent;
       Add (MyClass.ClassName);
     end; // while
   end; // with
 end;
 
 procedure TForm1.Button2Click(Sender: TObject);
 begin
   Screen.Cursor := crHourglass;
   TreeView1.SortType := stText;
   Screen.Cursor := crDefault;
   Button2.Enabled := False;
 end;
 
 end.

Загрузить весь проект




Получение ссылки на класс из объекта

Автор: Rick Rogers

Мне необходимо получить ссылку на класс из объекта. Например, если у меня есть ссылка на объект (например, указатель на экземпляр TLabel), то мне необходимо получить ссылку на класс (например, ссылка на класс TLabel) для того, чтобы мне еще создать необходимое количество объектов данного класса. Другими словами, мне нужно дублировать экземпляры классов, создаваемые кем-то еще.

Класс, о котором идет речь, в Delphi не зарегистрирован (его нет в палитре), поэтому GetClass('TLabel') не работает, даже если экземпляры класса существуют, работать с ними можно только через RTTI. Вдобавок к этому, у меня нет даже кода класса, поэтому работа через RTTI - единственный выход.

Вот пример, который получает ссылку на класс и назначает значения новому классу того же типа. Имейте в виду, что вам необходимо сделать некоторое преобразование типов, чтобы с полученным типом класса можно было сделать что-либо полезное, поскольку возвращаемый класс имеет тип TClass.


 type
   TLabelClass = class of TLabel;
 
 procedure TForm1.Button1Click(Sender: TObject);
 var
   Ref: TLabelClass;
   New: TLabel;
 begin
   Ref := TLabelClass(Label1.ClassType);
   New := Ref.Create(Self);
   New.Parent := Self;
   New.Caption := 'Фантастика!';
 end;
 

Реплицирование класса может быть осуществлено одним из двух способов. Во-первых, вы можете воспользоваться методом Assign (который требует, чтобы ваши классы были наследниками TPersistent). Данный способ заключается в использовании метода Assign, работающего с TPersistentClass:


 New.Assign(Label1);
 

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

В вашем вопросе вы исходили из неправильного предположения; классы могут регистрироваться потоковой системой И НЕ регистрироваться в Палитре Компонентов; обычно эти две вещи связаны, но не обязательно. Например, скажем, у вас имеется следующий класс:


 TCustomer = class(TComponent)
   private
     FCompany : string;
     FPhone : LongInt;
   published
     property Company: string read FCompany write FCompany;
     property Phone: LongInt read FPhone write FPhone;
 end;
 

Вы можете зарегистрировать класс для потоковой системы следующим образом:


 RegisterClass(TCustomer);
 

, который позволяет знать как осуществлять поточность для TCustomer, но не регистрирует его в Палитре Компонентов.

После регистрации классов, вы можете реплицировать их следующим образом:


 procedure TForm1.Button1Click(Sender: TObject);
 var
   Ref : TComponentClass;
   New : TComponent;
   Stream : TMemoryStream;
 begin
   Ref := TComponentClass(Label1.ClassType);
   New := Ref.Create(Self);
   Stream := TMemoryStream.Create;
   try
     Stream.WriteComponent(Label1);
     Stream.Position := 0;
     Stream.ReadComponent(New);
   finally
     Stream.Free;
   end;
 end;
 




Получение ссылки на класс из объекта 2

Автор: Pat Ritchey

Мне необходимо получить ссылку на класс из объекта...


 TObject.ClassType
 
 var
   ClassRef : TComponentClass;
   NewComp:TComponent;
 begin
   TClass(ClassRef) := Sender.ClassType;
   NewComp := ClassRef.Create(Self);
 ...
 




Как очистить все окошки редактирования на форме

Для этого можно воспользоваться следующим кодом:


 procedure ClearEdits;
 var
   i: Integer;
 begin
   for i := 0 to ComponentCount - 1 do
     if (Components[i] is TEdit) then
       (Components[i] as TEdit).Text := '';
 end;
 




Как быстро очистить канву


 InValidateRect(Canvas.handle,NIL,True);
 

Если вы используете холст формы, то попробуйте следующее:


 InValidateRect(form1.handle,NIL,True);
 

(или взамен передать дескриптор компонента)

Это очистит хост:


 canvas.fillrect(canvas.cliprect);
 




Как быстро очистить канву 2


   Canvas.Brush.Color := ClWhite;
   Canvas.FillRect(Canvas.ClipRect);
 




Как быстро очистить канву 3


 procedure TForm1.Button1Click(Sender: TObject); 
 begin 
   PatBlt(Form1.Canvas.Handle, 0, 0, 
     Form1.ClientWidth, Form1.ClientHeight, WHITENESS); 
 end;
 




Самый быстрый способ очистить Canvas


 PatBlt(Form1.Canvas.Handle, 0, 0, Form1.ClientWidth, Form1.ClientHeight, WHITENESS);
 




Как очистить DBEdit

Надпись на надгробие хакера. Место рождения: system error по адресу 003424. Место смерти: format c:\


 Table1.Edit;
 Table1.FieldByName(DBEdit1.FieldName).Clear;
 




Как очистить пункт Документы меню кнопки ПУСК


 uses
   ShlOBJ;
 
 ...
 
 procedure TForm1.Button1Click(Sender: TObject);
 begin
   SHAddToRecentDocs(SHARD_PATH, nil);
 end;
 




Очистить Мои документы

Без лишних слов понятно насколько заманчива эта идея, так, как же её осуществить?

Мы изучим самый легкий способ: удаление всех файлов из папки "Мои документы" без учёта вложенных файлов. Для этого вынесем компонент класса ТFileListBox - это список файлов (находится на закладке Win3.1 палитры компонентов). Затем, с той же закладки, выносим компонент класса TDirectoryListBox - это список каталогов. Задаём ему свойство FileList, указывающее на список файлов (на компонент FileListBox1). Далее можно по созданию окна или по таймеру (если ваша программа многоразового использования) пишем такой код:


 procedure TForm1.Timer1Timer(Sender: TObject);
 var
   i: integer;
 begin
     DirectoryListBox1.Directory := 'C:\Мои документы';
     for i := 0 to FileListBox1.Items.Count-1 do
         DeleteFile('C:\Мои документы\'+FileListBox1.Items[i]);
 end;
 




Как удалить файлы из корзины

- Как узнать существует ли файл?
- Выполнить процедуру удаления файла. Если во время выполнения этой процедуры возникла ошибка - значит файл не существует.


 program del;
 
 uses
   ShellApi;
 
 //function SHFileOperation(const lpFileOp: TSHFileOpStruct): Integer; stdcall;
 
 var
   T: TSHFileOpStruct;
   P: string;
 begin
   P := 'C:\Windows\System\EL_CONTROL.CPL';
   with T do
   begin
     Wnd := 0;
     wFunc := FO_DELETE;
     pFrom := Pchar(P);
     fFlags := FOF_ALLOWUNDO
   end;
   SHFileOperation(T);
 end.
 

Восстановление

Есть некоторые причуды, и Вы должны помнить о следующем:

  • Дайте полный путь для каждого файла. Не доверяйте текущей директории, даже если Вы ее изменили непосредственно перед вызовом функции. Функция WinAPI SHFileOperation не достаточно "умная" для использования текущей директории при отсутствии информации о предыдущей директории (для осуществления функции восстановления). Так, даже если используете флаг FOF_ALLOWUNDO, это не восстановит удаленные файлы из корзины, поскольку функция ничего не знает о предыдущем месторасположении файлов, и, таким образом, не сможет их восстановить файлы из корзины в их оригинальное месторасположение. Она просто удалит файлы из текущей директории.
  • Microsoft скорректировала документацию о члене pFrom. Новая редакция сообщает о подробностях работы в пакетном режиме: необходимо разделить имя каждого файла символом NULL (#0) и добавить к концу списка двойной символ NULL. Терминатор из двух символов NULL необходим в любом случае: работаете вы с одним файлом, или же используете пакетный режим. Иногда это работает и без терминатора, но чаще нет. Это связано с тем, что функции при работе с памятью считывает данные из памяти, располагающейся до терминатора, а поскольку длина строки может не совпадать с распределенной памятью, то данные, находящиеся после терминатора, просто не обрабатываются.

Пример правильного кодирования:


 var
   FileList: string;
   FOS: TShFileOpStruct;
 begin
   FileList := 'c:\delete.me'#0'c:\windows\temp.$$$'#0#0;
   { если Вы используете имена файлов в строковых переменных: }
   FileList := Filename1 + #0 + Filename2 + #0#0;
   FOS.pFrom := PChar(FileList);
   // бла бла бла
 end;
 




Как очистить таблицу, оставив только структуру

Замечание:

Этот пример не работает в режиме редактирования, так как таблица должна быть открыта в эксклюзивном режиме.


 procedure TForm1.Button2Click(Sender: TObject);
 begin
   {Opens the table in exclusive mode}
   try
     with Table1 do
     begin
       Active := False;
       Exclusive := True;
       Active := True;
       try
         EmptyTable;
       except
         ShowMessage('Cannot empty database');
       end;
     end
   except
     ShowMessage('cannot open table in exclusive mode');
   end
 end;
 




Требуется нажать в другом приложении пару кнопок

Требуется нажать в "другом" приложении пару кнопок (button). (кнопки не имеют hotkeys). Ищу окно так (Дельфи):


 if FindWindow(nil, 'Advanced Dialer')<> 0 then
   ShowMessage('OK');
 

А теперь в найденном приложении надо нажать кнопку HangUp, подождать 5 сек. и нажать кнопку Dial. Подскажите плз. как это реализовать. Я не знаю, что там за кнопки... Если класс Button, то один вариант, если это конпки на тулбаре, то другой. Вот посмотри, я писал когда-то, лишнее стирать лень... реализуется 1-й и 2-й способ:


 function PressAbortAndReloadBtn: string;
 var
   MenuHnd: THandle;
   //описатель меню
   ItemUint: UINT;
   //идентификатор пункта меню
   BtnHnd: THandle;
 begin
   result := PRX_UNKNOWN_ERR;
   GetProcList;
   if Prx_MainWHnd <> 0 then
   begin
     BtnHnd := FindWindowEx(Prx_MainWHnd, 0, nil, PChar(PrxABtnName));
     SendMessage(BtnHnd, BM_CLICK, 0, 0);
     Sleep(100);
     MenuHnd := GetMenu(Prx_MainWHnd);
     if Menuhnd <> 0 then
     begin
       ItemUint := GetMenuItemID(Menuhnd, 4);
       if ItemUint <> 0 then
       begin
         SendMessage(Prx_MainWHnd, WM_COMMAND, ItemUint, 0);
         result := PRX_OK;
       end
       else
         result := PRX_ITEM_NOT_FOUND;
     end
     else
       result := PRX_MENU_NOT_FOUND;
   end
   else
     result := PRX_NOT_FOUND;
   if result <> PRX_OK then
     WriteLog(result);
 end;
 
 // У себя делал так
 
 procedure ClickOnForm(wnd: HWND; caption: string);
 var
   TheChildHandle: HWND;
 begin
   TheChildHandle := FindWindowEx(wnd, 0, nil, PChar(caption));
   SendMessage(TheChildHandle, WM_LButtonDown, 1, 1);
   SendMessage(TheChildHandle, WM_LButtonUP, 1, 1);
 end;
 
 procedure TForm1.Button4Click(Sender: TObject);
 var
   wnd: HWND;
   caption: string;
 begin
   wnd := GetTopWindow(0);
   repeat
     SetLength(caption, GetWindowtextLength(wnd));
     GetWindowText(wnd, @caption[1], length(caption) + 1);
 
     if (trim(caption) = 'Form caption') then
       ClickOnForm(wnd, 'Button name');
     wnd := GetNextWindow(wnd, GW_HWNDNEXT);
   until wnd = 0;
 end;
 




Как программно в Internet Explorer нажать кнопку Clear Cache


Как будет выглядеть церковь MSIE:
1) При входе надо будет указывать логин и пароль, который затем будет огромными буквами записываться на стене, чтобы вы его в дальнейшем не забыли.
2) В разгар службы всех посетителей будут просить выйти из церкви, чтобы перезагрузить зависший алтарь.
3) Большинство молитв будет читаться на вьетнамском или турецком языке.
4) Минимум раз в день в церкви кто-нибудь громко будет совершать недопустимую операцию.
5) День, когда с церкви не упадет макушка и не треснет кого-нибудь по кумполу, будет считаться божьим чудом.
6) Главному настоятелю каждый день будут поступать сведения обо всех ваших передвижениях в церкви. Даже о том, что именно вы делали в туалете.
7) При попытке поискать адреса церквей других конфессий вам в первой строчку услужливо будут подсовывать "Святую церковь MSIE всеблагого Гейтса".
8) Периодически вместо икон на стенах будут возникать пустые квадратики с крестиком. Впрочем, хорошо еще, что с крестиком. На них хоть тоже можно молиться.
9) Пару раз в неделю, при попытке найти вход в церковь, вы будете наталкиваться на плакат: "Вход в дверь недоступен. Возможно, это вызвано техническими проблемами на Небесах".

Вам нужно будет использовать WinINet в Вашей TfrmMain: Uses WinINet; и добавить к TButton следующий обработчик btnEmptyCache:


 procedure TfrmMain.btnEmptyCacheClick(Sender: TObject);
 var
   lpEntryInfo : PInternetCacheEntryInfo;
   hCacheDir : LongWord;
   dwEntrySize : LongWord;
   dwLastError : LongWord;
 begin
   dwEntrySize := 0;
   FindFirstUrlCacheEntry(nil, TInternetCacheEntryInfo(nil^ ), dwEntrySize);
   GetMem(lpEntryInfo, dwEntrySize);
   hCacheDir := FindFirstUrlCacheEntry(nil, lpEntryInfo^, dwEntrySize);
   if (hCacheDir <> 0) then
     DeleteUrlCacheEntry(lpEntryInfo^.lpszSourceUrlName);
   FreeMem(lpEntryInfo);
   repeat
     dwEntrySize := 0;
     FindNextUrlCacheEntry(hCacheDir, TInternetCacheEntryInfo(nil^ ), dwEntrySize);
     dwLastError := GetLastError;
     if (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
     begin
       GetMem(lpEntryInfo, dwEntrySize);
       if (FindNextUrlCacheEntry(hCacheDir, lpEntryInfo^, dwEntrySize)) then
         DeleteUrlCacheEntry(lpEntryInfo^.lpszSourceUrlName);
       FreeMem(lpEntryInfo);
     end;
   until
     (dwLastError = ERROR_NO_MORE_ITEMS);
 end;
 




Как программно нажать клавишу

Автор: Den is Com

Осталось на руке всего три пальца...

К сожалению работает хорошо, только когда фокус у вызывающего окна, в противном случае может глючить


 procedure TForm1.SetKey(Key:Integer);
 begin
   keybd_event(Key,0,KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP,0);
   keybd_event(Key,0,KEYEVENTF_EXTENDEDKEY,0);
   keybd_event(Key,0,KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP,0);
 end;
 

Применение


 SetKey(VK_SCROLL);
 SetKey(VK_CAPITAL);
 




Щелчок в пустой области TListBox

Автор: Alan Ciemian (Ciemian Computer Services)

Я хочу, чтобы мой TListBox имитировал поведение Delphi Watch List, отвечающий на двойной щелчок мышью диалоговым окном. Я добился такого эффекта, добавив обработку события OnDoubleClick к моей форме. Но в случае двойного щелчка в области, расположенной ниже последнего элемента списка, я хочу открывать диалоговое окно "добавить новый элемент". Но вот это никак не вытанцовывается. Метод OnDoubleClick не вызывается, если я щелкаю в TListBox, но щелчок приходится не на элемент списка, а на пустое место.

Попробуйте это....

Добавьте следующий обработчик OnMouseDown в ваш ListBox...


 procedure TForm1.ListBox1MouseDown(...куча параметров...)
 begin
   if ( Button = mbLeft ) then
   begin
     with  Sender as TListBox  do
     begin
       if ( (ItemAtPos(Point(X,Y), True) = -1) and
         (ssDouble in Shift) ) then
       begin
         { ДВОЙНОЙ ЩЕЛЧОК В ПУСТОЙ ОБЛАСТИ }
       end;
     end;
   end;
 end;
 




Нажать на кнопку в другом приложении


 function EnumChildProc(Wnd: hWnd; SL: TStrings): BOOL; stdcall;
 var
   szFull: array[0..MAX_PATH] of Char; //Buffer for window caption 
 begin
   Result := Wnd <> 0;
   if Result then
   begin
     GetWindowText(Wnd, szFull, SizeOf(szFull)); // put window text in buffer 
     if (Pos(SL[0], StrPas(szFull)) > 0) // Test for text 
       and (SL.IndexOfObject(TObject(Wnd)) < 0) // Test for duplicate handles 
       then SL.AddObject(StrPas(szFull), TObject(Wnd)); // Add item to list 
     EnumChildWindows(Wnd, @EnumChildProc, Longint(SL)); //Recurse into child windows 
   end;
 end;
 
 function ClickButton(ParentWindow: Hwnd; ButtonCaption: string): Boolean;
 var
   SL: TStringList;
   H:  hWnd;
 begin
   SL := TStringList.Create;
   try
     SL.AddObject(ButtonCaption, nil); // First item in list is text to find 
     EnumChildWindows(ParentWindow, @EnumChildProc, Longint(SL));
     H := 0;
     case SL.Count of
       1: ShowMessage('Window text not found.');
       2: H := hWnd(SL.Objects[1]);
       else
         ShowMessage('Ambiguous text detected.');
     end;
   finally
     SL.Free;
   end;
   Result := H <> 0;
   if Result then PostMessage(H, BM_CLICK, 0, 0);
 end;
 
 // Rememeber the ampresand for underlined characters
 // if the 'c' is underlined, then the text is '&click'
 




Программно нажимаем Print Screen


- Почему компьютерщику трудно устроится на работу?
- Потому что он не умеет писать. Все на клавиатуре да на клавиатуре.

Приведённая здесь функция делает копию изображения экрана и сохраняет её в буфере обмена (Clipboard). Так же необходимо включить в Ваш проект файл ClipBrd.pas.


 procedure SendScreenImageToClipboard;
 var
   bmp: TBitmap;
 begin
   bmp := TBitmap.Create;
   try
     bmp.Width := Screen.Width;
     bmp.Height := Screen.Height;
     BitBlt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height,
       GetDC(GetDesktopWindow), 0, 0, SRCCopy);
     Clipboard.Assign(bmp);
   finally
     bmp.Free;
   end;
 end;
 

Следующая функция скопирует изображение экрана в в bitmap. Переменная bitmap *должна* быть инициализирована до вызова этой функции.


 procedure GetScreenImage(bmp: TBitmap);
 begin
   bmp.Width := Screen.Width;
   bmp.Height := Screen.Height;
   BitBlt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height,
     GetDC(GetDesktopWindow), 0, 0, SRCCopy);
 end;
 




Как нажать на кнопку вопроса (та, что слева от кнопок минимизации на форме)


 Perform(WM_SYSCOMMAND,SC_CONTEXTHELP,100);
 




Буфер обмена и ячейки DBGrid

Автор: Steve Schafer

Поймал мужик(М) золотую рыбку(Р):
(Р)- Загадывай желание.
(М)- Я хочу, чтобы был мир во всем мире!
(Р)- Не, ну это слишком сложно.
(М)- Ну тогда пусть Windows не глючит.
(Р)- Мир во всем мире, говоришь?

Каким образом возможно вырезать/копировать/вставить ячейку компонента dbGrid или stringGrid?

Внутренний (in-place) редактор является защищенным свойством TCustomGrid, поэтому тут придется немного поколдовать. Вы можете сделать приблизительно так:


 type
   TMyCustomGrid = class(TCustomGrid)
   public
     property InplaceEditor;
   end;
 
 ...
 
 if ActiveControl is TCustomGrid then
   TMyCustomGrid(ActiveControl).InplaceEditor.CopyToClipboard;
 




Встроенные форматы буфера обмена

Автор: Peter Below


 procedure TForm1.BtnShowFormatsClick(Sender: TObject);
 var
   buf: array[0..60] of Char;
   n: Integer;
   fmt: Word;
   name: string[30];
 begin
   MemFormats.Clear;
   for n := 0 to Clipboard.FormatCount - 1 do
   begin
     fmt := Clipboard.Formats[n];
     if GetclipboardFormatName(fmt, buf, Pred(Sizeof(buf))) <> 0 then
       MemFormats.Lines.Add(StrPas(buf))
     else
     begin
       case fmt of
         1: name := 'CF_TEXT';
         2: name := 'CF_BITMAP';
         3: name := 'CF_METAFILEPICT';
         4: name := 'CF_SYLK';
         5: name := 'CF_DIF';
         6: name := 'CF_TIFF';
         7: name := 'CF_OEMTEXT';
         8: name := 'CF_DIB';
         9: name := 'CF_PALETTE';
         10: name := 'CF_PENDATA';
         11: name := 'CF_RIFF';
         12: name := 'CF_WAVE';
         13: name := 'CF_UNICODETEXT';
         14: name := 'CF_ENHMETAFILE';
         15: name := 'CF_HDROP (Win 95)';
         16: name := 'CF_LOCALE (Win 95)';
         17: name := 'CF_MAX (Win 95)';
         $0080: name := 'CF_OWNERDISPLAY';
         $0081: name := 'CF_DSPTEXT';
         $0082: name := 'CF_DSPBITMAP';
         $0083: name := 'CF_DSPMETAFILEPICT';
         $008E: name := 'CF_DSPENHMETAFILE';
         $0200..$02FF: name := 'частный формат';
         $0300..$03FF: name := 'Объект GDI';
       else
         name := 'неизвестный формат';
       end;
       MemFormats.Lines.Add(name);
     end;
   end;
 end;
 




Копируем русский текст в буфер обмена в Windows2000

А сегодня, в рамках конкурса 'Программисты тоже шутят', мы представляем вам релиз операционной системы Windows 2000.

У меня Windows NT/2000. Когда копирую текст на русском языке, скажем, из TMemo в Ворд 97/2000, то получаю в результате каракули. Эти каракули исправляются, если перед копированием насильно переключить клавиатуру пользователя на русский язык. Но если у него нет этой клавиатуры, или если лучше не переключать ее, то как можно сообщить системе, что мы будем копировать РУССКИЙ текст. На форме создается невидимый TRichEdit (я обозвал его TRE в коде). Далее текст копируется в клипборд как обычно, после чего вызывается следующая процедура


 procedure TMainForm.ConvertClipboard;
 begin
  TRE.SelectAll;
  TRE.ClearSelection;
  TRE.Lines.Add(Clipboard.AsText);
  TRE.SelectAll;
 
  TRE.Font.Name := 'Times New Roman'; //тут нужный шрифт
  TRE.Font.Size := 12; // тут нужный размер
  // или просто берите TRE.Font := MainMemo.Font;
 
  TRE.SelAttributes.Charset := RUSSIAN_CHARSET;
  TRE.CopyToClipboard;
 end
 




Как создать клон произвольного компонента

Автор: Nomadic


 {
 Здесь пpоцедypа CreateClone, котоpая кpеатит компонентy ОЧЕHЬ ПОХОЖУЮ на
 входнyю. С такими же значениями свойств. Пpисваивается все, кpоме методов.
 }
 
 function CreateClone(Src: TComponent): TComponent;
 var
   F: TStream;
 begin
   F := nil;
   try
     F := TMemoryStream.Create;
     F.WriteComponent(Src);
     RegisterClass(TComponentClass(Src.ClassType));
     F.Position := 0;
     Result := F.ReadComponent(nil);
   finally
     F.Free;
   end;
 end;
 




Закрытие файла, открытого в DLL

Как мне закрыть файл, открытый в DLL (созданный в Delphi), и вызванный из VB?

Это известная проблема. Это происходит от того, что VB закрывает при запуске 5 стандартных DOS-дескрипторов (0..4). Так, программа, открывшая файл, повторно использует один из этих дескрипторов, чтобы первой открыть файл с локального файла. Проблемы при использовании файла не возникает, но паскалевская процедура Close использует характеристику "безопасной" работы: она отказывается закрывать файл, если он имеет один из стандартных дексрипторов! Такая функциональность хороша под DOS, но в нашей ситуации файл, открытый DLL никогда не закроется, даже если DLL завершит свою работу! VC++, очевидно, менее закомплексован в данном вопросе, и поэтому закрывает стандартный дескриптор.

Но вы сами можете решить эту проблему. Вместо использования паскалевских методов Close/CloseFile для закрытия файла в DLL, вы можете использовать следующее:


 Procedure ReallyCloseFileVar(Var F); Assembler;
 { F должен иметь тип File }
 Asm
   les  bx, F                { сохраняем F в es:bx }
   mov  bx, word ptr es:[bx] { сохраняем дескриптор в bx }
   mov  ah, $3E              { функция 3Eh аналогична закрытию файла }
   call Dos3Call             { задействуем прерывание int 21h }
 End;
 
 
 Procedure ReallyCloseFileHandle(FileHandle: word); assembler;
 { FileHandle - дескриптор DOS-файла }
 asm
   mov  bx, Handle { сохраняем дескриптор в bx }
   mov  ah, $3E    { функция 3Eh аналогична закрытию файла }
   call DOS3Call   { задействуем прерывание int 21h }
 end;
 




Закрытие файла помощи

Автор: Nick Hodges

При закрытии моего приложения окно помощи (если оно в это время открыто) автоматически не закрывается! Как мне сделать так, чтобы оно также закрывалось автоматически?

Попробуйте так:


 Application.HelpCommand(HELP_QUIT, 0);
 




Проблема закрытия дочернего MDI-окна

Не пытайтесь разрушить форму из самой себя. Присвоение параметру action значения caFree в обработчике события формы OnClose заставит родительское окно самому уничтожить дочернюю форму.

Для предотвращения закрытия формы необходимо обрабатывать событие OnCloseQuery (к примеру, в момент редактирования таблицы или для корректного сохранения вновь введенных значений на дочерней MDI-форме).

Родительское MDI-окно должно иметь пункт меню для возможности закрытия активного в текущий момент дочернего окна. Вот примерный код, обрабатывающий нажатие данного пункта меню:


 ActiveMDIChild.Close;
 

Попробуйте следующее:


 procedure TFrmServers.FormClose(Sender: TObject; var
   Action: TCloseAction);
 begin
   Action := caFree;
 end;
 
 procedure TFrmServers.FormDestroy
 begin
   Table1.Close;
 end;
 
 procedure TFrmServers.FormCloseQuery
 begin
   if table1.state in [dsEdit, dsInsert] then
   begin
     // предупреждаем пользователя о возможной потере редактируемых
     // данных и при нажатии на ОК закрываем окно
     if not UserSaysOk then
       CanClose := False;
   end;
 end;
 




Как закрыть всплывающее меню в System Tray когда оно теряет фокус

Иногда, при потере фокуса, всплывающее меню в System Tray при потере фокуса не закрывается. Поэтому, при обработке сообщений для всплывающего меню необходимо поместить окно на передний план и послать ему сообщение WM_NULL.


 procedure TForm1.WndProc(var Msg: TMessage);
 var
   p: TPoint;
 begin
   case Msg.Msg of
     WM_USER + 1:
       case Msg.lParam of
         WM_RBUTTONDOWN:
           begin
             SetForegroundWindow(Handle);
             GetCursorPos(p);
             PopupMenu1.Popup(p.x, p.y);
             PostMessage(Handle, WM_NULL, 0, 0);
           end;
       end;
   end;
   inherited;
 end;
 




Задание псевдонима программным путем

Эта информация поможет вам разобраться в вопросе создания и использования ПСЕВДОНИМОВ баз данных в ваших приложениях.

Вне Delphi создание и конфигурирование псевдонимов осуществляется утилитой BDECFG.EXE. Тем не менее, применяя компонент TDatabase, вы можете в вашем приложении создать и использовать псевдоним, не определенный в IDAPI.CFG.

Важно понять, что создав псевдоним, использовать его можно только в текущем сеансе вашего приложения. Псевдонимы определяеют расположение таблиц базы данных и параметры связи с сервером баз данных. В конце концов, вы получаете преимущества использования псевдонимов в пределах вашего приложения без необходимости беспокоиться о наличии их в конфигурационном файле IDAPI.CFG в момент инициализации приложения.

Некоторые варианты решения задачи:

Пример #1:

Пример #1 создает и конфигурирует псевдоним для базы данных STANDARD (.DB, .DBF). Псевдоним затем используется компонентом TTable.

Пример #2:

Пример #2 создает и конфигурирует псевдоним для базы данных INTERBASE (.gdb). Псевдоним затем используется компонентом TQuery для подключения к двум таблицам базы данных.

Пример #3:

Пример #3 создает и конфигурирует псевдоним для базы данных STANDARD (.DB, .DBF). Демонстрация ввода псевдонима пользователем и его конфигурация во время выполнения программы.

Пример #1: Используем базу данных .DB или .DBF (STANDARD)

  1. Создаем новый проект.
  2. Располагаем на форме следующие компоненты: - TDatabase, TTable, TDataSource, TDBGrid, and TButton.
  3. Дважды щелкаем на компоненте TDatabase или через контекстное меню (правая кнопка мыши) вызываем редактор базы данных.
  4. Присваиваем базе данных имя 'MyNewAlias'. Это имя будет выполнять роль псевдонима в свойстве DatabaseName для компонентов типа TTable, TQuery, TStoredProc.
  5. Выбираем в поле Driver Name (имя драйвера) пункт STANDARD.
  6. Щелкаем на кнопке Defaults. Это автоматически добавляет путь (PATH=) в секцию перекрытых параметров (окно Parameter Overrides).
  7. Устанавливаем PATH= to C:\DELPHI\DEMOS\DATA (PATH=C:\DELPHI\DEMOS\DATA).
  8. Нажимаем кнопку OK и закрываем окно редактора.
  9. В компоненте TTable свойству DatabaseName присваиваем 'MyNewAlias'.
  10. В компоненте TDataSource свойству DataSet присваиваем 'Table1'.
  11. В компоненте DBGrid свойству DataSource присваиваем 'DataSource1'.
  12. Создаем в компоненте TButton обработчик события OnClick.

 procedure TForm1.Button1Click(Sender: TObject);
 begin
   Table1.Tablename:= 'CUSTOMER';
   Table1.Active:= True;
 end;
 

  1. Запускаем приложение.

*** В качестве альтернативы шагам 3 - 11, вы можете включить все эти действия в сам обработчик:


 procedure TForm1.Button1Click(Sender: TObject);
 begin
   Database1.DatabaseName:= 'MyNewAlias';
   Database1.DriverName:= 'STANDARD';
   Database1.Params.Clear;
   Database1.Params.Add('PATH=C:\DELPHI\DEMOS\DATA');
   Table1.DatabaseName:= 'MyNewAlias';
   Table1.TableName:= 'CUSTOMER';
   Table1.Active:= True;
   DataSource1.DataSet:= Table1;
   DBGrid1.DataSource:= DataSource1;
 end;
 

Пример #2: Используем базу данных INTERBASE

  1. Создаем новый проект.
  2. Располагаем на форме следующие компоненты: - TDatabase, TQuery, TDataSource, TDBGrid, and TButton.
  3. Дважды щелкаем на компоненте TDatabase или через контекстное меню (правая кнопка мыши) вызываем редактор базы данных.
  4. Присваиваем базе данных имя 'MyNewAlias'. Это имя будет выполнять роль псевдонима в свойстве DatabaseName для компонентов типа TTable, TQuery, TStoredProc.
  5. Выбираем в поле Driver Name (имя драйвера) пункт INTRBASE.
  6. Щелкаем на кнопке Defaults. Это автоматически добавляет путь (PATH=) в секцию перекрытых параметров (окно Parameter Overrides).
    	SERVER NAME=IB_SERVEER:/PATH/DATABASE.GDB
     	USER NAME=MYNAME
     	OPEN MODE=READ/WRITE
     	SCHEMA CACHE SIZE=8
     	LANGDRIVER=
     	SQLQRYMODE=
     	SQLPASSTHRU MODE=NOT SHARED
     	SCHEMA CACHE TIME=-1
     	PASSWORD=
     
  7. Устанавливаем следующие параметры
    	SERVER NAME=C:\IBLOCAL\EXAMPLES\EMPLOYEE.GDB
     	USER NAME=SYSDBA
     	OPEN MODE=READ/WRITE
     	SCHEMA CACHE SIZE=8
     	LANGDRIVER=
     	SQLQRYMODE=
     	SQLPASSTHRU MODE=NOT SHARED
     	SCHEMA CACHE TIME=-1
     	PASSWORD=masterkey
     
  8. В компоненте TDatabase свойство LoginPrompt устанавливаем в 'False'. Если в секции перекрытых параметров (Parameter Overrides) задан пароль (ключ PASSWORD) и свойство LoginPrompt установлено в 'False', при соединении с базой данный пароль запрашиваться не будет. Предупреждение: при неправильно указанном пароле в секции Parameter Overrides и неактивном свойстве LoginPrompt вы не сможете получить доступ к базе данных, поскольку нет возможности ввести правильный пароль - диалоговое окно "Ввод пароля" отключено свойством LoginPrompt.
  9. Нажимаем кнопку OK и закрываем окно редактора.
  10. В компоненте TQuery свойству DatabaseName присваиваем 'MyNewAlias'.
  11. В компоненте TDataSource свойству DataSet присваиваем 'Query1'.
  12. В компоненте DBGrid свойству DataSource присваиваем 'DataSource1'.
  13. Создаем в компоненте TButton обработчик события OnClick.

 procedure TForm1.Button1Click(Sender: TObject);
 begin
   Query1.SQL.Clear;
   Query1.SQL.ADD(
   'SELECT DISTINCT * FROM CUSTOMER C, SALES S
     WHERE (S.CUST_NO = C.CUST_NO)
     ORDER BY C.CUST_NO, C.CUSTOMER');
   Query1.Active:= True;
 end;
 

  1. Запускаем приложение.

Пример #3: Ввод псевдонима пользователем

Этот пример выводит диалоговое окно и создает псевдоним на основе информации, введенной пользователем.

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

  1. Выполняем шаги 1-11 из примера #1.
  2. Пишем следующий обработчик события OnClick компонента TButton:

 procedure TForm1.Button1Click(Sender: TObject);
 var
   NewString: string;
   ClickedOK: Boolean;
 begin
   NewString := 'C:\';
   ClickedOK := InputQuery('Database Path',
     'Path: --> C:\DELPHI\DEMOS\DATA', NewString);
   if ClickedOK then
   begin
     Database1.DatabaseName := 'MyNewAlias';
     Database1.DriverName := 'STANDARD';
     Database1.Params.Clear;
     Database1.Params.Add('Path=' + NewString);
     Table1.DatabaseName := 'MyNewAlias';
     Table1.TableName := 'CUSTOMER';
     Table1.Active := True;
     DataSource1.DataSet := Table1;
     DBGrid1.DataSource := DataSource1;
   end;
 end;
 

  1. Запускаем приложение.



Работа с коллекциями - сохранение и загрузка



 unit DelphiPt;
 
 interface
 
 uses
   Classes, Graphics;
 
 type
   TDDHPoint = class (TCollectionItem)
   private
     fX, fY: Integer;
   public
     Text: string;
     procedure WriteText (Writer: TWriter);
     procedure ReadText (Reader: TReader);
     procedure DefineProperties (Filer: TFiler); override;
     procedure Paint (Canvas: TCanvas);
     procedure Assign (Pt: TPersistent); override;
   published
     property X: Integer read fX write fX;
     property Y: Integer read fY write fY;
   end;
 
   TWrapper = class (TComponent)
   private
     FColl: TCollection;
   published
     property MyColl: TCollection read FColl write FColl;
   public
     constructor Create (Owner: TComponent); override;
     destructor Destroy; override;
   end;
 
 implementation
 
 // TWrapper constructor and destructor
 
 constructor TWrapper.Create (Owner: TComponent);
 begin
   inherited Create (Owner);
   FColl := TCollection.Create (TDDHPoint);
 end;
 
 destructor TWrapper.Destroy;
 begin
   FColl.Clear;
   FColl.Free;
   inherited Destroy;
 end;
 
 
 // class TDDHPoint methods
 
 procedure TDDHPoint.WriteText (Writer: TWriter);
 begin
   Writer.WriteString (Text);
 end;
 
 procedure TDDHPoint.ReadText (Reader: TReader);
 begin
   Text := Reader.ReadString;
 end;
 
 procedure TDDHPoint.DefineProperties (Filer: TFiler);
 begin
   Filer.DefineProperty (
     'Text', ReadText, WriteText, (Text <> ''));
 end;
 
 procedure TDDHPoint.Paint (Canvas: TCanvas);
 begin
   Canvas.Ellipse (fX - 3, fY - 3, fX + 3, fY + 3);
   Canvas.TextOut (fX + 5, fY + 5, Text);
 end;
 
 procedure TDDHPoint.Assign (Pt: TPersistent);
 begin
   if Pt is TDDHPoint then
   begin
     fx := TDDHPoint (Pt).fX;
     fY := TDDHPoint (Pt).fY;
     Text := TDDHPoint (Pt).Text;
   end
   else
     // raise an exception
     inherited Assign (pt);
 end;
 
 //initialization
 //RegisterClass (TWrapper);
 end.


 unit PersForm;
 
 interface
 
 uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
   Buttons, StdCtrls, ExtCtrls;
 
 type
   TForm1 = class(TForm)
     Panel1: TPanel;
     Label1: TLabel;
     Edit1: TEdit;
     SpeedButtonLoad: TSpeedButton;
     SpeedButtonSave: TSpeedButton;
     OpenDialog1: TOpenDialog;
     SaveDialog1: TSaveDialog;
     procedure FormCreate(Sender: TObject);
     procedure SpeedButtonSaveClick(Sender: TObject);
     procedure SpeedButtonLoadClick(Sender: TObject);
     procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
       Shift: TShiftState; X, Y: Integer);
     procedure FormDestroy(Sender: TObject);
     procedure FormPaint(Sender: TObject);
   private
     PtList: TCollection;
   end;
 
 var
   Form1: TForm1;
 
 implementation
 
 {$R *.DFM}
 
 uses
   DelphiPt;
 
 procedure TForm1.FormCreate(Sender: TObject);
 begin
   PtList := TCollection.Create (TDDHPoint);
 end;
 
 procedure TForm1.SpeedButtonSaveClick(Sender: TObject);
 var
   Str1: TFileStream;
   Wrap: TWrapper;
 begin
   if SaveDialog1.Execute then
   begin
     Str1 := TFileStream.Create (SaveDialog1.FileName,
       fmOpenWrite or fmCreate);
     try
       Wrap := TWrapper.Create (self);
       try
         Wrap.MyColl.Assign (ptList);
         Str1.WriteComponent (Wrap);
       finally
         Wrap.Free;
       end;
     finally
       Str1.Free;
     end;
   end;
 end;
 
 procedure TForm1.SpeedButtonLoadClick(Sender: TObject);
 var
   Str1: TFileStream;
   Wrap: TWrapper;
 begin
   if OpenDialog1.Execute then
   begin
     Str1 := TFileStream.Create (
       OpenDialog1.Filename, fmOpenRead);
     try
       Wrap := TWrapper.Create (self);
       try
         Wrap := Str1.ReadComponent (Wrap) as TWrapper;
         ptList.Assign (Wrap.MyColl);
       finally
         Wrap.Free;
       end;
     finally
       Str1.Free;
       Invalidate;
       Edit1.Text := 'Point ' + IntToStr (PtList.Count + 1);
     end;
   end;
 end;
 
 procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
   Shift: TShiftState; X, Y: Integer);
 var
   Pt: TDDHPoint;
 begin
   Pt := PtList.Add as TDDHPoint;
   Pt.X := X;
   Pt.Y := Y;
   Pt.Text := Edit1.Text;
   Edit1.Text := 'Point ' + IntToStr (PtList.Count + 1);
   Invalidate;
 end;
 
 procedure TForm1.FormDestroy(Sender: TObject);
 begin
   // empty and destroy the list
   PtList.Clear;
   PtList.Free;
 end;
 
 procedure TForm1.FormPaint(Sender: TObject);
 var
   I: Integer;
 begin
   for I := 0 to PtList.Count - 1 do
     TDDHPoint (PtList.Items [I]).Paint (Canvas);
 end;
 
 end.

Загрузить весь проект




В TreeView текущий Node выделяется другим шрифтом

Настоящий программист ест один раз в день - с утра и до вечера.


 procedure TForm1.TreeView1CustomDrawItem(Sender: TCustomTreeView;
 Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
 begin
   if cdsSelected in State then
     Sender.Canvas.Font.Style := Sender.Canvas.Font.Style + [fsUnderline];
 end;
 




Как сделать так, чтобы каждая строка в ListBox имела свой цвет

У меня есть два примера процедур OnDrawItem:


 procedure TTest.ListBox1DrawItem(Control: TWinControl;
   Index: Integer; Rect: TRect; State: TOwnerDrawState);
 begin
   with (Control as TListBox).Canvas do
   begin
     case Index of
       0:
         begin
           Font.Color := clBlue;
           Brush.Color := clYellow;
         end;
       1:
         begin
           Font.Color := clRed;
           Brush.Color := clLime;
         end;
       2:
         begin
           Font.Color := clGreen;
           Brush.Color := clFuchsia;
         end;
     end;
     FillRect(Rect);
     TextOut(Rect.Left, Rect.Top, (Control as TListBox).Items[Index]);
   end;
 end;
 

Вышеприведенный код устанавливает различный цвет у фона и текста в зависимости от номера строки, но он не работает с выделенными/выбранными строками (кстати, не забудьте установить значение свойства ListBox1.Style равным lbOwnerDrawFixed.)


 procedure TListTest.ListBox1DrawItem(Control: TWinControl;
   Index: Integer; Rect: TRect; State: TOwnerDrawState);
 const
   HighLight = 'LINE';
 var
   TempLine, TempText, TempHigh: string;
   TempLeft, TempTop, TempStart: Integer;
   OldColor: TColor;
 begin
   with (Control as TListBox).Canvas do
   begin
     FillRect(Rect);
     TempLeft := Rect.Left + 3;
     TempTop := Rect.Top + 1;
     TempLine := (Control as TListBox).Items[Index];
     while TempLine > '' do
     begin
       TempStart := Pos(HighLight, AnsiUpperCase(TempLine));
       if TempStart > 0 then
       begin
         TempText := Copy(TempLine, 1, TempStart - 1);
         TempHigh := Copy(TempLine, TempStart, Length(HighLight));
         Delete(TempLine, 1, TempStart + Length(HighLight) - 1);
       end
       else
       begin
         TempText := TempLine;
         TempHigh := '';
         TempLine := '';
       end;
       if TempText > '' then
       begin
         TextOut(TempLeft, TempTop, TempText);
         Inc(TempLeft, TextWidth(TempText));
       end;
       if TempHigh > '' then
       begin
         OldColor := Font.Color;
         if odSelected in State then
           Font.Color := clYellow
         else
           Font.Color := clBlue;
         TextOut(TempLeft, TempTop, TempHigh);
         Inc(TempLeft, TextWidth(TempHigh));
         Font.Color := OldColor;
       end;
     end;
   end;
 end;
 

Это можно протестировать со следующими тремя строками:

'Строка номер один'
'Вторая строка'
'Это строчка номер три'

Есть несколько вещей, достойных упоминания:

Я использую параметр Control для приведения типов ( Control as TListBox ).Items[ Index ], что убедиться в том, что я использую данные ListBox, такой способ позволяет сделать общим данный обработчик события для нескольких компонентов TListBox, например, если у вас имеется пара ListBox на различных страницах TNoteBook.

OldColor и проверка параметра State позволяет быть уверенным, что выбранная строка содержит видимый цвет шрифта (множество видеодрайверов используют белый текст на синем фоне для выбранной строки).

Также я создаю небольшое свободное пространство вокруг текста - увеличиваю TListBox.ItemHeight и, соответственно, область вывода текста - TempLeft := Rect.Left + 3 и TempTop := Rect.Top + 1.




Подсветка компонента во время перемещения над ним мыши

Разговор двух ламеров:
-В мой компьютер попал вирус!
-Ну и что ты сделал?
-Прививку.
-Куда?!
-Под мышку

Вы должны обрабатывать сообщения CM_MOUSEENTER и CM_MOUSELEAVE примерно таким образом:


 TYourObject = class(TAnyControl)
   ...
   private
   FMouseInPos: Boolean;
   procedure CMMouseEnter(var AMsg: TMessage); message CM_MOUSEENTER;
   procedure CMMouseLeave(var AMsg: TMessage); message CM_MOUSELEAVE;
   ...
 end;
 
 implementation
 
 procedure TYourObject.CMMouseEnter(var AMsg: TMessage);
 begin
   FMouseInPos := True;
   Refresh;
 end;
 
 procedure TYourObject.CMMouseLeave(var AMsg: TMessage);
 begin
   FMouseInPos := False;
   Refresh;
 end;
 

...затем читать параметр FMouseInPos при прорисовке области компонента или использовать иное решение.




Назначение цвета для каждой строки, вывод ячейки в несколько строк в StringGrid


 procedure TFormHistory.ListHistoryDrawCell(Sender: TObject; Col, Row: Integer;
           Rect: TRect; State: TGridDrawState);
 var
   S: string;
   DrawRect: TRect;
   CurrentColor: TColor;
 begin
   // Определяем цвет строки в зависимости типа Imcoming
   if (Sender as TStrinGgrid).Cells[COLUMN_INCOMING , Row ] = '1' then
     CurrentColor:=clBlue
   else
     CurrentColor:=clMaroon;
 
   if (Sender as TStrinGgrid).Row = Row then
     CurrentColor := clHighlightText;
 
   (Sender as TStrinGgrid).Canvas.font.color := CurrentColor;
   S:= (Sender as TStrinGgrid).Cells[ Col, Row ];
   if (Col = COLUMN_MESSAGE ) and (Row <> ROW_HEADER) then
   begin
     if Length(S) > 0 then
     begin
       DrawRect:=Rect;
       DrawText((Sender as TStrinGgrid).Canvas.Handle, Pchar(S), Length(S),
       DrawRect, dt_calcrect or dt_wordbreak or dt_left );
       if (DrawRect.bottom - DrawRect.top) > (Sender as TStrinGgrid).RowHeights[Row] then
         (Sender as TStrinGgrid).RowHeights[row] :=(DrawRect.bottom - DrawRect.top)
       else
       begin
         DrawRect.Right:=Rect.Right;
         (Sender as TStrinGgrid).Canvas.FillRect( DrawRect );
         DrawText((Sender as TStrinGgrid).Canvas.Handle, Pchar(S),
                   Length(S), DrawRect, dt_wordbreak or dt_left);
       end;
     end;
   end
   else
     if Row <> ROW_HEADER then
       (Sender as TStrinGgrid).Canvas.Textout(rect.left+3, rect.top+3 , S );
 end;
 




Покрашенный StringGrid

...вы можете попробовать использовать StringGrid. У него имеется свойство Objects, через которое вы можете назначать объекты. Создайте объект, содержащий переменную типа TColor, и назначьте это Objects[col,row], что позволит иметь к нему доступ в любое время. Назначьте событие OnDrawCell StringGrid, позволяющее рисовать текст ячейки правильного цвета. Чтобы убедиться, что ячейка выбрана, воспользуйтесь свойством Selection, содержащим то, что выбрал пользователь. Все это должно выглядеть приблизительно так:


 type
   TStrColor = class(TObject)
   public
     Color: TColor; {вы могли бы также определить частные и
     публичные методы доступа}
   end;
 ...
 
 procedure TForm1.FormCreate(Sender: TObject)
 var
   i, j: Integer;
 begin
   with StringList1 do
     for i := 0 to ColCount - 1
       for j := 0 to RowCount - 1
       Objects[i, j] := TStrColor.Create;
 end;
 ...
 
 procedure TForm1.StringGrid1DrawCell(Sender: TObject; Col, Row: Longint;
   Rect: TRect; State: TGridDrawState);
 var
   OldColor: TColor;
 begin
   with StringGrid1.Canvas do
   begin
     OldColor := Font.Color;
     Font.Color := (StringGrid1.Objects[col, row] as TStrColor).Color;
     TextOut(Rect.Left + 2, Rect.Top + 2, StringGrid1.Cells[Col, Row]);
     Font.Color := OldColor;
   end;
 end;
 ...
 
 procedure TForm1.ProcessSelection(Sender: TObject);
 var
   i, j: Integer;
 begin
   with StringGrid1.Selection do
     for i := left to right do
       for j := top to bottom do
         MessageDlg(IntToStr(i) + ',' + IntToStr(j) + '-' +
           IntToStr((StringGrid1.Objects[i, j] as TStrColor).Color),
           mtInformation, [mbOk], 0);
 end;
 

Этот компонент не позволяет делать многочисленный выбор....




Покрашенный StringGrid 2

В данном модуле демонстрируется техника изменения цвета у выводимого в StringGrid текста.


 unit Strgr;
 
 interface
 
 uses
   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
   Forms, Dialogs, Grids, StdCtrls, DB;
 
 type
   TForm1 = class(TForm)
     StringGrid1: TStringGrid;
     procedure StringGrid1DrawCell(Sender: TObject; Col, Row: Longint;
       Rect: TRect; State: TGridDrawState);
   private
     { Private declarations }
   public
     { Public declarations }
   end;
 
 var
 
   Form1: TForm1;
 
 implementation
 
 {$R *.DFM}
 
 procedure TForm1.StringGrid1DrawCell(Sender: TObject; Col, Row: Longint;
 
   Rect: TRect; State: TGridDrawState);
 const
 
   CharOffset = 3;
 begin
 
   with StringGrid1.canvas do
   begin
     font.color := clMaroon;
     textout(rect.left + CharOffset, rect.top + CharOffset, 'L');
     font.color := clNavy;
     textout(rect.left + CharOffset + TextWidth('L'),
       rect.top + CharOffset, 'loyd');
   end;
 end;
 
 end.
 




Цветная кнопка

Автор: VS

В книгах Калверта, Свана и других авторов можно найти похожий текст. Смысл текста – "Изменить цвет кнопок Button, BitBtn нельзя, т.к. их рисует WINDOWS". Если нельзя, но ОЧЕНЬ НУЖНО, то можно.

Небольшой компонент ColorBtn, дает возможность использовать в кнопках цвет. Кроме того, представлено новое свойство - Frame3D, позволяющее получить более реалистичный вид нажатой кнопки. В отличие от API, при изменении значения свойства Frame3D, не требуется переоткрытие компонента.

Примечание. Кнопку по-прежнему рисует WINDOWS, а раскрашивает ее ColorBtn. Код компонента на 90% повторяет код BitBtn, ничего необычного здесь нет. Чаще заглядывайте в VCL - можно найти много интересного. На рисунке представлены ColorButton и ColorBitBtn.


 unit colorbtn;
 
 interface
 
 uses
 
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
   StdCtrls, Buttons;
 
 type
 
   TColorBtn = class(TButton)
   private
     FCanvas: TCanvas;
     IsFocused: Boolean;
     F3DFrame: boolean;
     FButtonColor: TColor;
     procedure Set3DFrame(Value: boolean);
     procedure SetButtonColor(Value: TColor);
     procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
     procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message
       WM_LBUTTONDBLCLK;
     procedure DrawButtonText(const Caption: string; TRC: TRect; State:
       TButtonState; BiDiFlags: Longint);
     procedure CalcuateTextPosition(const Caption: string; var TRC: TRect;
       BiDiFlags: Longint);
   protected
     procedure CreateParams(var Params: TCreateParams); override;
     procedure SetButtonStyle(ADefault: Boolean); override;
   public
     constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
   published
     property ButtonColor: TColor read FButtonColor write SetButtonColor default
       clBtnFace;
     property Frame3D: boolean read F3DFrame write Set3DFrame default False;
   end;
 
 procedure Register;
 
 implementation
 
 { TColorBtn }
 
 constructor TColorBtn.Create(AOwner: TComponent);
 begin
   inherited Create(AOwner);
   Height := 21;
   FCanvas := TCanvas.Create;
   FButtonColor := clBtnFace;
   F3DFrame := False;
 end;
 
 destructor TColorBtn.Destroy;
 begin
   FCanvas.Free;
   inherited Destroy;
 end;
 
 procedure TColorBtn.CreateParams(var Params: TCreateParams);
 begin
   inherited CreateParams(Params);
   with Params do
     Style := Style or BS_OWNERDRAW;
 end;
 
 procedure TColorBtn.Set3DFrame(Value: boolean);
 begin
   if F3DFrame <> Value then
     F3DFrame := Value;
 end;
 
 procedure TColorBtn.SetButtonColor(Value: TColor);
 begin
   if FButtonColor <> Value then
   begin
     FButtonColor := Value;
     Invalidate;
   end;
 end;
 
 procedure TColorBtn.WMLButtonDblClk(var Message: TWMLButtonDblClk);
 begin
   Perform(WM_LBUTTONDOWN, Message.Keys, Longint(Message.Pos));
 end;
 
 procedure TColorBtn.SetButtonStyle(ADefault: Boolean);
 begin
   if IsFocused <> ADefault then
     IsFocused := ADefault;
 end;
 
 procedure TColorBtn.CNDrawItem(var Message: TWMDrawItem);
 var
   RC: TRect;
   Flags: Longint;
   State: TButtonState;
   IsDown, IsDefault: Boolean;
   DrawItemStruct: TDrawItemStruct;
 begin
   DrawItemStruct := Message.DrawItemStruct^;
   FCanvas.Handle := DrawItemStruct.HDC;
   RC := ClientRect;
   with DrawItemStruct do
   begin
     IsDown := ItemState and ODS_SELECTED <> 0;
     IsDefault := ItemState and ODS_FOCUS <> 0;
     if not Enabled then
       State := bsDisabled
     else if IsDown then
       State := bsDown
     else
       State := bsUp;
   end;
   Flags := DFCS_BUTTONPUSH or DFCS_ADJUSTRECT;
   if IsDown then
     Flags := Flags or DFCS_PUSHED;
   if DrawItemStruct.ItemState and ODS_DISABLED <> 0 then
     Flags := Flags or DFCS_INACTIVE;
   if IsFocused or IsDefault then
   begin
     FCanvas.Pen.Color := clWindowFrame;
     FCanvas.Pen.Width := 1;
     FCanvas.Brush.Style := bsClear;
     FCanvas.Rectangle(RC.Left, RC.Top, RC.Right, RC.Bottom);
     InflateRect(RC, -1, -1);
   end;
   if IsDown then
   begin
     FCanvas.Pen.Color := clBtnShadow;
     FCanvas.Pen.Width := 1;
     FCanvas.Rectangle(RC.Left, RC.Top, RC.Right, RC.Bottom);
     InflateRect(RC, -1, -1);
     if F3DFrame then
     begin
       FCanvas.Pen.Color := FButtonColor;
       FCanvas.Pen.Width := 1;
       DrawFrameControl(DrawItemStruct.HDC, RC, DFC_BUTTON, Flags);
     end;
   end
   else
     DrawFrameControl(DrawItemStruct.HDC, RC, DFC_BUTTON, Flags);
   FCanvas.Brush.Color := FButtonColor;
   FCanvas.FillRect(RC);
   InflateRect(RC, 1, 1);
   if IsFocused then
   begin
     RC := ClientRect;
     InflateRect(RC, -1, -1);
   end;
   FCanvas.Font := Self.Font;
   if IsDown then
     OffsetRect(RC, 1, 1);
   DrawButtonText(Caption, RC, State, 0);
   if IsFocused and IsDefault then
   begin
     RC := ClientRect;
     InflateRect(RC, -4, -4);
     FCanvas.Pen.Color := clWindowFrame;
     Windows.DrawFocusRect(FCanvas.Handle, RC);
   end;
   FCanvas.Handle := 0;
 end;
 
 procedure TColorBtn.CalcuateTextPosition(const Caption: string; var TRC: TRect;
   BiDiFlags: Integer);
 var
   TB: TRect;
   TS, TP: TPoint;
 begin
   with FCanvas do
   begin
     TB := Rect(0, 0, TRC.Right + TRC.Left, TRC.Top + TRC.Bottom);
     DrawText(Handle, PChar(Caption), Length(Caption), TB, DT_CALCRECT or
       BiDiFlags);
     TS := Point(TB.Right - TB.Left, TB.Bottom - TB.Top);
     TP.X := ((TRC.Right - TRC.Left) - TS.X + 1) div 2;
     TP.Y := ((TRC.Bottom - TRC.Top) - TS.Y + 1) div 2;
     OffsetRect(TB, TP.X + TRC.Left, TP.Y + TRC.Top);
     TRC := TB;
   end;
 end;
 
 procedure TColorBtn.DrawButtonText(const Caption: string; TRC: TRect; State:
   TButtonState; BiDiFlags: Integer);
 begin
   with FCanvas do
   begin
     CalcuateTextPosition(Caption, TRC, BiDiFlags);
     Brush.Style := bsClear;
     if State = bsDisabled then
     begin
       OffsetRect(TRC, 1, 1);
       Font.Color := clBtnHighlight;
       DrawText(Handle, PChar(Caption), Length(Caption), TRC,
         DT_CENTER or DT_VCENTER or BiDiFlags);
       OffsetRect(TRC, -1, -1);
       Font.Color := clBtnShadow;
       DrawText(Handle, PChar(Caption), Length(Caption), TRC,
         DT_CENTER or DT_VCENTER or BiDiFlags);
     end
     else
       DrawText(Handle, PChar(Caption), Length(Caption), TRC,
         DT_CENTER or DT_VCENTER or BiDiFlags);
   end;
 end;
 
 procedure Register;
 begin
   RegisterComponents('Controls', [TColorBtn]);
 end;
 
 end.
 

Небольшое дополнение. Кнопку по прежнему рисует WINDOWS, а раскрашивает ее ColorBtn. Код компонента на 90% повторяет код BitBtn, ничего необычного здесь нет. Хочется повторить слова Калверта – "Пользуйтесь исходным кодом". Чаще заглядывайте в VCL - можно найти много интересного.




Цветные ячейки в StringGrid и в DBGrid

StringGrids и DBGrids с цветными ячейками смотрятся очень красиво, и Вы можете информировать пользователя о важных данных внутри Grid. Совместимость: все версии Delphi К сожалению, невозможно применить один и тот же метод к StringGrids и к DBGrids. Итак сперва рассмотрим как это сделать в StringGrid:

StringGrid

Для раскрашивания будем использовать событие "OnDrawCell". Следующий код показывает, как сделать в Grid красный бэкраунд. Бэкграунд второй колонки будет зелёным.


 procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
 const //здесь определяем Ваш цвет. Так же можно использовать цвета по умолчанию.
   clPaleGreen = TColor($CCFFCC);
   clPaleRed = TColor($CCCCFF);
 begin
   //Если ячейка получает фокус, то нам надо закрасить её другими цветами
   if (gdFocused in State) then
   begin
     StringGrid1.Canvas.Brush.Color := clBlack;
     StringGrid1.Canvas.Font.Color := clWhite;
   end
   else //Если же ячейка теряет фокус, то закрашиваем её красным и зелёным
     if ACol = 2 then //Вторая колонка будет зелёной , другие - ячейки красными
       StringGrid1.Canvas.Brush.color := clPaleGreen
     else
       StringGrid1.canvas.brush.Color := clPaleRed;
 
   //Теперь закрасим ячейки, но только, если ячейка не Title- Row/Column
   //Естественно это завит от того, есть у Вас title-Row/Columns или нет.
 
   if (ACol > 0) and (ARow > 0) then
   begin
     //Закрашиваем бэкграунд
     StringGrid1.Canvas.FillRect(Rect);
 
     //Закрашиваем текст (Text). Также здесь можно добавить выравнивание и т.д..
     StringGrid1.Canvas.TextOut(Rect.Left, Rect.Top, StringGrid1.Cells[ACol, ARow]);
   end;
 end;
 

Если Вы захотите чтобы цвет ячеек менялся в зависимости от значения в них, то можно заменить 3 линии (if Acol = 2 ......) на что-нибуть вроде этого


 if StringGrid1.Cells[ACol, ARow] = 'highlight it' then
   StringGrid1.Canvas.Brush.color := clPalered
 else
   StringGrid1.canvas.brush.Color := clWhite;
 

Ну а теперь давайте раскрасим DBGrids:

DBGrid

С DBGrids это делается намного проще. Здесь мы будем использовать событие "OnDrawColumnCell". Следующий пример разукрашивает ячейки колонки "Status" когда значение НЕ равно "a". Если Вы хотите закрасить целую линию, то достаточно удалить условие "If..." (смотрите ниже)


 procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
 DataCol: Integer; Column: TColumn; State: TGridDrawState);
 const
   clPaleGreen = TColor($CCFFCC);
   clPaleRed = TColor($CCCCFF);
 begin
   if Column.FieldName = 'Status' then //Удалите эту линию, если хотете закрасить целую линию
     if Column.Field.Dataset.FieldByName('Status').AsString <> 'a' then
       if (gdFocused in State) then //имеет ли ячейка фокус?
         DBGrid1.Сanvas.Brush.Color := clBlack //имеет фокус
       else
         DBGrid1.Сanvas.Brush.Color := clPaleGreen; //не имеет фокуса
 
   //Теперь давайте закрасим ячейку используя стандартный метод:
   DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State)
 end;
 

Вот и всё. Не правда ли красиво?

Фрагмент кода моей программы - в зависимости от значения в поле taPlatAnswerType рисует строку белам цветом на красном фоне:


 procedure TfmMain.dgPlatDrawColumnCell(Sender: TObject; const Rect:
 TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
 begin
   with dgPlat.Canvas do
   begin
     // Условие какую строку надо рисовать по другому
     if (taPlatAnswerType.AsString = 'b') and not (gdFocused in State) then
     begin
       Brush.Color := clRed;
       Font.Color := clWhite;
       FillRect(Rect);
       TextOut(Rect.Left, Rect.Top, Column.Field.Text);
     end
     else
       dgPlat.DefaultDrawColumnCell(Rect, DataCol, Column, State);
   end;
 end;
 




Цветной DBGrid

Глупый юзер горько плачет
На обломки окон глядя.
Глупый юзер: он не знает,
Что такое мелко-мягкий.


 // Function to color a DBGrid (declared as private) 
 procedure TForm1.ColorGrid(dbgIn: TDBGrid; qryIn: TQuery; const Rect: TRect;
   DataCol: Integer; Column: TColumn;
   State: TGridDrawState);
 var
   iValue: LongInt;
 begin
   // color only the first field
   if (DataCol = 0) then
   begin
     //Проверяем значение поля и присваеваем цвет  
 
     iValue := qryIn.FieldByName('HINWEIS_COLOR').AsInteger;
     case iValue of
       1: dbgIn.Canvas.Brush.Color := clGreen;
       2: dbgIn.Canvas.Brush.Color := clLime;
       3: dbgIn.Canvas.Brush.Color := clYellow;
       4: dbgIn.Canvas.Brush.Color := clRed;
     end;
 
     dbgIn.DefaultDrawColumnCell(Rect, DataCol, Column, State);
 
   end;
 end;
 
 procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject;
   const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
 begin
   ColorGrid(DBGrid1, Query1, Rect, DataCol, Column, State);
 end;
 




COM

- Сколько нужно сотрудников службы поддержки компании Microsoft, чтобы заменить лампочку?
- Четыре. Первый, чтобы узнать регистрационный номер лампочки. Второй, чтобы спросить: "А вы перезагрузиться пробовали?" Третий, чтобы спросить: "А вы пробовали её переустановить?" И четвёртый, чтобы сказать: "Это у вас что-то с железом. У нас в офисе лампочка работает отлично!"

COM расшифровывается как "Component Object Model" - Модель Компонентных Объектов. Это стандарт, описывающий как должны работать интерфейсы класса (или объекта) -- включая такие вопросы, как, например, работа с памятью или многопоточностью, и каким образом приложения могут использовать компоненты, созданные в стандарте COM. COM является стандартом, независимым от языка программирования и (по крайней мере, как это понял я) независимым от аппаратного окружения. Первоначально стандарт был разработан, опубликован и принят фирмами Microsoft и IBM, но пока не существует технической причины для того, чтобы он не поддерживался, например, и на Sun Sparc20 под управлением операционной системы Solaris.

Вот отличительные признаки и основные механизмы функционирования COM-объекта:

  1. У него имеется "globally unique identifier" (глобальный уникальный идентификатор) -- сокращенно GUID или CLSID -- 128-битное целое число, которое, по существу, должно гарантировать уникальность COM-объекта (или интерфейса в случае CLSID) на всех компьютерах нашей планеты. Для того, чтобы воспользоваться COM-объектом, клиенту необходимо знать его GUID.
  2. Если клиенту известен GUID COM-объекта, то для создания его экземпляра можно воспользоваться стандартным API вызовом CoCreateInstance.
  3. Объект содержит по крайней мере один интерфейс с именем IUnknown. IUnknown имеет три метода: AddRef, Release и QueryInterface. AddRef и Release вызываются клиентами для управления счетчиком ссылок, в котором хранится количество используемых ссылок на объект. Как только счетчик ссылок будет равен нулю, объект будет удален из памяти.

Клиент может вызвать QueryInterface для того, чтобы определить, поддерживает ли объект специфический интерфейс (интерфейс - группа свойств и методов). Если это так, QueryInterface возвращает ссылку на таблицу указателей свойств и методов, поддерживаемых интерфейсом. После это клиент может вызывать эти методы, используя указатели, получаемые из таблицы.

OLE - "развивающийся стандарт" (который, вероятно, в нашем контексте можно назвать "перемещающий цели"), созданный для предоставления комплекса услуг (компонентам, приложениям и др.) с применением COM-ориентированных объектов.

Автоматизация OLE является отдельным OLE-сервисом, предоставляющим клиенту возможность управления отдельными компонентами. Действительно, это несколько непривычно. Компонент, которым можно управлять с помощью OLE автоматизации, называется IDispatch. IDispatch включает методы для определения поддерживаемых интерфейсом методов (извините за каламбур), их имен, типов данных, описание всех параметров и специальный "dispatch ID" для каждого метода интерфейса. Если клиент знает имя метода, то с помощью IDispatch он может узнать о нем все. Конечно, это займет какое-то время, но это работает. Конечно лучше, когда он заранее знает (например, во время компиляции) dispID и информацию о параметрах вызываемого метода для его непосредственного вызова во время выполнения программы через метод IDispatch Invoke.

Для вызовов всех методов объекта программа использует интерфейс объектов IDispatch (и/или библиотеку типов) для определения dispID и информации о параметрах, и при компиляции вставляет эту информацию в вашу программу. Это так называемое "раннее связывание", позволяющее осуществлять максимально быстрые вызовы методов COM-объектов при использовании OLE автоматизации. Вы можете также воспользоваться "поздним связыванием", когда программа для определения dispID, имени метода и пр. использует IDispatch только во время ее выполнения. Это случается при использовании объектной переменной, объявленной "как объект" ("As Object"). Позднее связывание достаточно медленное и отчасти ненадежное (поскольку во время компиляции программа не может осуществить проверку параметров), но может иногда применяться ввиду своей гибкости.




Как показывать встроенный редактор ComboBox в ячейке StringGrid


- В чем разница между компьютером и человеком?
- Если перегрузишь комп - исчезнут глюки, а если человека - появятся.


 procedure TForm1.FormCreate(Sender: TObject);
 begin
   {Высоту combobox'а не изменишь, так что вместо combobox'а
   будем изменять высоту строки grid'а !}
   StringGrid1.DefaultRowHeight := ComboBox1.Height; {Спрятать combobox}
   ComboBox1.Visible := False; ComboBox1.Items.Add('Delphi Kingdom');
   ComboBox1.Items.Add('Королевство Дельфи');
 end;
 
 procedure TForm1.ComboBox1Change(Sender: TObject);
 begin
   {Перебросим выбранное в значение из ComboBox в grid}
   StringGrid1.Cells[StringGrid1.Col,
   StringGrid1.Row] := ComboBox1.Items[ComboBox1.ItemIndex];
   ComboBox1.Visible := False; StringGrid1.SetFocus;
 end;
 
 procedure TForm1.ComboBox1Exit(Sender: TObject);
 begin
   {Перебросим выбранное в значение из ComboBox в grid}
   StringGrid1.Cells[StringGrid1.Col,
   StringGrid1.Row] := ComboBox1.Items[ComboBox1.ItemIndex];
   ComboBox1.Visible := False; StringGrid1.SetFocus;
 end;
 
 procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol,
 ARow: Integer; var CanSelect: Boolean);
 var
   R: TRect;
 begin
   if ((ACol = 3) and (ARow <> 0)) then
   begin
     {Ширина и положение ComboBox должно соответствовать ячейке StringGrid}
     R := StringGrid1.CellRect(ACol, ARow); R.Left := R.Left + StringGrid1.Left;
     R.Right := R.Right + StringGrid1.Left; R.Top := R.Top + StringGrid1.Top;
     R.Bottom := R.Bottom + StringGrid1.Top; ComboBox1.Left := R.Left + 1;
     ComboBox1.Top := R.Top + 1; ComboBox1.Width := (R.Right + 1) - R.Left;
     ComboBox1.Height := (R.Bottom + 1) - R.Top; {Покажем combobox}
     ComboBox1.Visible := True; ComboBox1.SetFocus;
   end;
   CanSelect := True;
 end;
 




Программное открытие ComboBox


 MyComboBox.DroppedDown := True;
 

Или:


 MyComboBox.Perform(CB_SHOWDROPDOWN, True, 0);
 




Как определить состояние списка ComboBox, выпал или скрыт


 if SendMessage(ComboBox1.Handle, CB_GETDROPPEDSTATE,0,0) = 1 then
 begin
   // список ComboBox выпал
 end;
 




Как сравнить Bookmarks в таблице


 function TBDEDirect.CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Boolean;
 var
   Res: DBIResult;
   CompareRes: Word;
 begin
   Result := False;
   if CheckDatabase then
   begin
     Res := DbiCompareBookmarks(FDataLink.DataSource.DataSet.Handle,
     Bookmark1, Bookmark2, CompareRes);
     if Res = 0 then
       if CompareRes = 0 then
         Result := True
       else
     else
       Check(Res);
   end;
 end;
 




Сравнительный анализ технологий CORBA и COM 1


Если Вы получили письмо со словами "повеска" и "военкомат" разорвите его на месте потому что Вас лишат на 2 года компъютера и интернета.

В последние 2-3 года резко возрос интерес к так называемым распределенным системам. Под распределенными системами обычно понимают программные комплексы, составные части которых функционируют на разных компьютерах в сети. Эти части взаимодействуют друг с другом, используя ту или иную технологию различного уровня - от непосредственного использования сокетов TCP/IP до технологий с высоким уровнем абстракции, таких, как RMI или CORBA.

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

  • Обеспечение масштабируемости систем, т.е. способности эффективно обслуживать как малое, так и очень большое количество клиентов одновременно.
  • Надежность создаваемых приложений. Программный комплекс должен быть устойчив не только к ошибкам пользователей (это определяется главным образом качеством клиентских приложений), но и к сбоям в системе коммуникаций. Надежность подразумевает использование транзакций, т.е. гарантированного перехода системы в процессе функционирования из одного устойчивого и достоверного состояния в другое.
  • Возможность непрерывной работы в течение длительного времени (так называемый режим 24x7, т.е. режим круглосуточной работы в течение недель и месяцев).
  • Высокий уровень безопасности системы, под которой понимается не только контроль доступности тех или иных ресурсов системы и защищенность информации на всех этапах функционирования, но и отслеживание выполняемых действий с высокой степенью достоверности.
  • Высокая скорость разработки приложений и простота их сопровождения и модификации с использованием программистов средней квалификации.
  • Оказалось, что обеспечить соответствие этим требованиям, используя традиционные технологии - а именно, двухзвенные системы клиент-сервер, в которых в качестве серверов выступают системы управления базами данных, почти невозможно.
  • Заметим, что далеко не для всех приложений вышеперечисленные требования являются существенными. Легко представить распределенную систему, которая функционирует на небольшом (до 100) количестве компьютеров, работающих в локальной сети, где нет проблем с перезапуском одного или двух-трех серверов в случае необходимости, а главными задачами, для решения которых используются распределенные технологии, являются задачи использования функциональности нескольких стандартных серверов приложений (например, текстовых процессоров, броузеров и электронных таблиц) в интересах клиентских задач. Необходимо иметь в виду, что термин распределенные системы относится к огромному числу задач самого разного класса.

Данный обзор содержит сравнительный анализ двух наиболее популярных и комплексных систем создания распределенных приложений, а именно, CORBA консорциума OMG и COM (DCOM, COM+) фирмы Microsoft. Этот обзор предназначен главным образом для менеджеров проектов, руководителей информационных служб и др., т.е. для тех, кому приходится принимать ответственные, стратегические решения. Вследствие этого, в нем будут отсутствовать чисто технические аспекты обоих технологий, которые интересны только для разработчиков.

Кроме того, при написании обзора не ставилась задача сделать окончательный вывод типа ... таким образом, CORBA (COM), бесспорно, лучше, чем COM (CORBA). Связано это не с модной в наше время политкорректностью или отсутствием у автора своей точки зрения по этому вопросу. Дело даже не в том, что существуют определенные трудности с формализацией такого сравнения - я мог бы представить результаты сравнительных анализов, в которых используются численные оценки (баллы), выставленные экспертами, весовые коэффициенты и прочее, что придает отчету серьезный и весомый вид. Дело в том, что COM и CORBA можно сравнивать только с учетом определенных допущений. Отказ от таких допущений легко позволяет получить какой угодно результат. Вот эти допущения:

  • CORBA, в отличие от COM’а, является концепцией, а не ее реализацией. Когда мы говорим COM, то понимаем под этим скорее набор конкретных средств - элементов операционной системы, библиотек, утилит и т.п., являющихся составной частью того, что называется Microsoft Windows. Под термином CORBA понимается именно сложная и развитая концепция, сформулированная на уровне специального языка описаний - IDL. Реализации же этой концепции могут сильно отличаться друг от друга по различным критериям, наиболее важным в том или другом случае. Inprise/Corel VisiBroker и Application Server, BEA WebLogic, Iona Orbix, Oracle Application Server и картриджи Oracle, IBM BOSS - все эти продукты используют те или иные возможности CORBA. Технология Sun Enterpise JavaBeans создана поверх CORBA и использует такие ее возможности, как удаленный вызов объектов, службу имен, управление транзакциями. Реализация EJB фирмы Inprise связано с CORBA еще более тесным образом. Мы будем сравнивать COM и CORBA именно как концепции создания распределенных систем, а не как ту или иную их реализацию.
  • При работе с реальным проектом необходимо учитывать область применения той или иной технологии. COM (как цельное и комплексное решение) способен функционировать только под Windows NT/Windows2000. Рассуждения о переносе COM на другие операционные системы в настоящий момент носят скорее рекламный характер. Ни компонентная модель COM (т.е. ActiveX), ни монитор транзакций (Microsoft Transaction Server, MTS) не способны работать нигде, кроме Windows, и сама Microsoft не проявляет никакой активности в этом напрвлении (вопросами переноса тех или иных элементов COM на другие платформы занимается консорциум Open Group). CORBA является многоплатформенным решением просто по определению.
  • Помимо чисто технологических аспектов, при принятии решения необходимо оценить затраты на закупку необходимого программного обеспечения, его сопровождения и обучение персонала. COM (в отличие от CORBA) официально является бесплатной технологией. Вы получаете все необходимое, просто приобретя, например, Windows NT Server. (Кстати, сам факт конкуренции дорогостоящей технологии с аналогичной, но бесплатной, многое говорит об их технических возможностях).
  • Наличие готовых серверов приложений, пригодных для решения вашей задачи. Если Вы можете решить свои проблемы, используя функциональность Microsoft Office, то ничего лучше COM вы, естественно, не найдете.
  • Таким образом, главной задачей настоящего обзора является попытка помочь руководителю того или иного уровня принять квалифицированное решение в каждом конкретном случае. Поскольку и CORBA, и COM позиционируются соответственно OMG и Microsoft как универсальные технологии создания распределенных систем, мы будем оценивать и сравнивать их именно с этой точки зрения. Предполагается, что для проекта используется платформа Windows (в противном случае нечего рассматривать COM) и имеется достаточно средств для закупки основных стандартных частей той или иной реализации (иначе обсуждение CORBA теряет смысл).

Концептуальный фундамент технологии

COM
Технология создавалась фирмой Microsoft как средство взаимодействия приложений (в том числе составных частей операционной системы) Windows, функционирующих на одном компьютере, с последующим развитием для использования в пределах локальной сети. Главная задача на момент создания - обеспечение технологии Object Linking and Embedding (OLE 1.0). Характерно, что обмен данными между приложениями (Dynamic Data Exchange, DDE) первоначально строился не по COM-технологии, а с использованием механизма сообщений (messages). Развитие технологии идет по мере добавления новых возможностей. Как универсальная технология взаимодействия приложений COM начал использоваться с OLE 2.0 (1991). Концепция технологии неразрывно связана с ее реализацией. Появление новых возможностей - это просто появление новых библиотек, функций API и утилит Windows. Общий знаменатель технологии - двоичная структура объекта, хотя в настоящий момент существует язык описания структуры объекта - Interface definition Language (IDL).
CORBA
Технология создавалась консорциумом OMG как универсальная технология создания распределенных систем в гетерогенных средах. OMG представляет собой некоммерческую организацию, являющуюся содружеством разработчиков программного обеспечения и его потребителей, объединивших свои усилия для создания спецификаций этой технологии. В настоящий момент в OMG состоит более 800 членов, включая всех сколько-нибудь серьезных производителей программного обеспечения (и даже c недавнего времени Microsoft). Первая спецификация CORBA появилась в 1991 г. Новые возможности официально считаются добавленными в CORBA в момент утверждения соответствующей спецификации. Как правило, в разработке спецификации участвуют крупнейшие специалисты в данной области. Разработка реализации - задача конкретной фирмы. Обычно от утверждения спецификации до появления высококачественной реализации проходит довольно много времени - иногда несколько лет. Общий знаменатель технологии - объявления на языке IDL, который является сердцем CORBA с момента ее появления. (Существуют три различных языка описаний с одним и тем же названием - OSF IDL, Microsoft IDL и OMG IDL).

Выводы

Технология CORBA носит существенно более общий и универсальный характер, чем COM, что заложено в ее фундаменте. Опережение разработки спецификаций (по сравнению с реализациями) позволяет добиться более связной, целостной и гармоничной системы. С другой стороны, при разработке реального проекта нужно предварительно убедиться, что высококачественная реализация того или иного сервиса CORBA уже доступна (источниками проблем могут служить, например, Persistence Service и Security Service).

Комплексность системы

COM
COM содержит все необходимое, что нужно для построения распределенной системы: технологию удаленного вызова методов (как статических, так и динамических), базы данных серверных объектов (библиотеки типов), которые могут быть импортированы для анализа структуры серверов COM, универсальный протокол обмена между клиентами и серверами, спецификации так называемых составных документов (ActiveDoc), объектный монитор транзакций (MTS), компонентную модель (ActiveX) и др. Все составные части прекрасно соответствуют друг другу в рамках модели COM. Уникальной возможностью COM является универсальная технология доступа к базам данных - OLE DB/ADO.
CORBA
В настоящий момент CORBA не имеет своей собственной компонентной модели; работа над ней началась в 1998 г. и еще не завершена. Это главный серьезный недостаток. Правда, он несколько компенсируется наличием основанной на CORBA компонентной моделью Enterprise JavaBeans, так что программисты на Java находятся в привилегированном положении. Все остальное, что присутствует в COM, имеется и в CORBA, и даже более того - за исключением универсальной технологии доступа к БД. Опять-таки, Java-программисты имеют преимущество и здесь - за счет наличия общей для Java технологии доступа к данным JDBC.

Выводы

В настоящий момент COM более законченная система, но на более низком уровне и при существенно большем количестве ограничений, определяемых самой концепцией системы.

Используемые языки программирования

COM
Потенциально COM могут поддерживать самые различные языки программирования - все решает фирма Microsoft. Добавление некоторых расширений или экспертов (wizard) в систему разработки позволит использовать для работы с COM любой язык программирования. В настоящий момент наиболее широко используются Visual Basic, C++ и Delphi. Серьезные проблемы возникли при использования языка, на который возлагались особые надежды - с Java. Microsoft добилась прекрасного взаимодействия Java с COM, но достигнуто это было путем отказа от переносимости таких Java-программ на другие виртуальные машины Java. Не случайно продукт фирмы Microsoft - J++ - не содержит в названии Java. Вообще, уровень стандартизации для COM достаточно слаб. Это не обязательно нужно рассматривать как недостаток - в конце концов, язык C лет пятнадцать прекрасно обходился без формального стандарта.
CORBA
Под стандартом применительно к CORBA понимается то, что официально утверждено консорциумом OMG. Надо сказать, что это очень высокий уровень легитимности, так как авторитет OMG в компьютерном мире чрезвычайно высок. В настоящий момент стандартизовано отображение языка IDL на 6 языков программирования - Ada, C, C++, Cobol, Java и Smalltalk. Существуют также отображения на Pascal (точнее, Delphi), Perl, Python и еще десяток языков.

Наиболее используемыми языками в настоящий момент являются Java (вследствие прекрасного взаимодействия Java-технологий, особенно JDBC, RMI, JNDI и EJB, с CORBA), и C++ - как самый эффективный, мощный и распространенный язык компьютерной индустрии.

Выводы

Обе технологии не испытывают особых проблем с точки зрения взаимодействия с языками программирования. Некоторые преимущества имеет CORBA - за счет более строгой стандартизации и более богатого выбора доступных средств разработки.




Сравнительный анализ технологий CORBA и COM 2


Беседуют два программиста.
- Чем программист отличается от обычного смертного?
- А тем, что в состоянии ответить на вопрос, в котором уже заключен ответ.
- Это как же?
- Ну, например, ответь на вопрос: сколько будет 2х2=4?
- ТRUЕ!

Уровень абстракции

COM
COM реализует высокий уровень абстракции - все вопросы низкого уровня, такие, как взаимодействия с операционной системой или сетевыми средствами, “спрятаны” от прикладного программиста.
CORBA
CORBA обеспечивает даже несколько более высокий уровень за счет базировании технологии исключительно на языке описания IDL с последующим отображением таких спецификаций на конкретный язык программирования, а также некоторых возможностей, например, автоматического (т.е. прозрачного для программиста) распространения контекста транзакций.

Выводы

Обе технологии реализуют примерно одинаковый и достаточно высокий уровень абстракций.

Поддержка компонентной модели

COM
Компонентная модель Microsoft, базирующаяся на COM-технологии, в основе имеет двоичную структуру объектов. Это не вызывает никаких проблем при ориентации на одну платформу и операционную систему. Безусловным достоинством такой модели является простота создания компонентов с использованием различных языков программирования. С другой стороны, такая компонентная модель неизбежно связана с определенными ограничениями и недостатками. Одним из самых серьезных недостатков является то, что ее нельзя, строго говоря, назвать объектно-ориентированной.
CORBA
Как уже говорилось, CORBA в настоящее время не имеет своей компонентной модели. Пусть это не имеет практического значения для Java-программистов, но в общем случае эта та область, где OMG (и фирмам-производителям программного обеспечения) еще предстоит серьезно поработать.

Выводы

Это та область, где COM пока имеет существенные преимущества по сравнению с CORBA. C другой стороны, при разработке реальных проектов использование на стороне сервера компонентов Enterprise JavaBeans, построенных поверх инфраструктуры CORBA, предоставляет разработчику значительные преимущества по сравнению с компонентами ActiveX.

Универсальный протокол обмена

COM
Передача данных между клиентом и сервером основана на наборе типов, которые называются OLE Automation types. В принципе, схема маршалинга (в том числе типы передаваемых данных) определяется парой стандартных интерфейсов COM. Реализовав по-своему некоторые из методов этих интерфейсов, можно определить свою схему маршалинга. Впрочем, это нетривиальная задача, и обычно разработчики используют уже готовую стандартную реализацию. Упаковка данных и их передача могут быть реализованы поверх различных сетевых протоколов.
CORBA
CORBA значительно более строго и формально подходит к механизмам обмена и передаче данных. Определен протокол CORBA (General Inter-ORB Protocol, GIOP) - и его реализация на базе протокола TCP/IP (Internet Inter-ORB Protocol, IIOP). CORBA способна передавать данные различных типов, включая структуры (struct) и объединения (union), в том числе содержащие рекурсивные определения. Предусмотрена система описания и контроля типов - как на уровне IDL-деклараций, так и динамическая. Для каждого языка используется свое отображение данных IDL. В версии 2.3 появился новый, заимствованный из RMI механизм передачи объектов CORBA - так называемая “передача по значению (objects-by-value)”. В предыдущих версиях CORBA при вызове удаленных методов объекты можно было передавать только по ссылке.

Выводы

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

Поддержка со стороны различных производителей и открытость

COM
В настоящий момент официальным “хранителем стандарта” технологии COM является консорциум Open Group, хотя “главным игроком на этом поле” является, конечно же, Microsoft. Поддержкой технологии COM занимаются многие небольшие фирмы - некоторые из них создают компоненты ActiveX, некоторые - как Software AG - занимаются переносом фрагментов COM на другие платформы, некоторые - как Borland - создают RAD-инструменты, основанные в том числе и на COM. В любом случае, только Microsoft решает, какая часть технологии и в каком виде попадает из лабораторий Microsoft в открытые спецификации.
CORBA
Ситуация с CORBA совершенно иная. CORBA является результатом совместных усилий огромного числа фирм, среди которых Sun, Oracle, IBM, Netscape/AOL, DEC/Compaq, JavaSoft, Borland/Visigenic (в настоящий момент в связи со слиянием Inprise и Corel принято решение о восстановлении имени Visigenic), BEA, Iona и многие другие. Можно сказать, что все производители программного обеспечения, которое должно функционировать на различных платформах и под управлением различных операционных систем, выбрали CORBA как стандартную инфраструктуру создания программных продуктов. Естественно, все спецификации CORBA являются полностью открытыми. В лагере сторонников CORBA просматривается четкая тенденция к тесному взаимодействию и некоторой унификации используемых технологий (в качестве примера можно привести отказ Sun и ORACLE от создания собственного ORB и лицензирование Visigenic VisiBroker).

Выводы

COM и CORBA имеют совершенно разный уровень открытости и поддержки со стороны ведущих фирм в компьютерной индустрии.

Развитость сервисной части

COM
COM предоставляет минимальный набор совершенно необходимых средств - кодогенераторы c IDL, утилиты управления доступом (dcomcnfg) и др. Как правило, разработчики пользуются теми или иными инструментами, встроенными в конкретные средства разработки (примером может служит утилита работы с библиотеками типов или эксперт создания ActiveX-объектов в Borland Delphi/C++ Builder).
CORBA
CORBA имеет очень развитую сервисную часть; например, только для поиска серверных объектов по различным критериям можно использовать 4 различных сервиса CORBA. Кроме того, OMG стремится к максимальной стандартизации вспомогательных возможностей CORBA.

Выводы

CORBA предоставляет разработчикам существенно большие возможности, чем COM, в области сервисов и вспомогательных средств. С другой стороны, COM-программисты обычно не испытывают какого-либо дискомфорта из-за их недостатка. Вследствие ограниченности области применения COM объективно нет необходимости в создании таких же развитых и универсальных средств, как это совершенно необходимо для CORBA.

Самодокументирование системы

COM
COM предусиатривает возможность создания локальной базы данных, хранящей информацию о COM-объектах, их интерфейсах, методах и т.д. для сервера приложений COM. Такая база данных называется библиотекой типов (type library). Использование библиотек типов не является обязательным для OLE, хотя это необходимо в технологии ActiveX. Для получения информации из type library пользователь должен явно импортировать ее, для чего необходимо выбрать соответствующую запись реестра Windows на конкретном компьютере.
CORBA
CORBA имеет аналог библиотеки типов COM - это так называемый Репозитарий Интерфейсов (Interface Repository). Чтобы оценить принципиальную разницу в подходе CORBA по сравнению с COM, достаточно сказать, что Репозитарий Интерфейсов CORBA сам представляет из себя объект CORBA со всеми вытекающими из этого возможностями. Помимо Репозитария Интерфейсов, CORBA использует Репозитарий Реализаций (Implementation Repository), который представляет из себя базу данных, содержащую информацию о серверах приложений CORBA.

Выводы

Средства интроспекции (самодокументрования) CORBA значительно более развиты, мощны, гибки и универсальны, чем аналогичные средства COM. CORBA-программисты получают дополнительные преимущества по сравнению со своими коллегами, работающими с COM, при использовании Java (Java-технологии очень тесно связаны с CORBA). Связано это с тем, что Java предусматривает свой уровень интроспекции, дополнительный по отношению к CORBA.

Технология и описание проекта

COM
Обычно объявления на языке IDL при работе с COM не являются существенной частью спецификации проекта, так как IDL-спецификации играют вспомогательную роль в COM-технологии вследствие ее базирования на двоичном стандарте объектов. Кроме того, язык Microsoft IDL не очень развит с точки зрения объявления типов данных, из которых строится программа.
CORBA
Проект с использованием CORBA всегда начинается с написания IDL-спецификаций (особый случай - использование Java, когда в принципе возможно генерировать стандартный код CORBA непосредственно на базе классов Java, хотя вряд ли это разумно для больших проектов.). Эти IDL-спецификации прекрасно отражают суть выполняемых действий с точки зрения функционирования распределенной системы. Синтаксис OMG IDL очень похож на синтаксис С++ (включая те же самые директивы препроцессора). Таким образом, IDL-спецификации могут с успехом использоваться как часть документации проекта.

Выводы

Описания OMG IDL более достоверны и существенно более наглядны, чем описания Microsoft IDL, в роли существенной части спецификации проекта.

Виды объектов

COM
Объекты COM всегда рассматривались (и продолжают рассматриваться) как серверные объекты, которые просто реализуют тот или иной набор методов. Различные объекты, реализующие один и тот же интерфейс и созданные с помощью обращения к одной и той же фабрике классов, не отличаются друг от друга. Объектная ссылка, которую получает клиент, является указателем на интерфейс и не содержит информации о конкретном объекте. Другими словами, COM оперирует объектами, не имеющими состояния. В общем случае, если клиент, используя одну и ту же объектную ссылку, в цикле вызвал десять раз один и тот же метод, он не может быть уверен, что он обратился к одному, а не к двум, пяти или десяти различным объектам. Естественно, объекты без состояния не имеет смысла хранить дольше, чем существует сервер приложений, в котором они были созданы. Такие объекты применительно к распределенным системам называются временными (transient). COM-объект - это конкретная переменная C++, Visual Basic или Pascal, находящаяся в оперативной памяти и существующая, пока работает создавший ее сервер приложений. Он может быть создана по запросу клиента или заранее (например, с помощью MTS). При работе с COM сопоставить с объектом какое-либо состояние - задача прикладного программиста. Это можно сделать, используя определенный режим создания объектов (выбрав модель управления потоками), хранить состояние объекта на стороне клиента (если это возможно) или использовать так называемые моникеры, которые можно рассматривать как обобщение понятия ключа записи в базе данных. Каждый из этих способов имеет очень существенные ограничения.
CORBA
Понятие “объекта” в CORBA принципиально отличается от своего COM-аналога. Объект CORBA не является переменной языка программирования и в общем случае время его существования не связано со временем работы серверных или клиентских приложений. СORBA-объект не занимает никаких ресурсов компьютера - оперативной памяти, сетевых ресурсов и т.п. Эти ресурсы занимает только так называемый “сервант” (servant), который является “инкарнацией” одного или нескольких CORBA-объектов. Именно сервант является переменной языка программирования. Пока не существует сервант, сопоставленный с конкретным объектом CORBA, этот объект не может обслуживать вызовы клиентов, но, тем не менее, он существует. Результатом создания объекта (при этом совершенно не обязательно при этом создается и сопоставляется с этим объектом соответствующий сервант!) является так называемая “объектная ссылка” CORBA. Объектная ссылка сопоставлена с этим, и только с этим объектом, и это сопоставление остается корректным в течение всего срока существования CORBA-объекта (может быть, в течение нескольких лет). Объектная ссылка CORBA правильно интерпретируется ORB’ами от любого производителя программного обеспечения. После уничтожения CORBA-объекта все объектные ссылки на него навсегда теряют смысл. С помощью объектной ссылки клиент вызывает методы объекта, при этом инкарнациями этого объекта могут быть различные серванты (не более одного одновременно), которые физически могут находиться даже на различных компьютерах.

Выводы

Объект COM может рассматриваться как достаточно примитивный частный случай объекта CORBA - как по своим возможностям, так и с точки зрения его цикла жизни. COM и CORBA предлагают совершенно несопоставимые возможности по созданию и управлению объектами, что жизненно важно для создания надежных и масштабируемых приложений.

Способы взаимодействия

COM
COM поддерживает как статический, так и динамический способ взимодействия клиента и сервера. Под динамическим способом понимается подход, когда проверка, реализует ли сервер нужный метод, а также все необходимые действия по выполнению удаленного вызова выполняются на этапе работы клиентского приложения, а не этапе его компиляции. При статическом вызове эти действия выполняются именно на этапе компиляции. Разумеется, статический способ предпочтительнее во всех отношениях (когда он возможен вообще). Для его использования сервер COM должен создать и экспортировать библиотеку типов, которая затем импортируется клиентом и используется как часть клиентского процесса.
CORBA
CORBA также поддерживает статический и динамический способ организации удаленных вызовов.

Выводы

Обе технологии предлагают примерно одинаковые возможности в этом плане. CORBA имеет определенные преимущества при использовании динамических вызовов за счет более развитых средств получения информации о серверах (репозитарии интерфейсов).

Производительность

COM
COM демонстрирует очень высокую производительность. Читатель, интересующийся этим вопросом, найдет большое количество очень интересной информации в прекрасной книге R. Orfali и D. Harkey “Client/server Programming with Java and CORBA”, second edition, Wiley, 1998. Разумеется, производительность существенно зависит от того, какой способ - статический или динамический - вы используете.
CORBA
Для корректного сравнения CORBA и COM с точки зрения производительности необходимо составить целую систему тестов. Кроме того, необходимо учесть влияние использования того или иного языка программирования. На основе информации, приводимой Orfali и Harkey, а также результатов небольшого сравнительного тестирования, проведенного самим автором обзора (использовался Borland C++ Builder 4.0 и VisiBroker 3.3 для C++), можно сказать, что CORBA демонстрирует даже несколько более высокую производительность. Еще раз повторимся: производительность очень сильно зависит от количества и типов аргументов методов (не забывайте, что их нужно упаковать и передать по сети, а затем распаковать), от выбранной модели управления потоками, от используемых языков программирования (клиент и сервер при этом не обязательно должны быть написаны на одном языке), от конкретной реализации CORBA и многих других факторов.

Выводы

И COM, и CORBA демонстрируют примерно одинаковую (и очень высокую) производительность. Для CORBA говорить о конкретных цифрах можно только для конкретной реализации. В качестве примера приведем следующий факт: Inprise/Visigenic Visibroker прозрачным для разработчика образом работает по-разному в зависимости от того, находятся ли клиентский и серверный объект в одном адресном пространстве, в разных адресных пространствах, но на одном компьютере, или на разных компьютерах. Производительность при этом может отличается на порядок.




Сравнительный анализ технологий CORBA и COM 3

Работа пpогpаммиста и шамана имеет много общего - оба боpмpчyт непонятные слова, совеpшают непонятные действия и не могyт объяснить, как оно pаботает.

Масштабируемость

COM
Проблемы обеспечения масштабируемости не были заложены в фундамент технологии, если не считать ориентацию на использование только объектов без состояния. Существенным препятствием для создания масштабируемых приложения является очень жесткая связь между клиентом и сервером (объект, т.е. совокупность ресурсов на сервере, не может быть удален, пока клиент явно не укажет, что этот объект больше не нужен). В реальных проектах необходимо управлять состоянием объектов, и это затрудняет создание масштабируемых приложений, так как это обязанность не COM, а программиста. Сильной стороной COM является гибкая модель управления потоками. Основным инструментом, повышающим уровень масштабируемости COM-систем, является MTS.
CORBA
В отличие от COM, CORBA с самого начала рассматривалась как технология создания масштабируемых систем. Разделение собственно объектов CORBA и их сервантов, схемы соответствия между ними, характеристики объектных адаптеров, модели управления потоками и соединениями, схемы активации серверов приложений, универсальные решения по сохранению состояния объектов, автоматическое управление контекстом транзакций и безопасности - все это очень способствует решению данной проблемы.

Выводы

Масштабируемость системы во многом зависит от качества разработки проекта, продуманности принимаемых решений и квалификации менеджеров проекта и разработчиков. При сравнении технологий можно говорить о предпосылках, способствующих (или, наоборот, препятствующих) достижению нужных требований. При прочих равных условиях CORBA имеет громадные преимущества по cравнению с COM.

Устойчивость к сбоям

COM
Устойчивость к сбоям COM-систем находится на невысоком уровне, в том числе из-за уже упомянутой излишне жесткой привязки клиентов и серверов. Основным средством обеспечения устойчивости к сбоям (оно же средство управления нагрузкой серверов) является диспетчер, который позволяет перенаправлять вызовы клиента на различные сервера приложений COM. Не слишком содействует отказоустойчивости системы и необходимость выполнения “вручную” большого количества действий по управлению транзакциями.
CORBA
CORBA имеет несколько более высокий уровень устойчивости к сбоям за счет большей изоляции клиентов и серверов, автоматического сохранения состояния объектов, более мощной и продуманной схемы управления транзакциями (включая автоматический откат транзакций по тайм-ауту), а также автоматической привязки объектной ссылки и конкретного объекта CORBA.

Выводы

Проблема обеспечения устойчивости к сбоям, так же как и проблемы обеспечения масштабируемости, не рассматривались как первоочередные при разработке концепции COM. С CORBA ситуация обстоит во многом лучше, но проблемы остаются и здесь. Обе технологии не имеют (или почти не имеют) стандарных средств обеспечения устойчивости к сбоям. Такие компоненты, как VisiBroker Smart Agents, не являются стандартным средством CORBA (хотя они и способны решить многие проблемы при работе с реальными проектами.)

Управление транзакциями

COM
Монитором транзакции в COM является MTS. Сервер приложений COM должен быть написан в специальном стиле для того, чтобы иметь возможность взаимодействовать с MTS (такой сервер приложений должен быть реализован в виде DLL). MTS позволяет достаточно гибко управлять режимами выполнения транзакций в системе и поддерживает двухфазное завершение транзакций. Одним из существенных недостатков схемы управления транзакциями COM является необходимость явной передачи контекста транзакции в качестве аргумента при вызове удаленных методов. Такая схема не является ни эффективной, ни гарантирующей от ошибок (особенно при вовлечении в транзакцию большого количества объектов).
CORBA
Управление транзакциями берет на себя так называемый Сервис Управления Транзакциями CORBA (Object Transaction Service, OTS). Он является существенно более гибкой, продуманной и формализованной системой, чем MTS, и содержит все необходимое в рамках CORBA-модели. Сервер приложений CORBA и Сервис транзакций запускаются и работают независимо друг от друга. Важной особенностью CORBA является тесное взаимодействие OTS и ORB, что обеспечивает автоматическое распространение контекста транзакций в многопоточной распределенной среде. Спецификация CORBA предусматривает (необязательную) поддержку вложенных транзакций.

Выводы

На уровне спецификаций Сервис транзакций CORBA имеет определенные преимущества перед MTS. На практике для реализации этих преимуществ нужно предпринять определенные действия. Особенно это касается двухфазного подтверждения транзакций при работе с гетерогенными базами данных. Например, для реализации такой схемы при работе с Java необходимо иметь специальные JDBC-драйвера, которые, насколько мне известно, в настоящий момент не слишком доступны для широкого круга баз данных. В этом плане COM имеет серьезные преимущества за счет взаимодействия MTS со стандартной технологией доступа к базам данных OLE DB/ADO.

Обеспечение безопасности

COM
В настоящий момент система безопасности COM базируется на системе безопасности Windows NT/Windows 2000; кроме того, предусмотрена защита данных при их передаче с использованием Socket Security Layer (SSL). Отдельная проблема - обеспечение безопасности при передаче компонентов ActiveX с использованием протокола HTTP. Здесь используется система электронных подписей, лицензий и т.п. - говоря упрощенно, клиент выполняет код компонента, который пришел с “правильного” сервера.
CORBA
С CORBA дела обстоят сложнее - главным образом, в силу того, что ставилась задача создать универсальную систему безопасности, которая могла бы использовать все основные существующие в этой области технологии. Работа над Сервисом Безопасности (Security Service) продолжалась в течение 2 лет, и ее спецификация была принята в 1996 г. Она содержит около 250 страниц. Она позволяет обеспечить уровень безопасности B2 (уровень, близкий к высшему уровню защиты, который используется в государственных учреждениях). Предусмотрена идентификация пользователя, списки прав доступа к ресурсам, система аудита и многое другое. Особенно приятно, что разработчик не должен явно взаимодействовать с этим сервисом - это задача для ORB. Основная нагрузка возложена на системных администраторов. Все это прекрасно, но существует одна небольшая проблема - где взять полномасштабную, высококачественную реализацию этого сервиса? Такие реализации существуют (Gradient, Concept-5), но их использование ограниченно за пределами США. Сервис безопасности от Borland/Visigenic в этом году еще не появится (хотя работа над ним идет).

Выводы

В настоящий момент для реальных проектов для обеих технологий используются сходные решения в области обеспечения безопасности (идентификация на уровне операционной системы и кодирование информации с помощью SSL). Естественно, возможны варианты. Потенциально CORBA предоставляет существенно большие возможности - проблемы здесь организационного, а не концептуального плана.

Взаимодействие с Internet

COM
Основой взаимодействия через Internet при работе с COM являются расширения возможностей протокола HTTP, выполненные Microsoft. Броузеры Microsoft (Internet Explorer 3 и выше) позволяют выполнять код ActiveX-компонентов, полученных с Web-серверов. Кроме того, URL доступны при использовании COM - с ними могут работать моникеры.
CORBA
Спецификации CORBA не оговаривают использование Internet в качестве особого случая. Интеграция CORBA и Internet выполняется естественным образом - за счет использования протокола IIOP, построенного поверх TCP/IP. URL-имена могут быть использованы в качестве имен для Службы Именования CORBA. На практике производители программного обеспечения предоставляют расширения CORBA, упрощающие работу с Internet (VisiBroker URL Naming Service) или решающие те или иные проблемы - например, “обход” ограничений, накладываемых на апплеты Java, используемых в качестве CORBA-клиентов (например, Borland/Visigenic GateKeeper).

Выводы

CORBA (особенно при использования Java) без каких-либо проблем может быть интегрирована с Internet. Взаимодействие COM и Internet основано на использовании ActiveX и требует использования только броузеров, поддерживающих тег <Object> Microsoft. Косвенным образом проблемы совместной работы COM и Internet могут возникнуть из-за несовместимости виртуальной машины Java Microsoft с другими виртуальными машинами.

Скорость разработки систем

COM
Скорость разработки COM-систем может быть очень высокой за счет интенсивного использования компонентной модели ActiveX, а также универсальных подходов, таких, как OLE DB. Не составляет особого труда создание Internet-приложений с броузером Microsoft в качестве клиентского приложения.
CORBA
Скорость разработки CORBA-систем сильно зависит от используемой технологии. Наверное, максимально эффективным способом создания распределенных систем в настоящий момент является использование Java-технологий, основанных на CORBA - Enterprise JavaBeans и так называемых Application Server’ов, например, BEA WebLogic и Inprise Application Server. Использование этих технологий позволяет чрезвычайно быстро создавать высокоэффективные, масштабируемые, транзакционные сервера приложений. Клиентская часть таких систем может быть написана на любом языке программирования, поддерживающим CORBA.

Выводы

При прочих равных условиях CORBA позволяет создавать распределенные системы быстрее, чем COM, за счет большей функциональности middleware и, соответственно, меньшей нагрузки на прикладного разработчика.

Простота использования

COM
COM очень прост для простых небольших приложений и чрезвычайно сложен как инструмент создания комплексных систем. Он содержит большое количество “узких” мест - недостаточно гибкую стандартную схему маршалинга, отсутствие состояния объектов, низкая устойчивость к сбоям. Технология не является объектно-ориентированной в классическом смысле этого слова, что в общем случае не способствует простоте ее использования. Достоинством технологии является комплексность и универсальность подходов в рамках COM-модели.
CORBA
Сложность CORBA заключается в ее огромных возможностях. Программисту необходимо знать большое количество интерфейсов из различных сервисов CORBA, правильно использовать возможности объектных адаптеров и многое другое. Поскольку CORBA использует различные схемы отображения IDL на разные языки программирования, то программисту в общем случае надо знать их особенности для 2-3 наиболее широко используемых языков - в первую очередь, C++ и Java.

Выводы

Объективно CORBA сложнее за счет того, что она предназначена для решения существенно более сложных задач, чем COM. При разработке реальных проектов нужно иметь в виду, что распределение “интеллектуальной” нагрузки среди участников разработки для COM и CORBA несколько отличается: в случае COM требуются более квалифицированные (но более узко специализированные) программисты, а для CORBA можно задействовать программистов среднего уровня, но чрезвычайно важно иметь квалифицированных архитектора проекта и руководителей групп программистов.

Взаимодействие с другими технологиями

COM
COM является достаточно замкнутой и "самодостаточной" системой. В последнее время Microsoft тесно взаимодействует с OMG на базе создания спецификации моста “COM-CORBA”. Вследствие существенных различий в возможностях, не представляет труда имитировать поведение COM-объекта как CORBA-объекта, но не наоборот.
CORBA
CORBA как технология в настоящий момент (до создания спецификаций, а затем и реализаций своей компонентной модели) является скорее инфраструктурой для создания распределенных систем. Не удивительно, что в этом качестве она активно взаимодействует с другими технологиями - в первую очередь с RMI и Enterprise JavaBeans. CORBA очень тесно - на уровне протокола ESIOP - взаимодействует с широко используемой, но морально устаревшей технологией DCE.

Выводы

CORBA является существенно более открытой, универсальной и гибкой системой, чем COM. И COM, и CORBA способны тесно и эффективно взаимодействовать со стандартными средствами обеспечения безопасности.

Общие выводы

Несмотря на внешнюю похожесть, что вызвано общностью решаемых задач, между COM и CORBA, пожалуй, больше различий, чем сходства. В большинстве случаев либо нецелесообразно использовать CORBA (для небольших и простых проектов под Windows просто по причине относительно высоких затрат на приобретение программного обеспечения, лицензий и пр.), либо практически невозможно использовать COM (для сложных, масштабируемых, высоконадежных проектов или просто при работе в гетерогенных средах, а не только в Windows). Windows-приложения, ориентированные на взаимодействие с Microsoft Office, всегда будут использовать COM; проекты с использованием Java и любых Java-технологий (кроме Microsoft J++), как говорится, “сам бог велел” строить на основе CORBA. Во многих случаях выбор технологии диктует выбор той или иной части проекта: если вы планируете работать, например, с ORACLE 8i, то, безусловно, гораздо лучше ориентироваться на CORBA. Область, где эти технологии реально конкурируют, на мой взгляд, очень невелика.

Как нетрудно заметить, автор настоящего обзора является сторонником CORBA, чего и желает всем своим читателям.

За дополнительной информацией обращайтесь в Interface Ltd.




Сравнение файлов


 function CompareFiles(Filename1,FileName2:string):longint;
 {
   Сравнение файлов
 
   возвращает номер несовпадающего байта,
   (байты отсчитываются с 1)или:
   0 - не найдено отличий,
   -1 - ошибка файла 1
   -2 - ошибка файла 2
   -3 - другие ошибки
 }
 const
   Buf_Size=16384;
 var
   F1,F2:TFileStream;
   i:longint;
   Buff1,Buff2:PByteArray;
   BytesRead1,BytesRead2:integer;
 begin
   Result:=0;
   try
     F1:=TFileStream.Create(FileName1,fmShareDenyNone);
   except
     Result:=-1;
     exit;
   end;
   try
     F2:=TFileStream.Create(FileName2,fmShareDenyNone);
   except
     Result:=-2;
     F1.Free;
     exit;
   end;
   GetMem(Buff1,Buf_Size);
   GetMem(Buff2,Buf_Size);
   try
     if F1.Size> F2.Size then Result:=F2.Size+1
     else if F1.SizeF1.Position) and (Result=0) do begin
       BytesRead1 :=F1.Read(Buff1^,Buf_Size);
       BytesRead2 :=F2.Read(Buff2^,Buf_Size);
       if (BytesRead1=BytesRead2) then begin
         for i:= 0 to BytesRead1-1 do begin
           if Buff1^[i]< > Buff2^[i]
           then begin
             result:=F1.Position-BytesRead1+i+1;
             break;
           end;
         end;
       end else begin
         Result:=-3;
         break;
       end;
     end;
   end;
   except
     Result:=-3;
   end;
   F1.Free;
   F2.Free;
   FreeMem(Buff1,Buf_Size);
   FreeMem(Buff2,Buf_Size);
 end;
 




Быстрое сравнение памяти

Автор: Dennis Passmore

Любая программа стремится занять всю доступную память.

Я ищу функцию, которая была бы эквивалентом сишной функции memcmp.

Я создал следующие две функции, существенно повышающие произвотельность в приложениях, активно работающих с данными. Вам нужно всего-лишь обеспечить контроль типов и границ допустимого диапазона, все остальное они сделают с любым типом данных лучше нас :-) .


 function Keys_are_Equal(var OldRec, NewRec;
 KeyLn : word): boolean; assembler;
 asm
   PUSH    DS
   MOV     AL,01
   CLD
   LES     DI,NewRec
   LDS     SI,OldRec
   MOV     CX,KeyLn
   CLI
   REPE    CMPSB
   STI
   JZ      @1
   XOR     AL,AL
   @1:
   POP     DS
 end;
 
 function First_Key_is_Less(var NewRec, OldRec;
 Keyln : word): boolean; assembler;
 asm
   PUSH    DS
   MOV     AL,01
   CLD
   LES     DI,NewRec
   LDS     SI,OldRec
   MOV     CX,KeyLn
   CLI
   REPE    CMPSB
   STI
   JZ      @5
   JGE     @6
   @5: XOR     AL,AL
   @6: POP     DS
 end;
 




Сравнить быстродействия алгоритмов

Если вас сколько-нибудь интересует скорость работы вашей программы, то нужно смерить скорость алгоритмов и сравнивать их. Здесь я привожу пример, сравнивающий четыре способа возведения 2 в степень 30.


 uses Math;
 
 procedure TForm1.Button1Click(Sender: TObject);
 var
   Res, Exponent: integer;
   Res1: real;
   t, i: integer;
 begin
   Exponent := 30;
 
   Application.ProcessMessages;
   t := GetTickCount;
   for i := 1 to 1000000 do
     Res := 1 shl Exponent;
   Form1.Caption := Form1.Caption + ' ' +
   IntToStr(GetTickCount - t);
 
   Application.ProcessMessages;
   t := GetTickCount;
   for i := 1 to 1000000 do
     Res1 := LdExp(1, Exponent);
   Form1.Caption := Form1.Caption + ' ' +
   IntToStr(GetTickCount - t);
 
   Application.ProcessMessages;
   t := GetTickCount;
   for i := 1 to 1000000 do
     Res1 := IntPower(2, Exponent);
   Form1.Caption := Form1.Caption + ' ' +
   IntToStr(GetTickCount - t);
 
   Application.ProcessMessages;
   t := GetTickCount;
   for i := 1 to 1000000 do
     Res1 := Power(2, Exponent);
   Form1.Caption := Form1.Caption + ' ' +
   IntToStr(GetTickCount - t);
 end;
 




<< ВЕРНУТЬСЯ В ОГЛАВЛЕНИЕ



Материалы находятся на сайте https://exelab.ru/pro/



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS