Создание .NET-библиотеки для использования в WIN32-приложениях или как подключить библиотеку на C# к Delphi.
В жизни каждого программиста всегда происходит какая-то фигня, когда нужно выполнить поставленную задачу и заказчика не волнует как это будет сделано. Вот и случилось так, что нужно было написать dll-файл и подключить к проекту, написанному на Delphi. Но, т.к. я терпеть не могу паскаль и люблю C#, то было принято решение написать библиотеку на C# и каким-то образом подключить ее к проекту на делфях года этак 2005. В итоге задача была успешно решена. Каким образом…? Читайте дальше.
В Visual Studio создаем новый проект ClassLibrary, задаем ему вымышленное имя testwin32.

В исходном коде пишем класс:
...
using System.Runtime.InteropServices;
public interface IMyInterface
{
int Sum(int x, int y);
string AppendText(string text);
}
[ClassInterface(ClassInterfaceType.None)]
public class TestClass : IMyInterface
{
//просто суммируем два числа
public int Sum(int x, int y)
{
return x + y;
}
//к следующему тексту добавляем текущий год
public string AppendText(string text)
{
StringBuilder sb = new StringBuilder(text);
sb.Append(DateTime.Now.Year);
return sb.ToString();
}
}
Класс содержит два метода: первый возвращает сумму двух чисел; второй просто добавляет к строке какой-то текст.
Для того, чтобы методы были видны, требуется описать интерфейс и добавить в using System.Runtime.InteropServices. Класс наследуется от интерфейса IMyInterface и для класса описываем аргумент [ClassInterface(ClassInterfaceType.None)]. В самом интерфейсе вы описываете только те методы, которые будут видны «снаружи». Если в классе находятся другие методы, то в интерфейсе их описывать не обязательно (они будут работать внутри класса).
Следующим шагом будет подготовка проекта к компиляции. Для этого в меню Project выберите свойство проекта (Properties).

В открывшемся окне в Application нажмите на кнопку Assembly Information… В появившемся окне установите галочку напротив свойства Make assembly COM-visible — для того, чтобы ваша информации о библиотеке была общедоступна.

Далее на вкладке Build установите галочку напротив свойства Register for COM interop.

Теперь все готово к компиляции. Выполните компиляцию и перейдите в папку с созданным файлом.
Перед использованием файла в проекте Delphi, его нужно подготовить.
Утилитой regasm нужно создать tlb-файл. Сама утилита обычно находится в папке c:\Windows\Microsoft.NET\Framework\v2.0.50727\
regasm testwin32.dll /tlb:testwin32.tlb
dll-Библиотека рядом с exe-файлом программы.
Давайте подготовим небольшую программу на Delphi, которая будет использовать нашу библиотеку. Я использую Delphi 6. Создадим новый проект. В проект скопируем файл — testwin32.dll.
Если вы уже регистрировали библиотеку, то при компиляции в Visual Studio вместе с dll-файлом, сразу появляется и tlb-файл с таким же названием
В Delphi заходим в меню Project->Import Type Library. В появившимся окне выбираем testwin32 и нажимаем кнопку Create Unit. Если testwin32 в списке нет, то через кнопку Add находим tlb-файл.

Обратите внимание, если вы все правильно до этого сделали, то в списке классов, при добавлении библиотеки, вы увидите название своего класса
В коде по нажатию кнопок пишем следующий код:
...
uses
ComObj, testwin32_TLB;
{$R *.dfm}
procedure TForm1.btnSumClick(Sender: TObject);
var
intfRef: IMyInterface;
result: Integer;
begin
intfRef := CreateComObject(CLASS_TestClass) as IMyInterface;
result := intfRef.Sum(StrToInt(Edit1.Text), StrToInt(Edit2.Text));
lblSum.Caption := IntToStr(result);
end;
procedure TForm1.btnTextClick(Sender: TObject);
var
intfRef: IMyInterface;
begin
intfRef := CreateComObject(CLASS_TestClass) as IMyInterface;
lblText.Caption := intfRef.AppendText(Edit3.Text);
end;
В uses главного юнита допишите:
uses ComObj, testwin32_TLB;
testwin32_TLB — название юнита, который сгенерировался автоматически при добавлении библиотеки. Функция CreateComObject(CLASS_TestClass) as IMyInterface принимает название нашего класса, название которого строиться по схеме CLASS_ххххх.
Бывает так, что в файле mscorlib_TLB возникает ошибка типа Type ‘Byte’ is not yet completely defined. Исправляется она добавлением к каждому типу, строки «System.». Т.е. у вас должно получиться «System.Byte». Замените все ошибки и сохраните проект
Пример работы программы, которая использует библиотеку на C#.

