Newsgroup: it.comp.programmare.win32
Titolo: << DCOM >>

Ciao a tutto il NG,
chiedo scusa per la lunghezza di questo messaggio ma vorrei cercare di
risultare il più chiaro possibile.
Sono alle prime armi per quanto riguarda (D)COM perciò mi scuso sin da
ora per l'eventuale uso improprio della terminologia.
Ho la necessità di sviluppare un'applicazione distribuita con n client
utilizzando DCOM (VC++ 6.0).
Pensavo di strutturare la soluzione come segue:
- n client COM
- un componente in-process single apartment thread (STA) che funzioni
da class factory e che si trovi sul server
- i componenti server COM veri e propri anch'essi sul server
Il funzionamento desiderato è il seguente:
alla richiesta di un client COM di utilizzare un componente server,
viene invocato il componente class factory che crea il componente
server richiesto restituendo al client un puntatore all'interfaccia.
Ho però una serie di dubbi che non riesco a chiarire:
- il componente class factory in-process e STA, riesce a delegare il
problema della sincronizzazione delle eventuali richieste simultanee
dei client alla coda dei messaggi dell'apartment anche se viene
caricato in un dllsurrogate (p.e. DLLHOST.EXE)?
- i componenti server COM creati con la class factory devono poter
corrispondere uno a uno con i client COM dopo la creazione. A tal
proposito è meglio crearli come in-process o out-of-proc?
- strutturando la soluzione in modo più semplice, costruendo un unico
componente server out-of-proc, devo occuparmi della sincronizzazione
delle richieste dei client?
- con la soluzione descritta al punto precedente riesco ad ottenere il
multitasking (per ogni richiesta di un client, un'istanza del
componente server)?
Ringrazio sin da ora tutti coloro che dedicheranno un pò del loro tempo
ad aiutarmi.
Roby
Sent via Deja.com 
http://www.deja.com/
Before you buy.

 componente server)?
Se c'e` un unico componente factory dovrebbe comunque
poter costruire un diverso componente server per ogni
richiesta di un client.
Alex


           --------
Con la nuova struttura descritta (senza customizzare la class factory e
con il solo utilizzo di un unico componente out-of-proc) è possibile
ottenere un comportamento multitasking del componente server per cui
ad ogni richiesta di un client, venga creata un'istanza diversa dalle
precedenti (è corretto parlare di un nuovo processo???) del componente
out-of-proc server?
           --------
Grazie Alex per il post di risposta; comincio finalmente a
riorganizzare le idee...
Ciao


 wrote in message
news:89iums$ehq$1...@nnrp1.deja.com...
(...continua dal post precedente)


 out-of-proc server?
