Newsgroup: it.comp.lang.c++
Titolo: Help me!!!

Salve a tutti,
scrivo al newsgroup ma soprattutto ad Alex Martelli, che è stato molto
gentile a darmi delle dritte su come risolvere il problema con DCOM.
Nonostante tutto il mio tentativo di farmi restituire una stringa dal server
non ha avuto ancora sussesso.:-)
Poichè sono convito che il modo ci sia ma che sia io a non essere in grado
di gestire la questione mi rivolgo nuovamente a voi ponendovi diversi
quesiti.
L'ambiente di sviluppo è il VC++5.0 avvalendomi delle ATL.
Supponiamo che il  mio ATL project si chiami Pippo e il mio Simple COM
Object abbia una classe di nome PippoObj con associati i files PippoObj.h e
PippoObj.cpp.
Aggiungo a questo punto nell'IDL file la funzione che intendo esportare e
secondo le indicazioni datemi da voi scrivo:
HRESULT funz([in] const char*, [out, retval] char**);.
Nel momento in cui vado a compilare l'IDL file quello che ottengo è:
1) Nel file Pippo.h,autogenerato al momento della compilazione dell'IDL file
(MIDL), il metodo funz sopra specificato prende come parametri degli
unsigned char* invece che dei char*.
2) Invece sia nell'header file che nel source file di PippoObj il
compilatore MIDL riporta correttamente i parametri da passare al metodo
definito.
--La domanda associata a questi punti è:
--Come faccio ad evitare questa incongruenza e ad avere una coerenza di tipi
che passo al metodo da esportare?
Una strada l'ho trovata ed ho definito invece che char* ,LPSTR (so che si
tratta dellastessa cosa); l'unico dubbio che ho e che non sia la via
corretta perchè a questo punto ho problemi nel farmi ritornare la stringa
voluta.
Seguendo le indicazione da voi fornitemi "--un parametro [out] viene
allocato dal chiamato, e liberato dal
chiamante con i metodi CoTaskMemAlloc e CoTaskMemFree", ma nonostante tutto
nel passare i dati dal client al server e viceversa viene perso il
riferimento alla locazione di memoria puntata.
Cosa posso fare per uscire da questo tunnel?
Per chiarezza includo tre estratti dal client, dal server e dall'IDL:
--Client:
 LPSTR lpRitorno;
 m_pIServMatObj->dup("HELLO", &lpRitorno);
--IDL
....
 interface IServMatObj : IDispatch
 {
  [id(1), helpstring("method dup")] HRESULT dup([in, string] LPSTR val,
[out, string] LPSTR* ret);
 };
.....
--Server:
STDMETHODIMP CServMatObj::dup(LPSTR val, LPSTR * ret)
{
 unsigned int i;
 *ret = (char*)CoTaskMemAlloc(strlen(val) + 1);
 for (i = 0; i < strlen(val); i++)
 {
  *(*ret + i) = *(val + i) - 'A' + 'a';
 }
 *(*ret + i) = '\0';
 return S_OK;
}
Ringraziandovi sentitamente in anticipo, auguro a tutti buon lavoro.
Cordiali saluti  Matteo.

 };
Questa interfaccia non e` compatibile con Automation (quindi e`
inutile derivarla da IDispatch, tanto non puo` essere duale!).  Ti
sei ricordato di preparare, e registrare sia sul cliente sia sul
servente, la libreria di proxy/stub?  I sorgenti (qualcosa_p.c
e dlldata.c) te li fa MIDL.  Ricorda che il marshaling lo hai
"gratis" per le interfacce Automation-compliant (che hanno
anche il vantaggio di potere in effetti essere duali), ma non
per le altre; queste ultime richiedono la libreria di proxy/stub
(opportunamente registrata, tra l'altro).
Se il tuo progetto si chiama pippo, MIDL ti ha generato
pippops.mk
; fai nmake /f 
pippops.mk
 per generare la
pippops.dll.  Poi, distribuiscila, e come parte della
istallazione del tuo componente (anche sui clienti
ove non istalli l'exe, ma solo questa pippops.dll!)
fai girare regsvr32 sulla pippops.dll (nella sua collocazione
definitiva, qualunque essa sia).
Se non vuoi queste complicazioni, usa interfacce
Automation-compliant; tra l'altro, spesso (non sempre)
il codice di marshaling per queste e` migliore (piu`
ottimizzato, penso manualmente) di quello che puo`
generare MIDL dal sorgente IDL.  In questo caso,
probabilmente, questo delta di prestazioni sarebbe
sufficiente a ripagare l'overhead di usare BSTR.
Comunque, preparando e registrando la proxy/stub
dll non dovrebbero esserci problemi.  Ho provato,
tanto per essere sicuri al 100%; ATL EXE con simple
object, chiamato Pippo, e unico metodo dell'IPippo:
  [id(1), helpstring("method dup")] HRESULT dup([in, string] LPSTR val, [out,
string] LPSTR* ret);
Build di atlexe.exe, poi da linea comando (stando
nel directory del progetto):
nmake /f 
atlexeps.mk
poi ancora
regsvr32 atlexeps.dll
(e non scordarti di copiare la dll anche sul client e anche
li` registrarla...!).
Il cliente, banale applicazione a console:
#import "../atlexe.tlb"
using namespace ATLEXELib;
#include <stdio.h>
int main()
{
    CoInitialize(0);
    {
    IPippoPtr pPip("Pippo.Pippo.1");
    LPSTR pres;
    pPip->dup("HELLO", &pres);
    printf("%s\n", pres);
    }
    CoUninitialize();
    return 0;
}
Il programma stampa "hello", come previsto.
Alex