Показать сообщение отдельно
Старый 24.07.2004, 14:57   #20  
Alks is offline
Alks
Участник
 
336 / 41 (2) +++
Регистрация: 23.07.2004
Адрес: г. Новокузнецк
Короче намучился я с этой хренью вдоволь, и решил что лучше не морочить себе голову и делать через таймер.
Привожу исходный код двух основных модулей моего ActiveX-а, который запускает поток из которого совершенно безопасно генерируется событие для Axapta. Казалось бы всё пучком, но возникли две непреодолимые для меня сейчас проблемы:
1. создание и передача "safe" указателя на интерфейс IAxBarScanner драйверу сканнера (который разумеется сам не делает CoGetInterfaceAndReleaseStream, а если пытаться сделать его в основном потоке программы сразу после CoMarshalInterThreadInterfaceInStream, то черезчур умная ф-я возвращает прямой указатель, а не маршализированный).
2. вследствии непонятной мешанины с AddRef/Relese ActiveX застревает в памяти (откуда то берутся целых 5 ссылок на него и он не уничтожается как должен был бы), в результате объекты плодятся безконтрольно и ахапта при выходе остаётся в списке задач

Думаю что всё это вопросы разрешимые, но заниматься ими уже надоело, да и сроки поджимают, времени распылятся по мелочам, когда менее элегантное решение всё таки существует нет.

PHP код:
unit AxBarScannerImpl;

interface

uses
  Windows
ActiveXClassesControlsGraphicsMenusFormsStdCtrls,
  
ComServStdVCLAXCtrlsAxBarScannerXControl_TLBSysUtils;

type
  TAxBarScanner 
= class(TActiveXControlIAxBarScanner)
  private
    { Private 
declarations }
    
FDelphiControlTStaticText;
    
FEventsIAxBarScannerEvents;
    
FTestThreadTThread;
    
procedure ClickEvent(SenderTObject);
    
procedure DblClickEvent(SenderTObject);
  protected
    { Protected 
declarations }
    
procedure DefinePropertyPages(DefinePropertyPageTDefinePropertyPage); override;
    
procedure EventSinkChanged(const EventSinkIUnknown); override;
    
procedure InitializeControloverride;
    function 
Get_AlignmentTxAlignmentsafecall;
    function 
Get_AutoSizeWordBoolsafecall;
    function 
Get_BorderStyleTxStaticBorderStylesafecall;
    function 
Get_CaptionWideStringsafecall;
    function 
Get_ColorOLE_COLORsafecall;
    function 
Get_CursorSmallintsafecall;
    function 
Get_DoubleBufferedWordBoolsafecall;
    function 
Get_DragCursorSmallintsafecall;
    function 
Get_DragModeTxDragModesafecall;
    function 
Get_EnabledWordBoolsafecall;
    function 
Get_FontIFontDispsafecall;
    function 
Get_ParentColorWordBoolsafecall;
    function 
Get_ShowAccelCharWordBoolsafecall;
    function 
Get_VisibleWordBoolsafecall;
    function 
Get_VisibleDockClientCountIntegersafecall;
    
procedure _Set_Font(const ValueIFontDisp); safecall;
    
procedure Set_Alignment(ValueTxAlignment); safecall;
    
procedure Set_AutoSize(ValueWordBool); safecall;
    
procedure Set_BorderStyle(ValueTxStaticBorderStyle); safecall;
    
procedure Set_Caption(const ValueWideString); safecall;
    
procedure Set_Color(ValueOLE_COLOR); safecall;
    
procedure Set_Cursor(ValueSmallint); safecall;
    
procedure Set_DoubleBuffered(ValueWordBool); safecall;
    
procedure Set_DragCursor(ValueSmallint); safecall;
    
procedure Set_DragMode(ValueTxDragMode); safecall;
    
procedure Set_Enabled(ValueWordBool); safecall;
    
procedure Set_Font(var ValueIFontDisp); safecall;
    
procedure Set_ParentColor(ValueWordBool); safecall;
    
procedure Set_ShowAccelChar(ValueWordBool); safecall;
    