Se il componente e` UNICO, per definizione ve n'e` una sola
istanza; non capisco quindi ancora cosa intendi.
Un singolo SERVER (una singola .EXE) puo` creare molteplici
istanze (molteplici componenti) in diversi thread entro lo stesso
processo-del-server, che e` probabilmente la soluzione migliore.
Alex

 processo-del-server, che e` probabilmente la soluzione migliore.
Alla luce dell'architettura sopra descritta quindi, in seguito alle
differenti richieste dei client, all'interno dello stesso processo del
componente .EXE vengono creati i diversi thread (uno per ogni
differente istanza del componente)?
Inoltre, la corrispondenza client-istanza del componente (o allo stesso
modo client-thread) viene gestita in modo automatico da COM?
Se le cose stanno cosě, si tratta proprio del classico "uovo di
Colombo"!!
Approfitto ancora del tuo tempo e della tua esperienza.
Il componente COM deve effettuare per i client degli accessi ad un DB.
Di conseguenza, la presenza di thread diversi all'interno del processo-
server puň portare a dei problemi.
Mi devo preoccupare, di conseguenza, della sincronizzazione dei thread
per quanto riguarda le operazioni sul database (lock ed unlock di un
oggetto mutex,ecc...)?
E' penalizzante in termini di prestazioni oppure ancora una volta il
collo di bottiglia č rappresentato dalla rete?
Grazie mille


 collo di bottiglia è rappresentato dalla rete?
Occorre solo un minimo di cura.  L'ideale e` usare un buon DB che
gestisca lui la concorrenza, sara` sicuramente ben ottimizzato per
questo.  Se hai un DB del piffero puo` ben essere LUI il bottleneck
anche se c'e` la rete (o anche se usi un DB buono ma che richieda
accurata configurazione fisica, e la configurazione fisica e` fatta
coi piedi -- pochi indici ausiliari, magari messi su zone poco lette
e spesso aggiornate cosi` da pessimizzare invece che ottimizzare;
disco frammentato; ecc ecc).
Se il DB e` decente e ben ottimizzato probabilmente la concorrenza
se la gioca lui, e se cosi` non e` (o se i tuoi thread devono anche
collaborare un poco su strutture globali _in memoria_ del tuo
processo, ove naturalmente il DB non aiuta:-), probabilmente ti
basa una critical-section, MOLTO piu` leggera del Mutex (il mutex
e` piu` flessibile e potente, indispensabile per coordinare ad
es. processi diversi, o quando serve molta flessibilita` -- ma se
minimizzi le tue critical-section [cioe` le fai il piu` rapide
possibile] e tutti i tuoi thread sono entro lo stesso processo, no
problem, critical section hanno trascurabile overhead).
Un esempio di ottimizzazione: supponiamo che ci sia una
certa, articolata struttura in memoria.  Tutti i thread devono
spessissimo leggerla; ogni tanto, un thread deve cambiarla,
operazione complessa e lenta.
Soluzione probabilmente ottimale: proteggere gli accessi
in lettura con critical-section (sono operazioni comunque
molto brevi); il thread che deve scrivere lo fa *ottenendo
un clone della struttura corrente* (la struttura stessa puo`
essere ottimizzata per poter sempre fornire un clone di
se stessa ad altissima velocita`...), modificando il clone,
poi facendo uno "swap" della nuova roba modificata al
posto della vecchia in un sol colpo (la vecchia resta in giro
sinche` qualcuno la sta accedendo, per garantire la
atomicita` di transazioni -- quel che ti da` un buon DB,
se ne hai uno, ma, per roba in-memoria, devi farti da solo).
Non preoccuparti eccessivamente di queste ottimizzazioni
sinche` non ne hai riscontrato l'effettiva necessita` con
apposite misure, pero`; e` alto il rischio di ottimizzare
*prematuramente* cose che in realta` non stanno mai
davvero sulla "critical path" di esecuzione...!  Tieni solo
presente la "eventuale" necessita` ed architetta di
conseguenza cosi` che potrai implementare quel che
occorre se e quando occorre (basta normalmente lavorare
in buona prassi object-oriented, cosi` che tutte le operazioni
su di una certa struttura-dati siano incapsulate da metodi
dell'oggetto che la contiene...), e in prima fase occupati
invece solamente della *correttezza* del tuo codice.
Alex

 se li gestiscono loro.  Certo, se (sigh!) devi usare Access,...:-(.
Purtroppo è quello che passa il convento...
Faccio tesoro del tuo consiglio per il quale "non è il caso di mettere
il carro davanti ai buoi" e ritorno a qualcosa di più immediato.
Utilizzando (VC++ 6.0) le librerie ATL per sviluppare i componenti COM,
nel caso di scelta di sviluppo di componenti out-of-proc, mi viene
preclusa dal Visual Studio la possibilità di supportare MFC, cosa che
non accade se decido di sviluppare i componenti come DLL.
Se dovessi di conseguenza sviluppare il server COM come DLL, COM
ricorrerebbe all'uso del DLLHOST.EXE come surrogato di DLL (a meno che
non ne utilizzi uno personalizzato).
A questo punto la sincronizzazione delle richiesta dei client COM non
dovrebbe essere un problema a patto di implementare un apartment-
threaded, dico bene?
Vale ancora però quanto detto in merito alla possibilità di ottenere
molteplici componenti, implementati dallo stesso server COM, che girano
in diversi thread entro lo stesso processo?
Se si, la relazione Cliente <-> Istanza rimane biunivoca ed ancora
gestita da COM tramite assegnazione di proxy/stub?


 in diversi thread entro lo stesso processo?
No, perche` i thread chi li genera?
Non si possono correttamente generare thread nel corso di
una DllMain; infatti CComAutoThreadModule e` supportato
solo per serventi che vivono in EXE.
Certamente qualche accrocco ce lo si puo` sognare, ma,
accrocco per accrocco eguale accrocco al quadrato, mi
pare allora meglio accroccare le MFC all'EXE dell'ATL (non
avrai i wizard dello studio, ma le MFC puoi ficcarle comunque
dentro a viva forza; e`un accrocco, c'e` da andare per prove
ed errori, ma se proprio sei deciso ad usarle...).
Alex

 nulla di utile, mi pare.
