Utilisation d'une DLL COM à partir de C # sans bibliothèque de types
J'ai besoin d'utiliser un composant COM (dll) développé en Delphi, il y a des siècles. Le problème, c'est que la dll ne contient pas de bibliothèque de type... et de tous les interop fonctionnalité (par exemple. TlbImp).NET semblent se fonder sur les Tlb. Le composant a été utilisé dans Delphi programmes ici pendant de nombreuses années sans problèmes, car "Il n'est pas beaucoup d'un problème à l'aide d'objets COM à partir de Delphi, car nous savons que les interfaces" (citation développeur Delphi).
Est-il une manière que je peux utiliser cette DLL à partir de c# sans TLB? J'ai essayé d'utiliser la DLL en tant que non géré, mais la seule méthode qu'il exportations sont DllUnregisterServer
DllRegisterServer
DllCanUnloadNow
et DllGetClassObject
. Je sais les noms des classes et des fonctions que je vais utiliser, si cela peut être d'une aide quelconque.
Mise à JOUR:
J'ai essayé de mise en œuvre de Jeff suggestion, mais j'obtiens cette erreur:
"Impossible de convertir COM objet de type" ComTest.ResSrvDll' à l'interface de type " ComTest.IResSrvDll'. Cette opération a échoué car l'appel de QueryInterface sur le composant COM pour l'interface avec IID '{75400500-939F-11D4-9E44-0050040CE72C} a échoué en raison de l'erreur suivante: cette interface n'est Pas pris en charge (Exception de HRESULT: 0x80004002 (E_NOINTERFACE))."
C'est ce que j'ai fait:
J'ai eu cette définition de l'interface de l'un de Delphes-les gars:
unit ResSrvDllIf;
interface
type
IResSrvDll = interface
['{75400500-939F-11D4-9E44-0050040CE72C}']
procedure clearAll;
function ResObjOpen(const aClientID: WideString; const aClientSubID: WideString;
const aResFileName: WideString; aResShared: Integer): Integer; {safecall;}
...
end;
implementation
end.
À partir de ce que j'ai fait cette interface
using System.Runtime.InteropServices;
namespace ComTest
{
[ComImport]
[Guid("75400500-939F-11D4-9E44-0050040CE72C")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IResSrvDll
{
int ResObjOpen(string aClientID, string aClientSubID, string aResFileName, int aResShared);
}
}
Et ce coclasse (obtenu le guid de delphes-les gars)
using System.Runtime.InteropServices;
namespace ComTest
{
[ComImport]
[Guid("75400503-939F-11D4-9E44-0050040CE72C")]
public class ResSrvDll
{
}
}
Mise à JOUR
La solution de Jeff est la façon de le faire. Il est intéressant de remarquer, cependant, que la définition de l'interface doit correspondre à la COM-composants exactement! c'est à dire. même ordre, les mêmes noms, etc.
source d'informationauteur toxvaerd
Vous devez vous connecter pour publier un commentaire.
Vous avez juste besoin de la CLS_ID et id d'interface. J'ai écrit à ce sujet sur mon blog:
"À l'aide d'Obscures Windows Api COM .NET"
Écrire un wrapper en VB.Net. VB.Net prend en charge la véritable liaison tardive (pas de désordre de la réflexion). Tous vous avez besoin est l'identificateur de programme. Vous devriez également mettre en œuvre IDisposable explicitement gérer la composante du cycle de vie.
Il est assez fréquent que vous rencontrerez une implémentation de l'interface qui n'est pas soutenue par une bibliothèque de type (Delphi ou autre). Les extensions de Shell en sont un exemple.
Vous avez besoin de faire un appel API de Windows pour créer l'instance par le biais de la bonne COM appels de fonction. L'API va prendre soin de la gestion de la DLL via les fonctions exportées vous avez mentionné plus tôt.
Vous devrez recréer l'interface de définition dans le code C#, mais après cela, il vous suffit de créer l'objet, jette à l'interface, et il n'est pas différent de toute autre chose. Le seul inconvénient réel est ici, en fonction de votre utilisation, vous pouvez avoir des problèmes de thread pour traiter afin de vérifier le "modèle de thread" qui a été utilisé pour la DLL et de considérer votre utilisation en fonction de cela.
Voici un lien vers un tutoriel sur la consommation des interfaces qui ne sont pas TLB base.
Tutoriel
Oui et non.
Tous les C# (et de tout langage CLR) besoins afin de communiquer avec un objet COM est une interface compatible signature. Typiquement en spécifiant les méthodes, les GUID et le style d'un appartement de l'interface. Si vous pouvez ajouter à cette définition dans votre base de code puis le TLB n'est pas nécessaire.
Il y a une petite mise en garde qui vient avec cette déclaration. Je crois que vous allez avoir des ennuis si vous essayez d'utiliser un objet COM à travers appartement limites et qui n'ont pas adapté TLB enregistré. Je ne peux pas 100% rappeler sur ce point.
Vous pouvez également faire la liaison tardive puis d'appeler les méthodes de la réflexion (
myObject.InvokeMember("NameOfTheMethod", options, params, etc.)
).Un emballage doit, cependant, offrent de meilleures performances et la plus rapide de l'ordonnancement.
Je soupçonne que le
dynamic
mot-clé (C# 4.0) permet d'accomplir cela. Si elle le fait, elle va donner des résultats qui sont largement équivalentes à l'invocation de méthodes, c'est à dire comment Groo suggère.Si vous avez réussi à créer une instance de l'objet, vous êtes sur le premier obstacle majeur!
Maintenant, essayez ceci:
La raison pour laquelle je pense que vous pouvez avoir besoin pour ce faire est si Delphi COM objet n'est pas un "double" de l'objet. Il ne peut soutenir la liaison tardive, c'est à dire le genre d'invocation que vous voyez ci-dessus.
(En C# 4.0, ils font de ce plus facile avec le
dynamic
mot-clé.)EDIT: Viens de remarquer quelque chose de très suspect. L'IID de l'interface et le CLSID de l'objet lui-même semblent être les mêmes. Ce n'est pas juste.
Étant donné que vous avez réussi à créer l'objet, il semblerait que ce soit le CLSID de l'objet. Il n'est donc pas le droit IID. Vous avez besoin de revenir à votre Delphi, les gens et leur demander de vous dire ce que l'IID de l'interface
IResSrvDll
est.Modifier à nouveau: Vous pouvez essayer de changer le membre enum vous spécifiez à partir de
ComInterfaceType
. Il devrait y avoir pourIDispatch
et "double" - bien que votre objet ne prend pas en chargeIDispatch
ni de ceux qui devraient être le bon choix. LeIUnknown
paramètre (qui apparaît dans votre exemple de code) - ce qui suggère que la IID est faux.