|
COM и C# | ☑ | ||
---|---|---|---|---|
0
oleg_km
24.04.13
✎
13:43
|
Написал на C# два COM-объекта, оба в одной dll в одном проекте. Хочу в метод одного передавать ссылку на объект второго, чтобы метод первого дернул метод второго. Пробовал разные варианты:
1) В параметрах нужного метода первого объекта просто указал интерфейс второго: при вызове выскочило Неизвестная ошибка 2) В параметрах нужного метода первого объекта указал object, в теле метода попытался следать приведение и через () и через as, ругается: Нет такого интерфейса 3) В параметрах нужного метода первого объекта указал dynamic, все заработало, но мне так не нравится: нет типизации, нужен .Net 4, нужно на компьютер пользователя устанавливать доп. сборку Примерный код: namespace TestCOM { [Guid("E5B23F96-411D-4A67-AFBA-B3DF6B3B0ACB")] public interface ITestCOM { [DispId(4)] void TestOCX(ITestActiveX oTest); // 1-й вариант void TestOCX(object oTest); // 2-й вариант void TestOCX(dynamic oTest); // 3-й вариант } [ProgId("TestCOM.Test"), ClassInterface(ClassInterfaceType.None), Guid("1BD846DC-63F2-4070-AF23-8AECD6C158CC")] public class CTestCOM : ITestCOM { public void TestOCX(ITestActiveX oTest) // 1-й { oTest.ShowEvent("Test parameter"); } public void TestOCX(object oTest) // 2-й { ITestActiveX ot = (ITestActiveX) oTest; ot.ShowEvent("Test parameter"); } public void TestOCX(dynamic oTest) // 3-й { oTest.ShowEvent("Test parameter"); } } [Guid("D783DC48-8FB0-4fe9-BDC2-0CEE3F5E8921")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface ITestActiveX { [DispId(6)] void ShowEvent(string msg); } [Guid("A94CEA0F-1CD3-4829-A75E-B8A81A1EE56D")] [ProgId("TestCOM.TestActiveX")] [ComDefaultInterface(typeof(ITestActiveX))] [ClassInterface(ClassInterfaceType.None)] public class TestActiveX : UserControl, ITestActiveX { public void ShowEvent(string msg) { MessageBox.Show(msg); } } } Очень хочу первый вариант, если что готов и на второй |
|||
1
Rie
24.04.13
✎
13:49
|
(0) Так а где сам вызов-то?
|
|||
2
Serginio1
24.04.13
✎
13:49
|
[ClassInterface(ClassInterfaceType.AutoDual), ComVisible(true), Guid("A94CEA0F-1CD3-4829-A75E-B8A81A1EE56D"), ProgId("TestCOM.TestActiveX")]
|
|||
3
ptrtss
24.04.13
✎
13:58
|
||||
4
oleg_km
24.04.13
✎
13:58
|
(1) TestOCX в интерфейсе ITestCOM, ну в 1С примерно так:
об1 = Новый COMОбъект("TestCOM.Test"); об2 = Новый COMОбъект("TestCOM.TestActiveX"); об1.TestOCX(об2); (2) Имеется ввиду AutoDual вместо None? Только что попробовал, тоже самое. |
|||
5
oleg_km
24.04.13
✎
14:01
|
(3) Так это вроде соответствует второму варианту. вызов метода идет, но не проходит приведение типа. Ругается что интерфейс D783DC48-8FB0-4fe9-BDC2-0CEE3F5E8921 (ITestActiveX) не отдается QueryInterface
|
|||
6
Serginio1
24.04.13
✎
14:11
|
(4) У тебя не получится второй вызвать.
Можно в interface ITestCOM Создать метод который создает экземпляр класса TestActiveX. |
|||
7
Serginio1
24.04.13
✎
14:12
|
Например
ITestActiveX ПолучитьОббъектTestActiveX(); |
|||
8
Serginio1
24.04.13
✎
14:14
|
Об2=Об1.ПолучитьОббъектTestActiveX();
|
|||
9
oleg_km
24.04.13
✎
14:26
|
(6) Подожди, в 3-м варианте через dynamic получается же. Код из (4) в третьем варианте нормально работает, просто мне само использование dynamic не нравится.
|
|||
10
Serginio1
24.04.13
✎
14:56
|
Замени void TestOCX(ITestActiveX oTest);
На void TestOCX(IDispoatch oTest); это будет вариант с оbject и dynamic. Просто получается разные соклассы. |
|||
11
oleg_km
24.04.13
✎
15:02
|
(10) Вот так:
void TestOCX([MarshalAs(UnmanagedType.IUnknown)] object oTest); Пробовал, тоже не получилось |
|||
12
Serginio1
24.04.13
✎
15:15
|
IUnknown<>IDispatch
|
|||
13
Serginio1
24.04.13
✎
15:16
|
Ты лучше скажи
Об2=Об1.ПолучитьОббъектTestActiveX(); об1.TestOCX(об2); работает? |
|||
14
oleg_km
24.04.13
✎
15:20
|
(12) И с IDispatch тоже пробовал.
|
|||
15
oleg_km
24.04.13
✎
15:29
|
(13) Дело в том что объекты создаются независимо. но я сейчас попробовал наоборот во второй объект передать первый и все прошло нормально. Надо аккуратно все пересобрать
|
|||
16
Serginio1
24.04.13
✎
16:42
|
(15) Первый это основной coClass. Поэтому я и предложил попробовать 13
|
|||
17
Ковычки
24.04.13
✎
16:43
|
Вы написали не ком
|
|||
18
oleg_km
24.04.13
✎
16:55
|
(16) Первый это основной coClass
Как ты это понял, вообще-то это просто два разных КОМа, просто в одном проекте. Если быть точным один просто ком, второй активикс: CTestCOM : ITestCOM - просто ком TestActiveX : UserControl, ITestActiveX - активикс, я просто выкинул всякие события прочее (17) А как тогда его дергает 1С? 1С напрямую научилось подключаться к .NET? |
|||
19
oleg_km
24.04.13
✎
16:56
|
(16) Первый это основной coClass
Вот смотрю в библиотеке типов: у каждого свой кокласс |
|||
20
Serginio1
24.04.13
✎
18:29
|
Есть такая функция dllgetclassobject которая находит нужный
DLL v8: Можно ли использовать библиотеки без COM-сервера? И обычно вторым параметром передаетя IDispatch. Но проблема скорее всего в [ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch)] public class ContainerControl : ScrollableControl, IContainerControl ComVisible(true), Designer("System.Windows.Forms.Design.ControlDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), DefaultEvent("Load"), DesignerCategory("UserControl"), ClassInterface(ClassInterfaceType.AutoDispatch), Designer("System.Windows.Forms.Design.UserControlDocumentDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(IRootDesigner))] public class UserControl : ContainerControl То есть UserControl сам реализует IDispatch. Возможно в этом проблема |
|||
21
Serginio1
24.04.13
✎
18:31
|
Кстати ты 13 не пробовал?
|
|||
22
Serginio1
24.04.13
✎
18:46
|
Посмотри http://proasutp.com/articles/scadasystems/vijeocitect/create_an_activex_control_for_scada_vijeo_citect_on_microsoft_visual_c_shapr_2012.html?page=2
Но там [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] Да и для [ProgId("TestCOM.Test"), ClassInterface(ClassInterfaceType.None), Guid("1BD846DC-63F2-4070-AF23-8AECD6C158CC")] public class CTestCOM : ITestCOM [InterfaceType(ComInterfaceType.InterfaceIsDual)] |
|||
23
oleg_km
25.04.13
✎
11:17
|
Решил проблему. Дело в том что когда я написал пример вызывающего кода:
об1 = Новый COMОбъект("TestCOM.Test"); об2 = Новый COMОбъект("TestCOM.TestActiveX"); об1.TestOCX(об2); я немножко слукавил - только один объект создается конструкцией CreateObject, второй то сажается на форму как ActiveX. Среда 1С дает мне доступ к этому объекту как ссылку на элемент формы и судя по всему это какой-то контейнер. Т.е. когда я вызываю методы своего объекта, на самом деле я дергаю контейнер, а контейнер уже дергает мой объект, а когда я передаю ссылку в другой объект, он пытается привести тип в соответствие с указанным типом моего параметра и обнаруживает, что тип (тип контейнера) у него отсутствует. Я просто в ActiveX добавил метод, который возвращает указатель на себя, приведенный к типу своего интерфейса: public ITestOCX1 GetThis() { return (ITestOCX1)this; } И вызов теперь выглядит: обТест = Новый COMОбъект("TestCOM.TestCOM1"); обТест.CallTest(ЭлементыФормы.TestOCX1.GetThis()); Если это коряво, то как делать правильно? |
|||
24
Serginio1
25.04.13
✎
11:30
|
Это нормально, об этом я тебе и писал в 22 (просто идет расширение GetsIDOfNames и Invoke ), но мало чем отличается от того, что я предлагал тебе в 13.
|
|||
25
oleg_km
25.04.13
✎
11:37
|
(24) Я теперь понял в чем заключался совет: ссылку для дальнейшей работы в .NET нужно получать не от 1С, а от .NET
|
|||
26
Serginio1
25.04.13
✎
12:12
|
(25) Я тебе в 20 писал как получает 1С IDispatch через dllgetclassobject . TestActiveX по сути реализует два IDispatch,но расширяет он методы UserControl котрый ничего не знает об ITestCOM. Но в Net могли бы и переопределить QueryInterface, но почему то они этого не сделали.
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |