Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / CreateComObject in thread / 24 сообщений из 24, страница 1 из 1
30.11.2020, 09:38
    #40023253
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
Добрый день.
Может кто объяснить причину ошибки?
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, Winapi.ActiveX, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Win.ComObj, Vcl.StdCtrls;

const
  CLSID_Test: TGUID = '{FEEFE310-8A59-46C6-8704-7256A3C2FB42}';

type
  ITest = interface(IUnknown)
    ['{CB201791-8BF5-4ACA-B57F-88731E6C3D4D}']
    procedure Test; safecall;
  end;

  TTest = class(TComObject, ITest)
  private
    procedure Test; safecall;
  end;

  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

uses
  System.Win.ComServ;

procedure TForm2.Button1Click(Sender: TObject);
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      CoInitializeEx(nil, COINIT_MULTITHREADED);
      try
        var A := CreateComObject(CLSID_Test);
        var B := A as ITest; // 'Interface not supported'
        B.Test();
      finally
        CoUninitialize();
      end;
    end
  ).Start();
end;

{ TTest }

procedure TTest.Test;
begin

end;

initialization
  var X := TComObjectFactory.Create(ComServer, TTest, CLSID_Test,
    'Test', 'Test', ciMultiInstance, tmApartment);
  X.RegisterClassObject();

end.



Если это выполнить в консольном приложения - работает.
Если убрать поток - работает.
...
Рейтинг: 0 / 0
30.11.2020, 10:47
    #40023271
ziv-2014
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
X-Cite,
Сначала приведи к IUnknown, а потом через Supports получи ITest
...
Рейтинг: 0 / 0
30.11.2020, 10:55
    #40023272
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
ziv-2014,

var A := CreateComObject(CLSID_Test);

A - это и есть IUnknown
...
Рейтинг: 0 / 0
30.11.2020, 11:10
    #40023273
Zelius
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
X-Cite,

сейчас уже не помню, но кажется, что кто первый инициализировал ком в приложении того и тапки, а первым идет апартмент, ЕМНИП. и кстати CoInitializeEx - функция, уверен, что отрабатывает успешно?

у меня для сервиса использующего ActiveX компонент написан такой юнит и он стоит первым в проекте
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
program Project1;

uses
  ComUtils in 'ComUtils.pas',

..................


unit ComUtils;

interface

implementation

const
  COINIT_MULTITHREADED      = 0;      // OLE calls objects on any thread.
  COINIT_APARTMENTTHREADED  = 2;      // Apartment model
  COINIT_DISABLE_OLE1DDE    = 4;      // Dont use DDE for Ole1 support.
  COINIT_SPEED_OVER_MEMORY  = 8;      // Trade memory for speed.

function CoInitializeEx(pvReserved: Pointer; coInit: Longint): HResult; stdcall; external 'ole32.dll' name 'CoInitializeEx';
procedure CoUninitialize; stdcall; external 'ole32.dll' name 'CoUninitialize';

function Succeeded(Res: HResult): Boolean;
begin
  Result := Res and $80000000 = 0;
end;

procedure InitMultiThreadedCom;
var
  HRes: HResult;
begin
  HRes := CoInitializeEx( nil, COINIT_MULTITHREADED);
  if NOT Succeeded(HRes) then
    Halt(123);
end;

initialization
  InitMultiThreadedCom;
finalization
  CoUninitialize;
end.
...
Рейтинг: 0 / 0
30.11.2020, 11:31
    #40023281
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
я во всех своих проектах инициализирую/деинициализирую внутри TThread.Execute (просто пример для показа, без проверки Succeeded()), и всё работает:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
procedure MyThread.Execute;
begin
  CoInitializeEx(nil, COINIT_MULTITHREADED);
  OleInitialize(nil);
  
  { чтото делаем }

  OleUninitialize;
  CoUninitialize;
end;
...
Рейтинг: 0 / 0
30.11.2020, 11:35
    #40023283
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
Zelius,

Спасибо..
В общем, что получилось...
Описал
Код: pascal
1.
function CoGetApartmentType(out pAptType: TAPTTYPE; out pAptQualifier: TAPTTYPEQUALIFIER): HRESULT; stdcall; external 'Ole32.dll';


Чтобы узнать какие апартаменты используются
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
procedure TForm2.Button1Click(Sender: TObject);
var
  X1: TAPTTYPE;
  Y1: TAPTTYPEQUALIFIER;
begin
  CoGetApartmentType(X1, Y1);
  // APTTYPE_NA	A neutral apartment.
  // APTTYPEQUALIFIER_NONE	No qualifier information for the current COM apartment type is available.
  TThread.CreateAnonymousThread(
    procedure
    var
      X2: TAPTTYPE;
      Y2: TAPTTYPEQUALIFIER;
    begin
      CoInitializeEx(nil, COINIT_MULTITHREADED);
      try
        CoGetApartmentType(X2, Y2);
        // APTTYPE_STA	A single-threaded apartment.
        // APTTYPEQUALIFIER_NONE	No qualifier information for the current COM apartment type is available.
        var A := CreateComObject(CLSID_Test);
        var B := A as ITest;
        B.Test();
      finally
        CoUninitialize();
      end;
    end
  ).Start();
