powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / CreateComObject in thread
24 сообщений из 24, страница 1 из 1
CreateComObject in thread
    #40023253
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый день.
Может кто объяснить причину ошибки?
Код: 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
CreateComObject in thread
    #40023271
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite,
Сначала приведи к IUnknown, а потом через Supports получи ITest
...
Рейтинг: 0 / 0
CreateComObject in thread
    #40023272
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014,

var A := CreateComObject(CLSID_Test);

A - это и есть IUnknown
...
Рейтинг: 0 / 0
CreateComObject in thread
    #40023273
Zelius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
CreateComObject in thread
    #40023281
asutp2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
я во всех своих проектах инициализирую/деинициализирую внутри 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
CreateComObject in thread
    #40023283
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
CreateComObject in thread
    #40023288
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нашел, что OleInitialize вызывается раньше, чем срабатывает InitComObj в System.Win.ComObj
Походу это бага... Даже если указать System.Win.ComObj первым, все равно OleInitialize вызывается раньше.
...
Рейтинг: 0 / 0
CreateComObject in thread
    #40023289
Zelius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asutp2,

вот интересно какая модель в итоге в потоке, попробуй CoGetApartmentType
...
Рейтинг: 0 / 0
CreateComObject in thread
    #40023291
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну вот...
Код: 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
CreateComObject in thread
    #40023300
Zelius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
CreateComObject in thread
    #40023313
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Однозначно баг, потому что в справке сказано
автор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
CreateComObject in thread
    #40023320
vavan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
засада бывает когда стороння либа балуется, как например было с b92583 у девэксов, но там по крайней мере обсудить можно и иногда даже разрешить

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

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

Идем в
Код: 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
CreateComObject in thread
    #40023356
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

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

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

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

Еще раз.
1) Сервер - это exe приложение и не регистрируется в реестре.
2) Клиент это же самое приложение. Вызов клиентского кода будет в разных потоках, но в том же процессе.
...
Рейтинг: 0 / 0
CreateComObject in thread
    #40023385
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
CreateComObject in thread
    #40023395
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_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
CreateComObject in thread
    #40023429
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
Код ниже выполняется уже после того как OleInitialize внутри TApplication.Create выполнился
Еще раз большими буквами: ВАЖНА ТОЛЬКО ИНИЦИАЛИЗАЦИЯ ТОГО ПОТОКА, В КОТОРОМ ПРОИСХОДИТ РАБОТА С СОМ. Абсолютно все равно, что происходит в TApplication.Create. Этот код выполняется в главном потоке.

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

И это я еще не спрашиваю, зачем вам понадобился COM в рамках одного процесса
...
Рейтинг: 0 / 0
CreateComObject in thread
    #40023444
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_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
CreateComObject in thread
    #40023456
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite,
del
...
Рейтинг: 0 / 0
CreateComObject in thread
    #40023530
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
CreateComObject in thread
    #40023957
a.t
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
a.t
Гость
X-CiteНашел, что OleInitialize вызывается раньше, чем срабатывает InitComObj в System.Win.ComObj
Походу это бага... Даже если указать System.Win.ComObj первым, все равно OleInitialize вызывается раньше

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

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


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