Bene, visto quanto mi prospetti penso proprio di seguire il tuo
consiglio e di implementare un server EXE "sacrificando" MFC.
A questo punto perň non posso piů utilizzare le classi CDaoDatabese e
CDaoRecordset per lavorare con il database (e quindi non posso
riutilizzare del codice che ho da altre applicazioni).
Purtroppo sino ad ora ho sviluppato applicazioni solamente utilizzando
MFC.
Quali sono le maggiori limitazioni imposte dalla scelta di non
utilizzare MFC?
Qual'e a questo punto il modo migliore per operare con il database?


 Qual'e a questo punto il modo migliore per operare con il database?
Insert/New ATL Object/Data Access/Consumer; vedi anche
la documentazione sugli "OLE DB templates".  Ma questo
accede a livello di OLE DB, cioe` _sotto_ il DAO; non sono
certo di quanto questo ti complichi la vita (ho studiato un
po' il tema ma non ho avuto nessuna occasione di usarlo
per davvero...).
Alex

>per davvero...).
Sicuramente volevi dire sotto ADO.
Gli oggetti ADO hanno un'interfaccia COM (naturalmente) e quindi utilizzabile da C++.
Viceversa per l'accesso ai dati si puo' usare direttamente ODBC con le sue API.
Antonio

     [snip]
OK, ora ho le idee abbastanza chiare almeno per quanto riguarda
l'architettura di questo componente e questo grazie ai tuoi interventi.
Se hai voglia e tempo approfitterei ancora della tua invidiabile
esperienza.
Proseguendo con l'analisi del progetto da sviluppare ho incontrato la
necessità di implementare un comportamento "anomalo" per quanto
riguarda i componenti COM.
Sino ad ora mi è capitato di sviluppare la comunicazione COM a senso
unico: clint->componente.
Ora ho la necessità di far agire il componente da client, informando il
client vero e proprio riguardo a vari eventi che si generano sul server.
Setacciando la poco chiara documentazione di cui dispongo ho trovato
delle interfacce che sembrano fare al caso mio.
Tali interfacce sono
- IConnectionPointContainer
- IConnectionPoint
- IEnumConnections
Non riesco però a capire come il componente riesca a comunicare
l'evento al client?
Cose si intende per connection point?
E per sink (o bacino di eventi)?
Hai mai avuto occasione di utilizzare queste interfacce?


 Hai mai avuto occasione di utilizzare queste interfacce?
Certo, e` una cosa quotidiana.
A volte conviene ottenere le callback con altri
meccanismi piuttosto che non i connection-point,
semplicemente per accelerare connessione e
sconnessione se sono frequenti, a patto che tu
controlli sia i server, sia i client.
Ma nella gran parte dei casi il supporto gia`
presente nell'infrastruttura spinge ad usare
i meccanismi standard.
Alex

 ODBC con le sue API.
Qui non capisco proprio che vantaggio si potrebbe mai avere,
in un software di nuova progettazione quale quello che
stiamo discutendo.  Con OleDB puoi accedere a qualsiasi
fornitore di ODBC _e a molti altri fornitori di dati_, e varie
data sources hanno provider OleDB ottimizzati (a quello che
sento, ma non ho esperienza diretta, le prestazioni nonche`
la portabilita` fra diverse data sources sono decisamente
meglio con OleDB; in _teoria_ dovrebbe sicuramente essere
cosi`, in pratica non so-per-esperienza-personale se sia
_ancora_ cosi`).  Inoltre, grazie all'impostazione OO, OleDB
(e piu` ancora ADO) sono piu` agevoli da usare.  Quindi...?
Alex

>stiamo discutendo.
Era solo una possibile soluzione nel caso in cui chi scrive l'applicazione avesse gia' dimestichezza con le API ODBC.
In una prima implementazione (o prototipo) puo' essere comodo usare cose che hai gia' pronte. Io ad esempio ho gia' delle mie classi alternative ad MFC che interfacciano le suddette API.
In seconda battuta o contemporaneamente si puo' sviscerere bene il problema accesso ai dati.
Concordo con te sul vantaggio di ADO o OLEDB per le nuove applicazioni.
Antonio

     [snip]
Finalmente dopo una settimana di problemi (per altro non ancora del
tutto risolti) con la rete riesco di nuovo ad accedere al forum.
Anche se in ritardo ti ringrazio per la dettagliata descrizione in
merito all'implementazione di una outgoing interface per la notifica di
eventi da un componente verso il client.
Nel corso di questo periodo di "isolamento" ho avuto modo di scontrarmi
con altri problemi.
Continuando a discutere dello stesso progetto pensavo di implementare
delle strutture dati complesse (dei veri e propri oggetti) da
utilizzare per la comunicazione tra client e componente.
- Come posso fare per descrivere queste strutture a livello di
interfaccia (IDL)?
Ho trovato della documentazione sul tipo "variant"; ho letto però che
tipicamente è utilizzato per l'automation e quindi con IDispatch.
- Può essere utile utilizzare tale tipo nel mio caso o rischio di
complicarmi maggiormente la vita?
- Ho sentito parlare anche di oggetti OLE. E' corretto dire che si
tratta di oggetti implementati da un'applicazione e messi in qualche
modo a disposizione di altre applicazioni?
- Possono essere utili nel mio caso?
- Inoltre, che tipo di marshalling, secondo te, mi conviene utilizzare
(standard, librerie dei tipi, personalizzato)?
Grazie in anticipo


 (standard, librerie dei tipi, personalizzato)?
Il marshaling via librerie dei tipi tende ad essere il piu`
comodo per applicazioni non distribuite, quello standard
per applicazioni distribuite (la comodita` e` in funzione
di quello che devi distribuire e istallare sulle varie macchine
in gioco: col marshaling standard, solo la piccola DLL
proxy/stub puo` essere sufficiente, e non sei tenuto a
registrare la type-library).  Ma sono dettagli, come pure
lo e` quello che il marshaling standard e` mediamente un
poco piu` veloce di quello typelib.
La cosa importante e` che il marshaling typelib ti pone
seri vincoli relativamente a quello che possono esporre
le tue interfacce: in pratica esse devono essere quasi
compliant con Automation, che e` un notevole vincolo
(a meno che tu non intenda comunque sopportarlo allo
scopo di supportare la massima varieta` di clienti, ovvio,
nel qual caso tanto vale usare anche il marshaling typelib
visto che comunque la typelib dovrai distribuirla e anche
istallarla per massima comodita` dei tuoi clienti...!).
Il marshaling custom (personalizzato) si giustifica come
ottimizzazione in pochissimi casi, e comunque si ottiene
implementando IMarshal per quelle (si spera pochissime:-)
classi che vogliono proprio a tutti i costi fare marshal-by-
value o altre stranezze:-).  Puoi pensarci in sede di "fine
tuning" per eventuali colli di bottiglia della tua applicazione
una volta gia` sviluppata e ben funzionante.
Alex


OK, comincio allora con il marshalling standard, rimandando eventuali
variazioni al verificarsi di significative limitazioni.


 L'oggetto deve perciò essere necessariamente allocato dal componente?
L'oggetto-dati dovra` presumibilmente essere un parametro
[out] di un qualche metodo del componente, e se cosi` e`
allora, come da regole generali del COM, esso dovra` appunto
essere "allocato dal chiamato" (il componente); se poi, come
da primo suggerimento, usi un'interfaccia IChiamata, visto che
sara` chiaramente "il componente" (terminologia sempre un
poco dubbia... diciamo *il server*, eh?-) ad implementare i
metodi di quell'interfaccia (e le proprieta` sono in pratica dei
metodi particolari), chiaramente ivi avrai anche l'allocazione.
Alex

 ma OK in COM in quanto tale).