end;




Код: pascal
1.
2.
// В секции инициализации почему-то не помогло...
CoInitFlags := COINIT_MULTITHREADED;



Сделал отдельный модуль и указал вначале как у вас и заработало...

// APTTYPE_STA A single-threaded apartment.
// APTTYPEQUALIFIER_NONE No qualifier information for the current COM apartment type is available.

В обоих случаях
...
Рейтинг: 0 / 0
30.11.2020, 11:51
    #40023288
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
Нашел, что OleInitialize вызывается раньше, чем срабатывает InitComObj в System.Win.ComObj
Походу это бага... Даже если указать System.Win.ComObj первым, все равно OleInitialize вызывается раньше.
...
Рейтинг: 0 / 0
30.11.2020, 11:52
    #40023289
Zelius
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
asutp2,

вот интересно какая модель в итоге в потоке, попробуй CoGetApartmentType
...
Рейтинг: 0 / 0
30.11.2020, 12:00
    #40023291
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
Ну вот...
Код: pascal
1.
2.
3.
4.
constructor TApplication.Create(AOwner: TComponent);
.....
if not IsLibrary then
    FNeedToUninitialize := Succeeded(OleInitialize(nil));



Логично, что создается Application

и потом вызывается Application.Initialize; уже в котором вызывается InitComObj в System.Win.ComObj
...
Рейтинг: 0 / 0
30.11.2020, 12:15
    #40023300
Zelius
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
asutp2,

вот в справке интересно
авторOleInitialize calls CoInitializeEx internally to initialize the COM library on the current apartment. Because OLE operations are not thread-safe, OleInitialize specifies the concurrency model as single-thread apartment.
Once the concurrency model for an apartment is set, it cannot be changed. A call to OleInitialize on an apartment that was previously initialized as multithreaded will fail and return RPC_E_CHANGED_MODE.

так что сдается мне у тебя не COINIT_MULTITHREADED
...
Рейтинг: 0 / 0
30.11.2020, 12:31
    #40023313
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
Однозначно баг, потому что в справке сказано
авторCoInitFlags
Specifies the level of threading support requested for a COM server .EXE.

CoInitFlags controls the way COM is initialized for threading support. This variable only affects executables (.EXEs), not in-process servers (.DLLs and .OCXs).


Однако OleInitialize переводит в нейтральные аппартаменты,
И уже потом сменить их на другие нельзя.. Поэтому текст не будет соответствовать действительности..
P.S. попробую еще вариант с маршалингом апартаментов реализовать, но это такое себе...
...
Рейтинг: 0 / 0
30.11.2020, 13:00
    #40023320
vavan
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
засада бывает когда стороння либа балуется, как например было с b92583 у девэксов, но там по крайней мере обсудить можно и иногда даже разрешить

а порой неприятнее бывает когда прямо по ходу работы сторонние драйвера (принтерные скажем) могут вмешиваться

X-Cite
попробую еще вариант с маршалингом апартаментов реализовать, но это такое себе
помнится вроде когда-то CoMarshalInterThreadInterfaceInStream считалось одним из самых длинных названий
...
Рейтинг: 0 / 0
30.11.2020, 14:16
    #40023346
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
При чем здесь потоки и секция инициализации модуля?

Идем в
Код: sql
1.
HKCR\CLSID\{FEEFE310-8A59-46C6-8704-7256A3C2FB42}\InProcServer32

или
Код: sql
1.
HKLM\SOFTWARE\Wow6432Node\Classes\CLSID\{FEEFE310-8A59-46C6-8704-7256A3C2FB42}\InProcServer32

и смотрим на значение параметра ThreadingModel. Если там не Both, то CoInitializeEx должно вызываться ровно с тем флагом, который там написан.
...
Рейтинг: 0 / 0
30.11.2020, 14:47
    #40023356
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
_Vasilisk_,

Это если inproc сервер будет...
В Delphi ThreadingModel пишется если библиотека, при регистрации... А у меня сервер exe, при чем только пока запущен, поэтому в реестре ничего нет.
Клиент будет вызывать сервер в том же процессе, только мне надо, чтобы в произвольном потоке..
...
Рейтинг: 0 / 0
30.11.2020, 15:05
    #40023367
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
X-Cite
Код: pascal
1.
2.
  var X := TComObjectFactory.Create(ComServer, TTest, CLSID_Test,
    'Test', 'Test', ciMultiInstance, tmApartment);