UPDATE 1
Если вы ставите галочку напротив Register for COM interop и Make assembly COM-Visible, тогда Visual Studio регистрирует вашу библиотеку в системе автоматически. Для работы в другой системе вам необходимо убрать обе отметки и вручную зарегистрировать библиотеку. Для этого измените часть кода, представленный в примере:
[ClassInterface(ClassInterfaceType.None)] public class TestClass : IMyInterface ...
на
[ComVisible(true),ClassInterface(ClassInterfaceType.None)] public class TestClass : IMyInterface ...
К интерфейсу добавьте атрибут:
[ComVisible(true)] public interface IMyInterface ...
И выполните команду регистрации:
RegAsm.exe xxx.dll /codebase /tlb: xxx.tlb
Спасибо Сергею, за инфу.
Заключение
В этой статье мы рассмотрели как можно подключить написанную на C# библиотеку к приложению Win32. Как это все работает наглядно вы можете посмотреть в тестовом проекте, который прилагается к статье. СКАЧАТЬ ПРИМЕР.
Популярность: 38%
Если у вас возникли вопросы, вы можете оставить их в комментариях


Все работает, автору большое спасибо!
Теперь встал вопрос как сделать так же но в Builder C++.
Я думаю подключение должно быть по аналогии. Потому как это тоже борландовский продукт. Честно говоря, я не смотрел, но если нужна помощь, можно и покопаться.
Перерыл пол нета, только тут нашел толковый пример. спасибо!
Спасибо большое=)
Благодарю, Евгений! Сохраню в закладках, вдруг пригодится =)
Спасибо за статью! Нашел две ошибки:
1. «Класс содержит два метода: первый статический возвращает сумму двух чисел; » — там два метода не статические. К тому же статические методы не передаются через интерфейс.
2. «Давайте подготовит небольшую программу на Delphi» — подготовим, наверно
И как небольшое пожелание. Для полной ясности не мешало бы объяснить, почему при том, что мы ставим птичку «Register for COM interop», нам нужно еще использовать regasm.
А можно узнать, как использовать библиотеку в проекте C#? А то мучаюсь, не получается. Как прикрутить её знаю, а вот что в коде написать…
Отличный пример!!! Биг спс автору!
Вообще тема использования библиотек написанных на C#/C++ в проектах delphi — очень интересная тема, и очень часто где необходимо использовать такой подход в работе.
Возникла проблема переноса проекта на другой компьютер! Необходимо зарегистрировать dll, написанную на C#, на другом компьютере. при использовании «regasm» возникает ошибка «сбой при загрузки dll…. из за недопустимой сборки .Net». Соответственно при запуске приложения на другом компе вылетает ошибка «Класс не зарегистрирован». Может что нибудь посоветуете?
С такой проблемой не встречался, но:
посмотрите установлен ли Framework, на котором написана ваша библиотека.
Ыть… проблема была в версии VS. Переделал библиотеку на VS2008 и начало регистрироваться. Теперь проблема такая — при выполнении какой нибудь операции в программе, которая обращается в dll, возникает ошибка о неправильном типе данных. Эта ошибка возникает только на других компьютерах. На своем у меня все ОК.
Где то в гугле видел, что при регистрации необходимо использовать не только regasm.
И спасибо за ответ )
Если вы не против, то позвольте еще немного тут пописать )…
Заметил еще одну особенность. Если рассматривать ваш пример библиотеки и в свойствах проекта не ставить те две галочки о регистрации COM. Скомпилировали проект -> создался *.dll файл.
Далее регистрируем ручками: «C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe ClassLibrary2.dll /tlb:ClassLibrary2.tlb». Создается *.tlb файл. Пытаемся выполнить импорт в делфи (Project->Import Type Library). В списке видим нашу dll, но «Class Names:» пустое!
Вот в чем проблема блин (. Уже 2 дня мучаюсь… непойму как сделать чтобы нормально зарегать библиотеку на другом компьюторе???
Как выглядит эта ошибка на английском языке?
Попробуйте поиграть еще с этой утилитой RegSvcs.exe вашабиблиотека.dll
Ошибка генерировалась из за исключения в блоке try catch.
Проблема в том что имена классов не регистрируется при ручной регистрации.
Попробуй написать батник и регать с добавлением /codebase
[csharp]
RegAsm.exe xxx.dll /codebase /tlb: xxx.tlb
@pause
[/csharp]
не помогло (
Посмотри тогда пример такого кода:
пример кода
Вроде бы нашел решение….
в месте где указываем «[ClassInterface(ClassInterfaceType.None)]» необходимо указывать [ComVisible(true),ClassInterface(ClassInterfaceType.None)]. И после ручной регистрации видны имена классов.
Большое спс за ссылочку ). Позже потестю на рабочем проекте )
Если все заработает, отпишись пожалуйста что и как, а я дополню статью.
Мой результат такой:
если пишется библиотека для работы на других компьютерах, то в свойствах проекта не надо включать «Make assembly COM-visible» и «Register for COM interop». А вместо «[ClassInterface(ClassInterfaceType.None)]» необходимо писать «[ComVisible(true),ClassInterface(ClassInterfaceType.None)]«, также перед указать перед интерфейсом:
[ComVisible(true)]
public interface IMyInterface
{
…..
}
Перепробовал все сочетания опций — упорно не получается в VS2010 код в C# сделать COM visible.
Утилита dllexp не определяет функций для экспорта, хотя такой же код написанный в С++ с опцией
static __declspec(dllexport) показывает функции для экспорта с именами типа ?AkimaPolynom@Polynom@Interpolation@@SANNN@Z.
В чем еще может быть проблема?
В VS2010 я не пробовал, но там есть все нужные опции для компиляции. За утилиту dllexp я не знаю. К статье прилагается пример, попробуй его открыть в VS2010 и посмотри, что из этого получится.
Народ кто поможет откомпилировать http://twittervb.codeplex.com/
под COM visible а то у меня VS нема
Вопрос не в тему \Создание .NET-библиотеки для использования в WIN32-приложениях или как подключить библиотеку на C# к Delphi.\
Я пытаюсь тоже самое сделать с Google API .Net
a он гад ругается
Types registered successfully
Type library exporter warning processing ‘Google.GData.Client.Feed`1, Google.GDa
ta.Client’. Warning: Type library exporter encountered a generic type. Generic c
lasses may not be exposed to COM.
Type library exporter warning processing ‘Google.GData.Client.FeedRequest`1, Goo
gle.GData.Client’. Warning: Type library exporter encountered a generic type. Ge
neric classes may not be exposed to COM.
Type library exporter warning processing ‘Google.GData.Client.AtomCollectionBase
`1, Google.GData.Client’. Warning: Type library exporter encountered a generic t
ype. Generic classes may not be exposed to COM.
Type library exporter warning processing ‘Google.GData.Extensions.ExtensionColle
ction`1, Google.GData.Client’. Warning: Type library exporter encountered a gene
ric type. Generic classes may not be exposed to COM.
RegAsm : error RA0000 : Type library exporter encountered an error while process
ing ‘Google.GData.Calendar.CalendarEntry, Google.GData.Calendar’. Error: Type li
brary exporter encountered an error while processing ‘Google.GData.Client.GDataR
equestException, Google.GData.Client’. Error: Type library exporter cannot load
type ‘Google.GData.Client.GDataRequestException’ (error: System.TypeLoadExceptio
n: Inheritance security rules violated while overriding member: ‘Google.GData.Cl
ient.GDataRequestException.GetObjectData(System.Runtime.Serialization.Serializat
ionInfo, System.Runtime.Serialization.StreamingContext)’. Security accessibility
of the overriding method must match the security accessibility of the method be
ing overriden.).
Здрасте всем. Статья хорошая, но получить *.tlb файл вручную, сложновато.Ошибка такая же как у Сергея, но вот исходников нет и не предвидится (они закрытые).
Огромное спасибо! Нужно было решить аналогичную задачу. После недельных поисков наткнулись на эту статью. Всё работает, как часы.
а как это всё отлаживать?
Отлаживать нужно в среде .NET на этапе разработки библиотеки. После подключения уже врядли можно что-то отладить из Делфи. Поправьте, если не прав.
а, у меня экспресс был. там хорошо порезано в плане отладки. пример работает. а вот моя библиотека молча умирает на создании объекта, если вызывается из проги написанной на дельфи. под дельфёвыми дебагом выкидывается АВ. под дебагом в студии просто завершается трассировка. при вызове библиотеки из шарпа всё хорошо.
копаю.
Сложно сказать почему так может происходить. Вам должно быть виднее, если код ваш. Если разберетесь в ошибки, отпишитесь.
после каких-то манипуляций дебаг в шарпе стал выдавать float-point division by zero в родительском процессе. на http://interop.managed-vcl.com нашёл вот такое:
const
MCW_EM: Word = $133F;
function Get8087CW(): Word;
asm
PUSH 0
FNSTCW [ESP].Word
POP EAX
end;
procedure TForm1.Button1Click(Sender: TObject);
var
FPUCW: Word;
begin
FPUCW := Get8087CW();
try
Set8087CW(MCW_EM);
if OpenDialog1.Execute then begin
if tc=nil then tc:=TTestClass.Create(nil);
tc.FileName(OpenDialog1.FileName);
end;
finally
Set8087CW(FPUCW);
end;
end;
заработало.