Come posso in IDL dichiarare un oggetto di tipo struct?
Grazie ancora


 Come posso in IDL dichiarare un oggetto di tipo struct?
L'esempio tipico e`
typedef struct _PERSONA_TAG
{ 
    BSTR Nome;
    BSTR Cognome;
    int anni;
    BSTR Indirizzo;
} PERSONA; 
La sintassi, com'e` vero in generale per IDL, e` molto simile
a quella del C.  Naturalmente, ci sono ampie possibilita` di
"personalizzazioni", soprattutto attraverso gli attributi posti,
come al solito, fra [quadre]  (campo per campo).
Alex

 stesso appartamento (e quindi thread).
Cerco ora di fare il punto della situazione (mi sforzo il piů possibile
di utilizzare la terminologia corretta).
Ho necessitŕ di costruire un'applicazione server-multiclient con
l'utilizzo di DCOM.
Per quanto riguarda il lato server, implemento i componenti come
apartment-thread utilizzando dei server COM ".EXE" .
Cosě facendo i problemi di sincronizzazione fra diversi accessi allo
stesso oggetto da parte dei client, sono gestiti dall'SCM (per il fatto
di essere apartment-thread).
In questo modo alle richieste di diversi client vengono generate
diverse istanze dello stesso oggetto, dove ogni istanza č legata 1:1
con un client (questo legame 1:1 avviene attraverso i relativi
proxy\stub).
Perciň ogni client č in grado di lavorare con _una ed una sola_ istanza
del componente COM dal momento della richiesta al momento del rilascio
dello stesso.
E' possibile inoltre generare un pool di thread in grado di garantire
l'esecuzione di tutte le istanze dei componenti presenti.
Dato che un apartment č caratterizzato dall'avere un solo thread, di
conseguenza diverse istanze del componente dovranno condividere lo
stesso apartment.
Quanto ho scritto č corretto?
Se č corretto, avrei bisogno ancora di qualche chiarimento (porta
pazienza:-)
- Se un client chiude la sessione di lavoro rilasciando il componente,
č possibile fare in modo che quest'ultimo generi un evento che
notifichi il verificarsi di questa operazione (l'evento non deve essere
diretto al client ma ad un altro oggetto)?
- Due istanze di un componente che condividono lo stesso apartment (e
quindi lo stesso thread) sono due processi diversi (come processo
intendo l'insieme di programma, spazio di indirizzamento, registri,
stack, SP, PC, ecc...)?
Se, come penso (o spero!!) di aver capito, lo sono in cosa differiscono?
- Ho provato ad utilizzare la classe CComAutoThreadModule da te
indicatami ma con scarso successo. Puoi farmi vedere del codice di
esempio per l'utilizzo di tale classe?
- Dove trovi la pazienza di stare dietro a casi disperati come quello
che rappresento io?
Grazie mille


 esempio per l'utilizzo di tale classe?
Ti suggerisco: anzitutto, un ripasso "di fondo" degli argomenti
sinora visti, col buon articolo di Jason Smith che trovi a:
http://msdn.microsoft.com/workshop/components/com/comthread.asp
e i link che l'articolo stesso comprende;
poi, l'articolo di Anderson sulle class factories, a:
http://www.comdeveloper.com/articles/class_factories.asp
(come per tutti gli articoli di COMdeveloper, puoi anche scaricarne
rapidamente una versione solo-testo, zippata; vedi
http://www.comdeveloper.com/articles/
 per l'elenco completo);
e l'articolo di Grimes sul threading in COM, che trovi a:
http://www.vsj.co.uk/archive/outlook-9906.asp
.
Nessuno di questi (credo) ha un esempio completo di uso di
CComAutoThreadModule.  Prova cosi`.  Costruisci con il wizard
di Visual Studio 6 un server COM ATL, di tipo EXE.  Vedrai,
in uno dei sorgenti che il wizard ti prepara, la dichiarazione
CExeModule _Module;
(viene posta subito prima dell'object map).  OK sin qui...?
Bene, cambia questa riga a...:
class CMyModule :
public CComAutoThreadModule<CComSimpleThreadAllocator>
{
public:
   LONG Unlock( )
   {
      LONG l = CComAutoThreadModule<ComSimpleThreadAllocator>::Unlock( );
      if (l == 0)
         PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
      return l;
   }
   DWORD dwThreadID;
} _Module;
proprio come suggerito dall'MSDN (puoi anche togliere,
se vuoi, dallo stesso file sorgente, tutte le parti
relative a CExeModule).
Poi aggiungi un oggetto (apartment-threaded) e
nell'ambito della sua dichiarazione di classe poni:
DECLARE_CLASSFACTORY_AUTO_ THREAD()
cosi` che la sua classfactory usi appunto il thread
pool gestito da _Module.
Alex

 pool gestito da _Module.
In che modo la CMyModule crea il pool di thread necessari per eseguire
tutte le istanza del componente (tutti in una volta, un pò per volta
sulla base del numero di apartment-threaded esistenti, ecc...  )?
L'assegnazione agli apartment dei thread appartenenti al pool viene
gestita da CMyModule?


 gestita da CMyModule?
Viene delegata a CComSimpleThreadAllocator (o altra tua
classe customizzata allo scopo).
Alex

 _Module dovrebbe essere dichiarato in stdafx.h; hai verificato?
Originariamente in stdafx.h esiste una definizione del tipo:
class CExeModule : public CComModule
{
public:
	LONG Unlock();
	DWORD dwThreadID;
	HANDLE hEventShutdown;
	void MonitorShutdown();
	bool StartMonitor();
	bool bActivity;
};
CExeModule _Module;
Se in ServerCOM.cpp (implementazione del WinMain) sostituisco a...
CExeModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)
END_OBJECT_MAP()
...
la definizione...
class CMyModule : public CComAutoThreadModule<CComSimpleThreadAllocator>
{
public:
   LONG Unlock()
   {
      LONG l=CComAutoThreadModule<CComSimpleThreadAllocator>::Unlock();
      if (l == 0)
         PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
      return l;
   }
   DWORD dwThreadID;
} _Module;
BEGIN_OBJECT_MAP(ObjectMap)
END_OBJECT_MAP()
...
in stdafx.h non riesco a definire CMyModule perchè ho l'errore:
ServerCOM.cpp(20) : error C2011: 'CMyModule' : 'class' type redefinition
Se, invece che in ServerCOM.cpp, definisco in stdafx.h la CMyModule
(con la definizione di cui sopra) non viene riconosciuto il metodo
'StartMonitor':
ServerCOM.cpp(155) : error C2039: 'StartMonitor' : is not a member of
'CMyModule'
Roby
(Gli indirizzi che mi hai suggerito sono davvero molto interessanti!)


 'CMyModule'
...le aggiunte che ti fa il wizard al normale CComModule, per
generare la classe CExeModule, sono carine ma non sono
indispensabili e per questo non le ho riportate anche nella
class CMyModule che ti ho portato come esempio; naturalmente
devi togliere anche le chiamate ai metodi che ho tolto... oppure
rimetti i metodi anche in CMyModule se pensi che ti servano!
Alex

 anche nel .cpp;
OK, ho definito la classe solo in stdafx.h come segue:
class CMyModule : public CComAutoThreadModule<CComSimpleThreadAllocator>
{
public:
   LONG Unlock()
   {
      LONG l=CComAutoThreadModule<CComSimpleThreadAllocator>::Unlock();
      if (l == 0)
         PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
      return l;
   }
   DWORD dwThreadID;
} _Module;
extern CMyModule _Module;
Ho perņ il seguente errore in fase di link:
StdAfx.obj : error LNK2005: "class CMyModule
_Module"(?Module@@3VCMyModule@@A) already defined in ServerCOM.obj
anche se l'unica definizione che ho di CMyModule č in stdafx.h
All'interno di uno degli aricoli che mi hai segnalato ho letto che...
"...ATL has a solution to this with CComAutoThreadModule and
ComClassFactoryAutoThread which
allows you to create a pool of STA threads and ATL will choose which
thread is used to create a STA object when a client request comes in."
Quindi inserendo CMyModule all'interno del server COM, aggiungo al
componente la capacitą di creare (all'inizio) un pool di thread (di
tipo single threaded-apartment); in seguito poi ad ogni richiesta dei
client, vengono generate le istanze del componente per ognuna delle
quali ATL assegnerą un thread del pool (e quindi un apartment)?
Roby


 quali ATL assegnerą un thread del pool (e quindi un apartment)?
Esatto: ciascuno degli N thread sara` usato per gestire circa N1/N
delle N1 istanze del componente attive in un dato momento.
Alex

 ...aggiungi CMyModule _Module al solo ServerCOM.cpp.