какие еще вопросы могли остаться после этого?
...
Рейтинг: 0 / 0
30.11.2020, 15:12
    #40023369
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
_Vasilisk_,

Все перепробовал - ничего не работает, из-за того, что OleInitialize вызывается первой...
Если первым вызвать CoInitializeEx(nil, COINIT_MULTITHREADED), то tmApartment работает.

Еще раз.
1) Сервер - это exe приложение и не регистрируется в реестре.
2) Клиент это же самое приложение. Вызов клиентского кода будет в разных потоках, но в том же процессе.
...
Рейтинг: 0 / 0
30.11.2020, 15:42
    #40023385
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
X-Cite
Все перепробовал
Обманываете. Или пишите
Код: sql
1.
CoInitializeEx(nil, COINIT_APARTMENTTHREADED)

или
Код: pascal
1.
2.
var X := TComObjectFactory.Create(ComServer, TTest, CLSID_Test,
    'Test', 'Test', ciMultiInstance, tmFree);

(или tmBoth)
X-Cite
1) Сервер - это exe приложение и не регистрируется в реестре
Сервер регистрируется в подсистеме COM
X-Cite
2) Клиент это же самое приложение
При вызове CreateComObject это не имеет никакого значения
X-Cite
то tmApartment работает
Потому, что все вызовы уходят в главный поток.

Потоковые модели должны совпадать. Точка.
...
Рейтинг: 0 / 0
30.11.2020, 16:04
    #40023395
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
_Vasilisk_,

После вызова OleInitialize модель Neutral

Код ниже выполняется уже после того как OleInitialize внутри TApplication.Create выполнился
Код: pascal
1.
2.
3.
4.
5.
6.
7.
var
  X: TComObjectFactory;

initialization
  X := TComObjectFactory.Create(ComServer, TTest, CLSID_Test,
    'Test', 'Test', TClassInstancing.ciMultiInstance, TThreadingModel.tmFree/tmBoth/tmNeutral);
  X.RegisterClassObject();




Когда в ответ на CreateComObject вызывается
Код: pascal
1.
2.
function TComObjectFactory.CreateInstance(const UnkOuter: IUnknown;
  const IID: TGUID; out Obj): HResult;


То в этот момент модель Neutral
И почему-то не видит ITest

В первом сообщении я привел пример.
Как без игр с uses сделать так, чтобы работало?
Исходя из анализа кода vcl - никак...
...
Рейтинг: 0 / 0
30.11.2020, 17:30
    #40023429
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
X-Cite
Код ниже выполняется уже после того как OleInitialize внутри TApplication.Create выполнился
Еще раз большими буквами: ВАЖНА ТОЛЬКО ИНИЦИАЛИЗАЦИЯ ТОГО ПОТОКА, В КОТОРОМ ПРОИСХОДИТ РАБОТА С СОМ. Абсолютно все равно, что происходит в TApplication.Create. Этот код выполняется в главном потоке.

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

И это я еще не спрашиваю, зачем вам понадобился COM в рамках одного процесса
...
Рейтинг: 0 / 0
30.11.2020, 18:11
    #40023444
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
_Vasilisk_,

окей, а что скажешь на это?

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
uses
  System.Win.ComServ;

procedure TForm2.Button1Click(Sender: TObject);
begin
  TThread.CreateAnonymousThread(
    procedure
    begin // код здесь - это имитация клиента
      CoInitializeEx(nil, COINIT_MULTITHREADED);
      try
        var A: IUnknown := CreateComObject(CLSID_Test);
        var B: ITest := A as ITest; // 'Interface not supported'
        B.Test();
      finally
        CoUninitialize();
      end;
    end
  ).Start();
end;

initialization
  var X := TComObjectFactory.Create(ComServer, TTest, CLSID_Test,
    'Test', 'Test', TClassInstancing.ciMultiInstance, TThreadingModel.tmFree);
  X.RegisterClassObject();

end.
...
Рейтинг: 0 / 0
30.11.2020, 18:48
    #40023456
ziv-2014
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
X-Cite,
del
...
Рейтинг: 0 / 0
01.12.2020, 08:40
    #40023530
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
...
Рейтинг: 0 / 0
02.12.2020, 14:01
    #40023957
a.t
a.t
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
X-CiteНашел, что OleInitialize вызывается раньше, чем срабатывает InitComObj в System.Win.ComObj
Походу это бага... Даже если указать System.Win.ComObj первым, все равно OleInitialize вызывается раньше

это не баг, это фича. для корректной работы oleinitflags нужно задавать до вызова application.initialize.

см. секцию инициализации comobj.
...
Рейтинг: 0 / 0
02.12.2020, 15:23
    #40023982
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateComObject in thread
a.t
для корректной работы oleinitflags
Которое оказывает влияние только на инициализацию главного потока и никак не влияет на дополнительные
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / CreateComObject in thread / 24 сообщений из 24, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]