DCOM : Serveur in-proc (Dll) activé en local ou à distance |
Créez un projet nommé Server0301 avec Visual C++ 6.0 et l'assistant de projet ATL COM AppWizard.
Le server est de type DLL et le code du proxy/stub est séparé.
Ajoutez un nouvel objet ATL de type simple objet nommé Info.
Ajoutez la méthode GetComputerName à l'interface IInfo.
La méthode GetComputerName fait appel à la fonction ::GetComputerName du Win32 SDK et retourne le résultat dans un VARIANT. Le VARIANT étant le type générique du Visual Basic mais surtout le seul type reconnu par les langages de script.
STDMETHODIMP CInfo::GetComputerName(VARIANT *vName) { // TODO: Add your implementation code here DWORD dw = 255; char szComputerName[255]; ::GetComputerName(szComputerName, &dw); Sleep(3000); CComVariant v(szComputerName); v.Detach(vName); return S_OK; }Pour être en mesure d'invoquer le composant de manière locale ou distante, modifiez le fichier RGS et ajoutez les lignes suivantes. AppId va permettre de visualiser le server dans l'outil de configuration DCOMCNFG afin de préciser le nom du server distant sur lequel va s'exécuter le composant.
HKCR { GetComp.GCInfo.1 = s 'GCInfo Class' { CLSID = s '{C4F1B2E4-DD84-11D4-8784-0008C7EA647B}' } GetComp.GCInfo = s 'GCInfo Class' { CLSID = s '{C4F1B2E4-DD84-11D4-8784-0008C7EA647B}' CurVer = s 'GetComp.GCInfo.1' } NoRemove CLSID { ForceRemove {C4F1B2E4-DD84-11D4-8784-0008C7EA647B} = s 'GCInfo Class' { val AppID = s '{AECA5120-E18E-11d4-8784-0008C7EA647B}' ProgID = s 'GetComp.GCInfo.1' VersionIndependentProgID = s 'GetComp.GCInfo' ForceRemove 'Programmable' InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' } 'TypeLib' = s '{C4F1B2D7-DD84-11D4-8784-0008C7EA647B}' } } NoRemove AppID { {AECA5120-E18E-11d4-8784-0008C7EA647B} = s 'GetComp.GCInfo' { } 'GetComp.DLL' { val AppID = s '{AECA5120-E18E-11d4-8784-0008C7EA647B}' } } }
// Client0301.cpp : Defines the entry point for the console application. // #define STRICT #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0400 #endif #define _ATL_APARTMENT_THREADED #include#define DBINITCONSTANTS #define INITGUID #include #include #include #include #include "..\\Server0301\\Server0301.h" #include "..\\Server0301\\Server0301_i.c" int main(int argc, char* argv[]) { USES_CONVERSION; if( argc != 2 ) { printf("Client0301 [option]\n"); printf("-I : inproc\n"); printf("-R : remote\n"); return 0; } char * pArg = argv[1]; char cOption = ' '; if( !strcmpi(pArg, "-I") ) { cOption = 'i'; } if( !strcmpi(pArg, "-R") ) { cOption = 'r'; } CoInitialize(NULL); IInfo * ptr; HRESULT hr; if( cOption == 'i' ) hr = CoCreateInstance(CLSID_Info, NULL, CLSCTX_INPROC_SERVER, IID_IInfo, (void **) &ptr); else if( cOption == 'r' ) hr = CoCreateInstance(CLSID_Info, NULL, CLSCTX_REMOTE_SERVER, IID_IInfo, (void **) &ptr); if(FAILED(hr)) { printf("Failed to get IInfo interface. Hr=0x%08x, GetLastError=%ld\n", hr, GetLastError()); return 0; } CComVariant vOut; ptr->GetComputerName(&vOut); LPSTR lpszOut = W2A(vOut.bstrVal); printf("Computer Name = %s\n", lpszOut); ptr->Release(); ptr = NULL; return 0; }
Choisissez l'entrée Server0301.Info, appuyez sur le bouton Propriétés puis choisissez l'onglet Emplacement. Sélectionnnez la case à cocher et précisez le nom du serveur distant:
Sur le serveur distant, enregistrez les dll dans la base de registres:
Placez vous sur la machine cliente.
Lancez le test avec l'option -R. Le client active le composant sur la machine distante. Le protocol DCOM rentre en scène.
Remarque: Sur la machine locale, il est possible de voir
le composant évoluer dans le surrogate dllhost.exe ; pour cela il faut ajouter
DllSurrogate dans la base de registre du client sous HKCR\AppId\xxx et invoquer
CoCreateInstance avec CLS_LOCAL_SERVER comme option de contexte d'exécution
dans l'application cliente. Modifiez le code client:
// Client0301.cpp : Defines the entry point for the console application. // #define STRICT #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0400 #endif #define _ATL_APARTMENT_THREADED #includeLe composant fait une attente de 3 secondes au sein de la méthode GetComputerName, ce qui laisse le temps d'observer que le système lance le surrogate. On le constante dans la listes des processus du Gestionnaires de tâches de Windows NT. Attention, le fait de préciser sous HKCR\AppId\xxx les valeurs RemoteServerName et DllSurrogate fait que l'outil DCOMCNFG ne propose plus l'onglet Emplacement ou est précisé le nom de la machine distante. Pour résoudre ce problème, il est possible d'utiliser en lieu et place de DCOMCNFG, l'outil OleView qui est fourni par Visual C++ 6.0. Sélectionnez le mode Expert et déroulez tous les objets. La sélection ne se fait pas sur le AppID comme avec DCOMCNFG mais sur le nom de l'interface. Choisissez Info Class:#define DBINITCONSTANTS #define INITGUID #include #include #include #include #include "..\\Server0301\\Server0301.h" #include "..\\Server0301\\Server0301_i.c" int main(int argc, char* argv[]) { USES_CONVERSION; if( argc != 2 ) { printf("Client0301 [option]\n"); printf("-I : inproc\n"); printf("-L : local\n"); printf("-R : remote\n"); return 0; } char * pArg = argv[1]; char cOption = ' '; if( !strcmpi(pArg, "-I") ) { cOption = 'i'; } if( !strcmpi(pArg, "-L") ) { cOption = 'l'; } if( !strcmpi(pArg, "-R") ) { cOption = 'r'; } CoInitialize(NULL); IInfo * ptr; HRESULT hr; if( cOption == 'i' ) hr = CoCreateInstance(CLSID_Info, NULL, CLSCTX_INPROC_SERVER, IID_IInfo, (void **) &ptr); else if( cOption == 'l' ) hr = CoCreateInstance(CLSID_Info, NULL, CLSCTX_LOCAL_SERVER, IID_IInfo, (void **) &ptr); else if( cOption == 'r' ) hr = CoCreateInstance(CLSID_Info, NULL, CLSCTX_REMOTE_SERVER, IID_IInfo, (void **) &ptr); if(FAILED(hr)) { printf("Failed to get IInfo interface. Hr=0x%08x, GetLastError=%ld\n", hr, GetLastError()); return 0; } CComVariant vOut; ptr->GetComputerName(&vOut); LPSTR lpszOut = W2A(vOut.bstrVal); printf("Computer Name = %s\n", lpszOut); ptr->Release(); ptr = NULL; return 0; }
Sélectionnez l'onglet Implementation:
Sélectionnez l'onglet Activation :
On peut ainsi préciser l'utilisation du surrogate et aussi du nom de la machine distante.
On a donc 3 modes d'utilisation de notre composant:
- le mode en dll
- le mode local avec dllhost.exe
- le mode distant avec dllhost.exe
Il est aussi possible d'invoquer le composant dans un script VBS:
'client0301.vbs Main Sub Main Dim Obj Dim strOut Set Obj = CreateObject("Server0301.Info") Obj.GetComputerName strOut MsgBox strOut Set Obj = Nothing End SubLancez la commande: wscript client0301.vbs
© 2001 Christophe Pichaud. All rights reserved.