OK, grazie ora funziona.
E' in questo punto del codice che CComAutoThreadModule crea il pool di
thread?
...
 _ASSERTE(SUCCEEDED(hRes));
    _Module.Init(ObjectMap, hInstance, &LIBID_PROVATHREADLib);
    _Module.dwThreadID = GetCurrentThreadId();
...
Il "motore" per la creazione e l'assegnazione dei thread alle istanze
dei componenti è quindi già completo?


 dei componenti è quindi già completo?
In teoria si`.  Che dubbio hai...?
Alex

 In teoria si`. Che dubbio hai...?
E' troppo bello per essere vero!
Quindi semplicemente dalla scelta di sviluppare un server COM ".EXE" e
dall'utilizzo di CComAutoThreadModule, si è ottenuto un oggetto
1. capace di sincronizzare le richieste da n client
2. capace di limitare l'overhead utilizzando un pool di thread per
eseguire tutte le istanze del componente
E' grandioso!!
Su un'altro progetto "giocattolo", nel frattempo ho realizzato con ATL
un servente che specifica un'interfaccia per generare un evento verso
un cliente che implementi tale interfaccia.
Per lo sviluppo del cliente utilizzo un normale EXE MFC.
All'interno del cliente ho importato le type library:
#import "Componente.exe"
using namespace COMPONENTELib;
...
Come posso implementare al client l'interfaccia che ho specificato nel
componente (nel menu di contesto non viene visualizzata la voce
"implement interface")?


 "implement interface")?
