Newsgroup: it.comp.programmare.win32
Titolo: [Help] Invocare funzioni server OLE

Salve, mi aiutate a risolvere questo problema?
    Vorrei automatizzare l'uso di un programma di win9x, cioé preparare i
dati con un altro programmino e poi sottomettrli al primo.
    Il primo programma non l'ho scritto io, ho solo l'eseguibile ma nella
documentazione c'è scritto che è possibile usarlo come server OLE  e ci sono
le dichiarazioni delle funzioni che è possibile invocare.
    Io conosco il C++, ma non so niente di OLE e WIN32. Come faccio a
invocare le funzioni del server OLE dal piccolo programmino che mi accingo a
scrivere? Come faccio a passare i parametri? (ho letto qualcosa su un tipo
VARIANT, ma mi servirebbe qualche dritta)
    Grazie a chiunque saprà e vorrà rispondermi. Ciao
                    Paolo

 wrote in message
U7sr4.13347$317.1...@news.infostrada.it...

Che versione di C++ usi?  Il Visual C++ della Microsoft offre
delle "scorciatoie" che possono essere molto comode per il
lavoro che ti proponi di fare.
Che interfacce pubblica il "primo programmino" che vuoi usare?
"Pura automation" (o come anche si dice, "puro dispatch"), o
custom, o duali?  Le interfacce dispatch sono potenzialmente piu`
comode da usare per linguaggi puramente interpretati (cioe` di
"scripting"), quelle custom per linguaggi compilati (come il C++
o il Visual Basic) -- le duali si possono usare in entrambi i modi
e quindi offrono la massima comodita` per il codice cliente.
VARIANT tipicamente si usa per le interfacce di dispatch: e` un
tipo di "unione discriminata" (una struct con alcuni campi fissi
di descrizione e un campo che e` una union e puo` avere tanti
tipi diversi) che permette di passare parametri di vari tipi anche
da linguaggi che non hanno il concetto di "tipo di dati".
Le API Windows ti offrono tante chiamate per gestire i VARIANT
(e i SAFEARRAY che spesso le VARIANT contengono).  Inoltre,
trovi vari tipi che incapsulano le VARIANT dal punto di vista C++
rendendole piu` comode da usare: in Visual C++, trovi la
variant_t come parte del "supporto nativo COM", e la classe
CComVariant, parte dell'ottimo framework ATL (personalmente
preferisco quest'ultima, che offre al programmatore un controllo
piu` dettagliato e preciso di quello che sta succedendo).
Ma il concetto base di COM e` la _interfaccia_.  I puntatori ad
interfacce COM sono la cosa principale che un cliente COM deve
gestire; anche qui trovi varie versioni di smart pointer che ti
facilitano la vita (e anche qui preferisco quelle che offre la ATL,
CComPtr e CComQIPtr).
Grosso modo, un programma cliente COM fara` cose del tipo
(parecchie le puo` fare un framework per suo conto...):
-- inizializzare il COM (CoInitialize o CoInitializeEx)
-- scoprire l'identificatore esatto della coclass (component-class)
    (CLSIDFromProgID, ecc)
-- istanziare un servente di quella classe (CoCreateInstance o
    vari altri approcci) o connettersi a un servente gia` esistente
    e disponibile (GetActiveObject)
-- usare le interfacce di quel servente e/o oggetti ausiliari cui
    il servente da` accesso
-- rilascio delle connessioni (punk->Release)
-- chiusura del COM (CoUninitialize)
Il CLSID dei componenti che vuole istanziare puo` anche essere
gia` noto a compile-time; l'IID delle interfacce vuole usare deve
esserlo (in pratica, esclusi cioe` i linguaggi che permettono di
generare al volo codice-macchina) a meno che non usi delle
interfacce di puro dispatch.
OLE (l'Object Linking and Embedding) e` una sovrastruttura
complessa e specializzata sopra il COM ed e` improbabile che
tu ne abbia bisogno.  C'e` probabilmente una confusione di
termini, perche` il marketing MS in vari periodi storici del
passato ha usato a sproposito "OLE", e piu` avanti "Active/X",
per riferirsi in realta` al COM che sta sotto ad entrambe
queste tecnologie.
Alex

Caio Alex e grazie per aver risposto.
Purtoppo non ho capito molte delle cose che hai cercato di spegarmi: nella
documentazione del programma che vorrei automatizzare c'č solo scritto che
si tratta di un out-of-process EXEcutable, che lo si puň attivare come
server OLE (c'č un piccolo eseguibile che si occupa della registrazione), e
poi ci sono le dichiarazioni delle funzioni che č possibile invocare, non di
piů. Io come ti ho detto conosco il C++ ma non so niente di OLE, COM, WIN32
e via dicendo, e cercavo solo una scorciatoia, appunto, per realizzare
questa automazione.
Ho a disposizione il Borland C++ 5.0 e il MSViusalC++ 6.0.
Se č una cosa relativamente semplice dammi qualche dritta, altrimenti per
ora dovrň abbandonare il progetto.
Ciao e ancora grazie.

 wrote in message
KwTr4.23311$317.2...@news.infostrada.it...

Non e` difficilissimo...!  Soprattutto non con MSVC++ 5 e successivi,
grazie alla #import.  La documentazione, se veramente comprende
solo cio` che dici, e` pero` decisamente deficitaria.
Prova a fare un programmino-giocattolo che comprende la riga:
#import "c:/pippo.exe"
supponendo che l'eseguibile che ti interessa sia pippo.exe e viva
in c:/, e vedi se MSVC++ ti genera un file pippo.tlh (nel directory
dove mette anche gli .obj).  Se si`, sei a 90% dell'opera, perche`
significa che pippo.exe comprende una typelib come sua risorsa
(come DOVREBBE fare qualsiasi buon servente COM...) e ti basta
usare opportunamente gli smart-pointer che la pippo.tlh dichiara
e i metodi delle interfacce accedute loro tramite.
Alex

Se si`, sei a 90% dell'opera,
Ciao Alex Grazie ai tuoi consigli sembra che sia arrivato al 90%
dell'opera:ho il mio bel file pippo.tlh
Ora c'è qualche altra scorciatoia o comunque qualche altra cosa che devo
sapere per andare avanti?
Grazie ancora, Paolo

 wrote in message
news:dIas4.28737$317.2...@news.infostrada.it...

Leggi il file pippo.tlh e vedrai che definisce un namespace PippoLIB
o simili; aggiungi dunque un'istruzione
    using namespace PippoLIB;
subito dopo l'#import, per semplicita` (altrimenti dovrai usare
PippoLIB::IPippoPtr ecc ecc per riferirti a tutti i nomi che il .tlh
dichiara, o altre forme alternative di using).
Vedrai poi che il .tlh definisce degli smart-pointer verso una o
piu` interfacce.  Leggilo e capirai sicuramente quale sia la
interfaccia che serve a te; avra` i metodi e le proprieta` che
ti interessa chiamare.
Supponi sia IPippo, allora lo smart pointer e` IPippoPtr.
Scrivi cosi` il tuo main (o WinMain, equivalentemente):
int work(int argc, char* argv[]);
int main(int argc, char* argv[])
{
    CoInitialize(0);
    int rc;
    try {
        rc = work(argc, argv);
    } except(_com_error& err) {
        // segnala l'errore basato su err.error() ecc
        rc = -123;
    }
    CoUninitialize();
    return rc;
}
e metti in work quel che normalmente metteresti in
main.
NON tenere smart pointer come variabili statiche o
globali, o se proprio devi farlo accertati di azzerarle
PRIMA dell'uscita del programma (specificamente,
PRIMA del CoUninitialize...!).
Tipicamente avrai:
int work(int argc, char* argv[])
{
    IPippoPtr pPippo("Nomedel.Componente");
    pPippo->PutQualcosa(23);
    int i = pPippo->GetQualcosaltro();
    if(i != 234)
        pPippo->UnMetodoCheTiPiace();
    else
        pPippo->UnAltroMetodo("ciao mama");
    return 57;
}
o simili.
Alex