Oups.
Là, ça sort de mon domaine de compétence.
Version imprimable
Oups.
Là, ça sort de mon domaine de compétence.
:cry: :cry: :cry: :cry: :cry: Personne ne peut m'aider, je trouve toujours rien :cry: :cry: :cry: Même pas un tutorial :cry: :cry: :cry:
Eh bien,
Moi aussi j'ai essayé de faire un exemple chez moi mais en vain. :|
1. Je sais passer un interger du client vers mon local server
2. Je sais récupérer un interger à partir de mon local server
3. Je sais passer une BSTR du client vers mon local server
4. Mais je ne sais pas récupérer un simple BSTR à partir de mon local server. :?
Chose étrange, l'exemple
http://www.codeproject.com/com/LocalCOMServerClient.asp n'illustre même pas ce 4 ième point.
Un composant COM en local server est d'abord un exe, et donc il gènere son propre espace de processus, et le client qui lui est un autre exe auront du mal à échanger facilement des infos en termes de désignation de bloc mémoire pour les pointeurs.
Ecoute pour gagner du temps fait en sorte que ton objet COM appartiennent à l'espace de processus de tes client ie un Server in process (dll).
L'avantage est que les appels coûte moins chère entre le client et le composant mais le désavantage si le composant crash, le client crash aussi.
Voilà.
Mais justement c pour ça que j'ai choisi que le serveur soit un exécutable. J'en ai absoluement besoin.
Je pense que c un problème relatif à l'idl.
Pour ton quatrième point voilà ce qu'il faut faire:
Citation:
Dans le fichier IDL
[ object,
uuid(349FDD79-DD63-46ee-A989-45D9B3C3AD53),
oleautomation,
helpstring("ITest Interface")
]
interface ITest : IUnknown
{
HRESULT Method1([in] BSTR Msg1, [out] BSTR *Msg1_);
};
Citation:
Exemple d'implémentation
STDMETHODIMP Test::Method1(BSTR Msg1, BSTR *Msg1_) {
char str[255] = "Salut Gabrielly";
CComBSTR temp(str);
*Msg1_= temp.Detach();}
Citation:
Appel au niveau du client:
//Some code...
CComBSTR msgout;
_bstr_t msgin(" ");
pITest->Method1(msgin,&msgout);
BSTR tmp1;
tmp1 = msgout.Detach();
char TT[255];
sprintf(TT, "%ws", tmp1);
//Some code...
Non, non, il y a confusion,
Lorsque le composant est un "Inproc server" ie empaqueté dans une dll, il n' ya aucun problème dans la passation des variables avec son client quel que soit sa nature.
Mais si le composant est un "Out of Process" ou un local server ie empaqueté das un exe alors mon 4 ième point ne fonctionne pas
Ma conclusion est que tu développes une DLL COM et non un EXE COM pour ton serveur.
Donc c'est le contraire. :P
Si ton composant COM est une DLL, alors il sera mappé dans l'espace d'adressage de tes processus clients. Et donc tu peux balancer tes pointeurs de part et d'autres entre le serveur et le client.
Mais si ton composant COM est un EXE alors il gère son propre espace d'adresses et tes clients qui sont aussi des exe gèrent également leurs propres espaces. C'est pourquoi COM fait du Marshalling pour déplacer des blocs de mémoire entre les processus rendant de ce fait les valeurs de pointeurs changeant ou invalides.
Fait une DLL ATL COM.
Génère un projet ATL, et laisse les assitants générés automatiquement le fichier IDL et les scripts d'inscription des composants (*.reg)
Voilà
Alors je comprends plus rien.
Il faut que mon serveur soit un exécutable. J'en ai absolument besoin.
I'm stuck with it.
Je dois trouver comment résoudre mon problème (passer une liste d'élements de type char) sachant que mon serveur est un exécutable.
Pourquoi ne pas sérialiser tes BSTR en une seule, puisqu'elles peuvent contenir des données binaires ?
8O Tu peux expliquer davantage stp?
Une BSTR est codée avec sa taille en premier, ce qui fait qu'elle peut contenir des zéros.
Résultat, en utilisant les fonctions agissant sur les BSTR, on peut les regrouper en une seule.
(Car si j'ai bien compris, passer une seule BSTR n'est pas un problème).
En supposant que toutes tes BSTR soient des chaînes normales, c'est-à-dire terminées par des caractères nuls:
Àprès ce code, ta BSTR contient une suite de strings unicode, séparées par des \0!Code:
1
2
3
4
5
6
7
8 TailleTotale = 0 POUR chaque BSTR str de la liste TailleTotale += SysStringLen(str)+1 StringFinale = SysAllocStringLen(NULL, TailleTotale) POUR chaque BSTR str de la liste Ajouter str à StringFinale (après le \0), \0 inclus
Ecoute mambo, Médinoc te propose de faire la concaténation de tous les éléments de la liste en une seule chaine de caractères.
Moi je te conseillerais d'utiliser le CComBSTR qui encapsule l'API brut d'utilisation des BSTR.
Mais Mambo, pour moi si tu veux que ton serveur réussise alors ouvre un nouveau projet ATL et crée une DLL et ajoute une classe de type COM.Code:
1
2
3
4
5
6
7 CComBSTR bstr("Chaine1"); bstr += "\nChaine2"; bstr += "\nChaine3"; CComBSTR bstrList(bstr); bstrList; // Au final tu as "Chaine1\nChaine2\nChaine3"
Je suis en train de voir d'autres exemples de serveurs en utilisant ATL (tout en gardant le fait qu'il soit un exécutable) mais je trouve pas la solution pour passer un double pointeur.
Merci à vous deux.
Mambo,
Voici un formidable code pour ton exemple,
Dans ce petit programme, le code client construit un objet collection de BSTR, ensuite il passe l'adresse de l'objet tout entier au serveur.
Le serveur COM remplit la liste des BSTR et retourne au code client.
Ce dernier affiche le résultat à l'écran.
Le code est lisible est très compréhensif, tu ne verra nul part ou j'emploi l'API brut pour traiter les BSTR, et encore moins pour traiter le tableau, les classes elles mêmes s'en chargent.
Nature des projets: le client est un EXE, le serveur est une DLL ATL COM
Voici la méthode du serveur du composant COM CMamboSvr
Voici le code du clientCode:
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 // MamboSvr.cpp : Implementation of CMamboSvr #include "stdafx.h" #include "MamboSvr.h" #include <atlstr.h> // CString #include <atlcoll.h> // CAtlArray<> #include "CastingVariant.h" // un utilitaire pour la convertion d'un objet en VARIANT // CMamboSvr STDMETHODIMP CMamboSvr::GetMySmartList(VARIANT* pvarMySmartList) { // je convertit du VARIANT vers mon objet collection de BSTR CAtlArray<CComBSTR>* pMyClientSmartList = NULL; pMyClientSmartList = MCN::CCastingVariant< CAtlArray<CComBSTR> >::CastFromVariant(*pvarMySmartList); if( pMyClientSmartList == NULL) return E_POINTER; // j'ajoute simplement dans l'objet liste fournit par le code client pMyClientSmartList->Add("Banane"); pMyClientSmartList->Add("Framboise"); pMyClientSmartList->Add("Orange"); CComBSTR bstr = L"Mandarine"; CString str = "Poire"; LPSTR lpsz = "Pomme"; LPWSTR lpwsz = L"Mangue"; pMyClientSmartList->Add(bstr); pMyClientSmartList->Add(CComBSTR(str)); pMyClientSmartList->Add(lpsz); pMyClientSmartList->Add(lpwsz); ATLASSERT(pMyClientSmartList->GetCount() == 7); // je me rassure return S_OK; }
Pour le fichier "CastingVariant.h", voiciCode:
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 // Client.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> // pour l'affichage à l'écran #include <atlcomcli.h> // pour CComPtr<> #include <atlcoll.h> // pour CAtlArray<> #include "..\Mambo\Mambo.h" // Pour l'interface IMamboSvr du composant COM CMamboSvr #include "CastingVariant.h" // un utilitaire pour la convertion d'un objet en VARIANT #include "ComInitializer.h" // un utilitaire pour initialiser COM MCN::CComInitializer COM; // Initialise COM int _tmain(int argc, _TCHAR* argv[]) { CComPtr<IMamboSvr> spMamboSvr; HRESULT hr = spMamboSvr.CoCreateInstance(L"Mambo.MamboSvr.1"); if(hr == S_OK) { CAtlArray<CComBSTR> MyClientSmartList; // mon objet collection de BSTR // je convertit mon SmartList en VARIANT pour mon objet COM VARIANT varMySmartList = MCN::CCastingVariant< CAtlArray<CComBSTR> >::CastToVariant(&MyClientSmartList); spMamboSvr->GetMySmartList(&varMySmartList); // remplissage par le composant Mambo ATLASSERT(MyClientSmartList.GetCount() != 0); // je me rassure que c'est effectivement remplis for(ULONG i = 0; i < MyClientSmartList.GetCount(); i++) { CComBSTR bstrText = MyClientSmartList.GetAt(i); CStringA str(bstrText); // je convertit en ANSI std::cout << str << std::endl; // j'affiche la liste de mes fruits du serveur Mambo } } system("pause"); // pour mettre en pause et visualiser les fruits du serveur return 0; }
Pour le fichier "ComInitializer.h", voiciCode:
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 #pragma once namespace MCN { template<typename T> class CCastingVariant { public: static T* CastFromVariant(VARIANT var) { if(var.vt != VT_BYREF || var.byref == NULL) return NULL; return (T*) var.byref; } static VARIANT CastToVariant(T* pT) { if(pT == NULL) return CComVariant(); VARIANT var; var.byref = (void*) pT; var.vt = VT_BYREF; return var; } }; } // namespace MCN
Le code marche impécablement bienCode:
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 namespace MCN { class CComInitializer { private: HRESULT m_hr; public: #if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM) CComInitializer(DWORD dwCoInit = COINIT_APARTMENTTHREADED) : m_hr(E_UNEXPECTED) { m_hr = CoInitializeEx(NULL, dwCoInit); } #else CComInitializer() : m_hr(E_UNEXPECTED) { m_hr = CoInitialize(NULL); } #endif HRESULT Result() { return m_hr; } ~CComInitializer() { if (SUCCEEDED(m_hr)) CoUninitialize(); } }; } // namespace MCN
:D
le serveur est une DLL? Est ce que je peux accèder à ce genre de serveurs à distance?
Oui bien sûre pourquoi pas.
et pq c In-proc alors?
Oui, tu as raison.
Voit un peu l'api "CoCreateInstanceEx" et surtout dcom config ou service de composants.
Je crois qu'il faut faire une petite recherche...
Oui, j'arrête pas les recherches :roll:
En gardant l'idée du out-proc serveur, est ce que l'utilisation de SAFEARRAY ne résouderait pas le problème?
Tiens j'ai découvert un bon article sur DCOM
Citation:
Running in-process components remotely: Surrogate
In order to run in-process components remotely, a surrogate process on the remote machine is required. In addition to enabling remote execution, surrogate processes offer the following benefits:
Faults in the in-process server are isolated to the surrogate process.
One surrogate process can service multiple clients simultaneously.
Clients can protect themselves from untrusted server code, while accessing the services the server provides.
Running an in-process server in a surrogate gives the DLL the surrogate's security.
Windows NT 4.0 Service Pack 2.0 and DCOM for Windows 95 introduced a default surrogate process, as well as a protocol for writing custom surrogates. The default implementation of the surrogate process is a mixed-threading, model-style, pseudo-COM server. When multiple DLL servers are loaded into a single surrogate process, this process ensures that each DLL server is instantiated using the threading model specified in the registry for that server. If a DLL server supports both threading models, then COM will choose multithreading. This surrogate process is written so that COM handles both the unloading of DLL servers and the termination of the surrogate process.
An in-process server will be loaded into a surrogate process under the following conditions:
There must be an AppID value specified under the CLSID key in the registry, and a corresponding AppID key.
In an activation call, the CLSCTX_LOCAL_SERVER bit is set, and the CLSID key does not specify LocalServer32, LocalServer, or LocalService.
The CLSID key contains the InProcServer32 subkey.
The DLL specified in the InProcServer32 key exists.
The DllSurrogate value exists under the AppID key.
If there is a LocalServer or LocalServer32 or LocalService, indicating the existence of an EXE, the EXE server or service will always be launched in preference to loading a DLL server into a surrogate process.
The DllSurrogate named-value must be specified for surrogate activation to occur. To launch an instance of the system-supplied surrogate, set the value of DllSurrogate either to an empty string or to NULL. To specify the launch of a custom surrogate, set the value to the path of the surrogate.
For remote surrogate activation, specify RemoteServerName but not DllSurrogate on the client, and specify DllSurrogate on the server.
It is best to configure a DLL server that is designed to run alone in its own surrogate process and to service multiple clients across a network with a RunAs value specified under the AppID registry key. Whether the RunAs specifies "Interactive User" or a specific user identity depends upon the user interface (UI), security, and other server requirements. Specifying a RunAs value ensures that only one instance of the server is loaded to service all of the clients, regardless of the identity of the client. On the other hand, do not configure the server with RunAs If the intention is to have one instance of the DLL server running in surrogate to service each remote client identity.
Multiple servers will share a surrogate if they are launched under matching security identities and share the same AppID value. If two servers are launched under different security identities, they must be in different surrogates, regardless of whether their AppIDs match.
Impossible ; d'abord comme le dit Medinoc on n'utilise que des BSTR et segundo c'est pas possible d'interfacer des listes en tant que paramêtre.Citation:
Envoyé par mambo
Pour la bonne et unique raison que COM doit s'interfacer avec des programmes VB , Delphi qui ne connaissent pas la STL par exemple ou CStringList, CArray.
Donc tu ne peux que récupérer ou affecter ( get/set) un BSTR.
C'est l'appli cliente à gérer les listes de chaines de caractêres
Citation:
Envoyé par Médinoc
c'est déconseillé les risques de plantages et instabilité sont élevés