Il modo piu` semplice (secondo me) per implementare interfaccie
COM e` usare l'ATL -- cosa che puoi benissimo fare anche entro
un progetto che e` "un normale EXE MFC".  Insert/New ATL Object,
e la prima volta Visual Studio ti chiedera` il permesso di attrezzare
il progetto per supportare *anche* ATL (oltre che MFC).  Daglielo,
e lavora con ATL...!
Esiste il modo di implementare interfacce (di puro dispatch, come
normalmente devono essere le "source interfaces" in gioco) anche
in MFC, usando dei proxy che l'MFC stesso sa generare.  Ma e`
tanto che non lo faccio, che non mi ricordo neppure piu` bene
come si faceva.  Usa ATL, "c'est plus facile"!
Alex

 COM e` usare l'ATL
Fantastico, questa non la sapevo!
Fino a poco tempo fa utilizzavo VC++ 5.0 con il quale non era permesso
introdurre oggetti ATL (Insert\New ATL Object) se il progetto è aperto
con MFC.
Ma ora come posso implementare nel cliente l'interfaccia di outgoing
specificata dal componente?
Nonostante abbia importato nel cliente le type library del componente,
non vedo ancora (all'interno del class view) tale interfaccia...


 AtlAdvise per connettere, e fai tutto.
Ho sviluppato in ATL un cliente "giocattolo" che utilizza un oggetto
(sink?) per implementare un'interfaccia di outgoing specificata da un
servente.
Devo ora effettuare il collegamento tra il connection point del
servente ed il sink del cliente; a tale scopo, utilizzo l'istruzione
AtlAdvise che richiede come parametri:
- puntatore all'IUnknown del componente;
- puntatore all'IUnknown del sink;
- un LPDWORD dove "raccogliere" il cookie.
Probabilmente mi perdo in un bicchiere d'acqua, ma come posso ottenere
l'IUnknown del sink?
Ho l'interfaccia del sink, ma non il clsid o il ProgId e l'unico modo
che conosco per ottenere un'interfaccia di un oggetto è attraverso
CoCreateInstance (o simili) e QueryInterface!!
Problema di secondaria importanza:
per implementare l'interfaccia al client (realizzato con MFC) ho
inserito un nuovo oggetto ATL nel progetto.
Selezionato "Implement Interface..." dal menu di contesto ho importato
le type library del componente ma nella lista della finestra "Implement
Interface" viene visualizzata solamente l'interfaccia del componente e
non la source interface (outgoing interface) che voglio implementare.
Per implementare la source interface nel sink ho dovuto:
- eliminare la stringa "no_namespace" dalla linea di codice #import...
- aggiungere di seguito "using namespace XXXLib;"
- modificare, nella serie dei template dai quali eredita la classe
dell'oggetto sink, il secondo parametro dell'ultima riga di quanto
segue inserendo l'IDD della source interface in luogo dell'IDD
dell'interfaccia del componente
class ATL_NO_VTABLE CSink :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CSink, &CLSID_Sink>,
	public ISupportErrorInfo,
	public IConnectionPointContainerImpl<CSink>,
	public IDispatchImpl<ISink, &IID_ISink, &LIBID_Sink>,
	public IDispatchImpl<IComponent, (*)&DIID__IComponentEvents(*),
&LIBID_POLYGONLib>
- infine, implementare i metodi dell'interfaccia di outgoing.
E' normale operare così :-( oppure ho dimenticato di fare qualcosa :-)?
Dove ho sbagliato?
Grazie


 Dove ho sbagliato?
Vedi "Supporting IDispEventImpl" nell'MSDN, mi pare
l'approccio piu` semplice.  Ti conviene fare una search
di IDispEventImpl nell'MSDN, perche` ci sono un paio
di bug documentati nella knowledge-base (con relativi
workaround, se ti colpiscono).
Alex