Аннотация:
В этой статье мы с вами обсудим вопросы взаимодействия с компонентами .NET при помощи COM. Прочитав и осмыслив то, что здесь изложено, вы сможете с легкостью использовать компоненты .NET в ваших приложениях при помощи COM. А значит, сможете из любого вашего старого приложения, использующего WinApi, использовать практически все современные средства .NET.
Re[6]: Использование .NET компонентов при помощи COM
Hello, "Hottabych1" > > Вот это да! Сработало!!! Спасибо большое, уже мозги плавились ! > А Вы не могли бы объяснить, почему так важно применять именно BSTR?
BSTR это не обычная строка, а скажем так, "паскалевская". это значит, что по
смещению [-1] хранится длина этой строки. Если маршалинг не используется, то
обычно это себя никак не проявляет. Однако, если возникает необходимость
маршалинга, то маршаллер считает мусор из [-1] смещения и получится то, что
получится...
Posted via RSDN NNTP Server 2.0 beta
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: Использование .NET компонентов при помощи COM
Здравствуйте, recLusa, Вы писали:
L>Создать проект Class Library. L>В свойствах проекта выставить : L>[Make Assembly COM — Visible]; L>(при желании) [Register for COM interop]; L>(и, если необходим ключ) [Sign The Assembly]
L>В принципе, это избавляет от необходимости описания L>интерфейса в начале и т.д.
Плохая идея:
1. При каждой компиляции все GUIDы будут перегенерированы и на совместимости со старыми версиями можно ставить крест. Поэтому надо описывать интерфейс и прописывать ему атрибут Guid, и указывать Guid для классов.
2. Указание ComVisible в свойствах проекта сделает видимыми все public классы, а не только те которые нужно. Я видел такой индусский плагин, который загадил весь реестр полсотней ненужных классов, форм и интерфейсов вместо регистрации одного-единственного класса. Поэтому атрибут ComVisible лучше ставить только для тех классов, которые собираетесь показывать для COM interop.
Re[3]: Использование .NET компонентов при помощи COM
Статья оказалась очень полезной, спасибо.
Вот только интересно, почему автор не говорит о возможностях
Visual Studio по этой теме.
Вполне замечательно срабатывает такой вариант.
Создать проект Class Library.
В свойствах проекта выставить :
[Make Assembly COM — Visible];
(при желании) [Register for COM interop];
(и, если необходим ключ) [Sign The Assembly]
В принципе, это избавляет от необходимости описания
интерфейса в начале и т.д.
Просто пишется "обычная dll", с любым (относительно) кодом.
А при компиляции VS делает все сам.
В качестве пожелания, дополнить статью этим методом.
Думаю, для многих такой вариант окажется "проще".
Спасибо.
Re[4]: Использование .NET компонентов при помощи COM
Здравствуйте, kuj, Вы писали:
kuj>А regasm Some.dll?
пробовал
но сейчас всё исправилось
использовалась какая-то старая версия Some.tlb
Правило наименьшего удивления: Программа должна работать так, чтобы это вызывало наименьшее удивление у пользователя.
Построй свой мини-горд на http://rumactep.myminicity.com/
Re[7]: Использование .NET компонентов при помощи COM
От:
Аноним
Дата:
18.08.08 04:05
Оценка:
Аналогичная проблема не могу работать со строковыми переменныыми.
вот код библиотеки на C#
public interface IMifareLibrary
{
String G_Name { get; set;}
}
public class MifareLibrary : IMifareLibrary
{
private String PG_Name;
//конструктор класса
public MifareLibrary()
{
PG_Name = "";
PG_Passwd = "";
}
public String G_Name
{
get
{
return PG_Name;
}
set
{
PG_Name = value;
}
}
}
Код в клиенте
#include <windows.h>
#include <stdio.h>
#include <comdef.h>
#import"mifarelibrary.tlb" raw_interfaces_only
using namespace MifareLibrary;
void main()
{
if (FAILED(CoInitialize(NULL)))
return;
_bstr_t bstrCLSID;
CLSID clsidOrbit;
IMifareLibrary* pIOrbit;
HRESULT hr;
bstrCLSID = "MifareLibrary.MifareLibrary";
if (FAILED(CLSIDFromProgID (bstrCLSID,&clsidOrbit)))
return;
if (FAILED(CoCreateInstance(clsidOrbit,0,CLSCTX_ALL,__uuidof(IMifareLibrary),(void**)&pIOrbit)))
return;
BSTR strAbout;
pIOrbit->get_G_Name((unsigned short **)"Volkov");
pIOrbit->put_G_Name(strAbout);
printf("Printf Connect To Gate = %d\n",t);
pIOrbit->Release();
CoUninitialize();
}
Не понимаю почему она просит преобразование в (unsigned short **). Смотел по примерам никто с такой проблемой не сталкивался.
Собственно на функции присваивания программа и отваливается ( Уже голова кипит не понимаю в чем проблема.
Может кто занет почему у меня не проходит по этому условию. Вроде все правильно делаю.
//Создаём объект
//и сразу же получаем интересующий нас интерфейс ITestComponent
if (FAILED(CoCreateInstance(clsidOrbit,0,CLSCTX_ALL,__uuidof(ITestComponent),(void**)&pIOrbit)))
return;
Пути я прописывал, например, во так:
#import "C:\\3\\net\\My\\bin\\Release\\My.tlb" raw_interfaces_only Это нормально?
В командной строке я могу писать так: C:\5\sn.exe -k my.snk ?
Re[2]: Использование .NET компонентов при помощи COM
Здравствуйте, Rodion Online, Вы писали:
RO>Может кто занет почему у меня не проходит по этому условию. Вроде все правильно делаю.
RO> if (FAILED(CoCreateInstance(clsidOrbit,0,CLSCTX_ALL,__uuidof(ITestComponent),(void**)&pIOrbit))) RO> return;
у меня тоже так не работает — говорит, класс незарегистрирован
если положить Some.dll в тот каталог, где и клиент, то работает
PS пробовал делать и так gacutil /i Some.dll
всё равно не работает........
Правило наименьшего удивления: Программа должна работать так, чтобы это вызывало наименьшее удивление у пользователя.
Построй свой мини-горд на http://rumactep.myminicity.com/
Re[3]: Использование .NET компонентов при помощи COM
Здравствуйте, MACTEP, Вы писали:
MAC>если положить Some.dll в тот каталог, где и клиент, то работает MAC>PS пробовал делать и так gacutil /i Some.dll MAC>всё равно не работает........
PPS кстати, сборка видна в GacCash [\WINDOWS\assembly]
Правило наименьшего удивления: Программа должна работать так, чтобы это вызывало наименьшее удивление у пользователя.
Построй свой мини-горд на http://rumactep.myminicity.com/
Re[3]: Использование .NET компонентов при помощи COM
Здравствуйте, MACTEP, Вы писали:
MAC>если положить Some.dll в тот каталог, где и клиент, то работает MAC>PS пробовал делать и так gacutil /i Some.dll
А regasm Some.dll?
Здравствуйте!
Кто-нибудь пробовал добавить в интерфейс свойство с типом string? У меня почему-то тогда не получается из клиента записать строку. То есть она вроде как записывается, но при попытке чтения значения свойства возвращается пустая строка
Re[2]: Использование .NET компонентов при помощи COM
Hello, "Hottabych1" > Кто-нибудь пробовал добавить в интерфейс свойство с типом string? У меня > почему-то тогда не получается из клиента записать строку. То есть она > вроде как записывается, но при попытке чтения значения свойства > возвращается пустая строка
Обычно работает. Надо смотреть финальный код
Posted via RSDN NNTP Server 2.0 beta
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[3]: Использование .NET компонентов при помощи COM
Здравствуйте, TK, Вы писали:
TK>Hello, "Hottabych1" >> Кто-нибудь пробовал добавить в интерфейс свойство с типом string? У меня >> почему-то тогда не получается из клиента записать строку. То есть она >> вроде как записывается, но при попытке чтения значения свойства >> возвращается пустая строка
TK>Обычно работает. Надо смотреть финальный код
Вот код сборки (файл Some.cs). Собственно, взят практически полностью из статьи. Только изменил свойство About.
using System;
using System.Reflection;
using System.Text;
//Данный атрибут определяет файл, в котором находится
//пара личных криптографических ключей,
//однозначно идентифицирующих сборку
//[assembly:AssemblyKeyFile("../Orbit.snk")]
//[assembly:AssemblyVersion("1.0.0.0")]namespace TestComponentLib
{
//Этот интерфейс нужен для взаимодействия
//с COM public interface ITestComponent
{
int Mul(int First, int Second);
int Square { get; set; }
String About { get; set; }
}
/// <summary>
/// Summary description for Class1.
/// </summary>public class TestComponent : ITestComponent
{
private int m_iSquare;
private string m_strAbout;
public TestComponent()
{
m_iSquare = 0;
}
// Implementing interface ITestComponentpublic int Mul(int First, int Second)
{
return First * Second;
}
public int Square
{
get
{
return m_iSquare;
}
set
{
m_iSquare = value * value;
}
}
public string About
{
get
{
return"This component is written in C#." + m_strAbout;
}
set
{
m_strAbout = value;
}
}
}
}
А вот код клиента на MFC:
// TestMFCNet.cpp : Defines the entry point for the console application.
//#include"stdafx.h"#include"TestMFCNet.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#import"e:\Мои документы\Visual Studio Projects\TestComponent\bin\Debug\TestComponent.tlb" raw_interfaces_only
using namespace TestComponent;
// The one and only application object
CWinApp theApp;
using namespace std;
void DoWork()
{
//Инициализируем СOM как STA, хотя значения это, в общем-то, не имеет,
//так как наш компонент автоматически поддерживает обе потоковые модели.if (FAILED(CoInitialize(NULL)))
return;
_bstr_t bstrCLSID;
CLSID clsidOrbit;
ITestComponent* pIOrbit;
HRESULT hr;
//Это ProgID нашего компонента.
//Как видите, он складывается из области видимости и имени
//самого компонента, записанных через точку.
bstrCLSID = "TestComponentLib.TestComponent";
//Получаем CLSID (Class ID) через ProgIDif (FAILED(CLSIDFromProgID (bstrCLSID, &clsidOrbit)))
return;
//Создаём объект
//и сразу же получаем интересующий нас интерфейс ITestComponentif (FAILED(CoCreateInstance(clsidOrbit, 0, CLSCTX_ALL, __uuidof(ITestComponent), (void**)&pIOrbit)))
return;
//BSTR strAbout;
LPWSTR strAbout;
//Запрашиваем информацию о компоненте
pIOrbit->put_About(L" HI!!!!!");
pIOrbit->get_About(&strAbout);
CW2CT str(strAbout);
//Для вывода используем UNICODE-версию MessageBoxlong res = 0;
pIOrbit->put_Square(232);
pIOrbit->get_Square(&res);
AfxMessageBox(str);
CoUninitialize();
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// initialize MFC and print and error on failureif (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
DoWork();
}
return nRetCode;
}
Re[4]: Использование .NET компонентов при помощи COM
Здравствуйте, TK, Вы писали:
TK>Hello, "Hottabych1" >> >> Вот код сборки (файл Some.cs). Собственно, взят практически полностью из >> статьи. Только изменил свойство About.
TK>Не пробовал использовать нормальные BSTR? (для put_ особенно) TK>
TK>LPWSTR strAbout;
TK> //Запрашиваем информацию о компоненте
TK> pIOrbit->put_About(L" HI!!!!!");
TK> pIOrbit->get_About(&strAbout);
TK>
Вот это да! Сработало!!! Спасибо большое, уже мозги плавились ! А Вы не могли бы объяснить, почему так важно применять именно BSTR?
Не пойму, почему не работает. Вот код, который я пытаюсь отладить.
Изменения по отношению к оригиналу состоят только в форматировании.
Кроме того я перенес файл Orbit.snk в папку C# проекта,
а C#dll перед запуском переношу в ту же папку, где находится C++ Some.exe.
C++ программа прекращает работу на строке, отмеченной **.
Что сие и как с ним бороться?
Спасибо!
using System;
using System.Reflection;
// Определение файла личных криптографических ключей, идентифицирующих сборку
[assembly:AssemblyKeyFile("Orbit.snk")]
[assembly:AssemblyVersion("1.0.0.0")]
namespace TestComponentLib
{ public interface ITestComponent // Этот интерфейс нужен для взаимодействия с COM
{ int Mul(int First, int Second);
int Square { get; set; }
String About { get; }
}
public class TestComponent: ITestComponent // Данный класс реализует интерфейс ITestComponent
{ public TestComponent() { m_iSquare = 0; }
public int Mul( int First, int Second) { return First * Second; }
private int m_iSquare;
public int Square { get { return m_iSquare; } set { m_iSquare = value * value; } }
public String About { get { return "This component wrote on C#"; } }
}
}
Здравствуйте, Алексей Дубовцев, Вы писали: АД> ...вы сможете с легкостью использовать компоненты .NET в ваших приложениях при помощи COM.
Пробую dhtml пример, отваливается на Orbit = new ActiveXObject("TestComponentLib.TestComponent");
Тупо свалил в одну директорию .dll+.htm, чего не хватает? В реестре вижу Class как в статье, .еxe пример работает нормально.
IE 7.0, MS FW 2.0
Здравствуйте, gok, Вы писали:
gok>Здравствуйте, recLusa, Вы писали: L>>Создать проект Class Library. L>>В свойствах проекта выставить :
gok>пытаюсь повторить, не найду где в vc2005 ставятся флажки для сборки?
gok>Проект Class Lib, в assemblyInfo.cpp вижу/меняю [assembly:ComVisible(true)]; gok>Какие команды пользовать для остальных ключей? (Register, Sign, ...) gok>gok
День добрый.
Вот. Если еще не нашел:
Заходишь Меню Project -> MyClassLibrary Properties.
Далее вкладка Application. Кнопка Assembly Information.
Там внизу есть флажок Make Com Visible.
На вкладке Build тоже внизу галочка register for com interop.
На вкладке Signing галочка Sign thr assembly.
И далее дает возможность сделать новый key или выбрать имеемый.
Правда, обычно ключиком не подписываю (вообще обхожусь без этого).
И регистрирую regasm -ом, так как тестировать COM имеет смысл наверное
в контексте того Win32 Apz, для кот. он пишется.
Поэтому подкидываю готовую dll-ку туда, куда надо и регистрирую:
c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe MyClassLibrary.dll /codebase /tlb MyClassLibrary.tlb
Прекрасно работает и на Develop машине и у заказчиков.
Удачи!
Здравствуйте, recLusa, Вы писали:
L>[Использование .NET компонентов при помощи COM]
L>Статья оказалась очень полезной, спасибо. L>Вот только интересно, почему автор не говорит о возможностях L>Visual Studio по этой теме.
L>Вполне замечательно срабатывает такой вариант.
L>Создать проект Class Library. L>В свойствах проекта выставить :
Можно еще проще, при создании библиотеки класса указать что это библиотека типа COM class и VS сама сгенерит шаблон необходимый для создания com-библиотечки.
мне понадобилось переделать тип сборки с DLL на EXE, так как получил конфликт различных сторонних DLL (не комовских).
то есть мне нужен outproc server, чтобы весь .NET работал в отдельном процессе.
сразу всё резко перестало работать. получил сообщение что CLSCTX некорректен.
возможно ли создать на дот нете COM outproc server ?
если да, то как?
я просто поменял тип проекта "Class library" на "Windows Application" и прикрутил форму.
точно также запускаю
regasm my.exe /tlb
получаю нормальную tlb
но EXE не пашет
а DLL пашет как часы.
Что забыл?
from __python__ import paradigma
from __future__ import generators
from __waterfall__ import power
Re[2]: Использование .NET компонентов при помощи COM
неужели никто никогда не делал EXE outproc сервера на дот нете?
ну ведь надо же что-то прикрутить и всё заработать должно.
в инете полно примеров, как делать DLL — class library, но ничего нет про EXE.
у Троельсена в теме "Обращение клиента СОМ к сборке .NET" рассматривается тоже DLL
есть правда тема "Взаимодействие со службами СОМ+"
где говориться буквально следующее
ApplicationActivationAttribute Определяет, будет ли компонент, определенный в сборке,
запускаться в процессе создателя (библиотечное приложение)
или в системном процессе (серверное приложение)
и следующее
в среде выполнения .NET могут работать только модули DLL
и следующее
Как уже говорилось, приложения MTS и СОМ+ бывают двух
разновидностей: библиотечные (активируемые в процессе вызывающего клиента)
и серверные (для них создается новый объект dllhost.exe). По умолчанию создается
библиотечное приложение.
вот мне и нужен отдельный серверный тип, но мне не нужен COM+
как просто и сердито сконвертировать работающее приложение DLL написанное на шарпе,
которое выставляет один интерфейс с одной функцией через CCW,
чтобы стать EXE out-proc сервером, что надо прикрутить?
надо же как-то организовать цикл месаг, кто делал?
не надо никаких мультипоточностей, обычное STA приложение,
точнее COM out of process server, написанное на шарпе.
переделать на out-proc понадобилось, потому как есть конфликтующие DLL разных версий, которые нельзя выкосить.
from __python__ import paradigma
from __future__ import generators
from __waterfall__ import power
Re[4]: Использование .NET компонентов при помощи COM