procedure Set_Visible(ValueWordBool); safecall;
    
procedure ActivateScanData(const DataWideString); safecall;
    
procedure ShowRefCountsafecall;
  public
    
destructor Destroyoverride;
    
//procedure AfterConstruction; override;
  
end;

implementation

uses ComObj
TestThread;

TAxBarScanner }

procedure TAxBarScanner.DefinePropertyPages(DefinePropertyPageTDefinePropertyPage);
begin
  
{TODODefine property pages here.  Property pages are defined by calling
    DefinePropertyPage with the 
class id of the page.  For example,
      
DefinePropertyPage(Class_AxBarScannerPage); }
end;

procedure TAxBarScanner.EventSinkChanged(const EventSinkIUnknown);
begin
  FEvents 
:= EventSink as IAxBarScannerEvents;
end;

procedure TAxBarScanner.InitializeControl;
begin
  
// Это нужно дельфям
  
FDelphiControl := Control as TStaticText;
  
FDelphiControl.OnClick := ClickEvent;
  
FDelphiControl.OnDblClick := DblClickEvent;

  
// Создаём поток
  
FTestThread := AxTestThread.CreateTrue );

  
// Сериализуем указатель на интерфейс в поток...
  
if not SucceededCoMarshalInterThreadInterfaceInStreamIID_IAxBarScanner,
    
Self as IAxBarScanner, (FtestThread as AxTestThread).Strm ) ) then
  begin
    MessageBox
0'CoMarshal...() error''Error'MB_OK );
  
end;

  
// Если попробовать заменить эту хитрую процедуру простым присваиванием типа:
  // (FTestThread as AxTestThread).Scanner := Self as IAxBarScanner;
  // не пропуская указатель на интерфейс через ф-ии принудительного маршаллинга,
  // то аксапта неминуемо повиснет.
  // После десериализации любые вызовы к интерфейсу будут проходить через механизм
  // single threaded apartment model и, как следствие, выполнятся
  // в рамках работы основного потока программы GetMessage/DispatchMessage.

  // Активируем работу потока
  
FTestThread.Resume;
end;

// ... вырезал ненужный код генерируемый дельфи

destructor TAxBarScanner.Destroy;
begin
  
// Убиваем поток
  //_AddRef;
  //_AddRef;
  
FTestThread.Terminate;
  
FTestThread.WaitFor;
  
FTestThread.Free;

  
inherited;
end;

procedure TAxBarScanner.ActivateScanData(const DataWideString);
begin
  
if FEvents <> nil then
    FEvents
.OnScanDataData );
end;

procedure TAxBarScanner.ShowRefCount;
begin
  MessageBox
0PCharIntToStrRefCount ) ), 'RefCount'MB_OK );
end;

initialization
  TActiveXControlFactory
.Create(
    
ComServer,
    
TAxBarScanner,
    
TStaticText,
    
Class_AxBarScanner,
    
1,
    
'',
    
0,
    
tmSingle);
end
PHP код:
unit TestThread;

interface

uses
  Classes
AxBarScannerImplAxBarScannerXControl_TLBActiveX;

type
  AxTestThread 
= class(TThread)
  private
    { Private 
declarations }
  protected
    
procedure Executeoverride;
  public
    
StrmIStream;
    
ScannerIAxBarScanner// Собственно интерфейс ActiveX объекта
  
end;

implementation

uses Windows
;

procedure AxTestThread.Execute;
begin
  CoInitializeEx
nilCOINIT_APARTMENTTHREADED );
  
Strm._AddRef;
  if 
not SucceededCoGetInterfaceAndReleaseStreamStrmIID_IAxBarScannerScanner ) ) then
  begin
    MessageBox
0'CoGetIface...() error'''MB_OK );
  
end;
  
Strm := nil;

  while 
not Terminated do
  
begin
    Sleep
1000 );
    if 
not Terminated then
    begin
      Beep
300100 );
      
Scanner.ActivateScanData'Debil' );
    
end;
  
end;
  
Scanner := nil;
  
  
CoUninitialize;
end;

end