Newsgroup: it.comp.lang.visual-basic
Titolo: Non fare bloccare il programma, come?

ciao a tutti!
ho utilizzato la seguente funzione x crearmi un mio netsend (incollata
in fondo al post)
siccome quando manda il mex, finchè non ha terminato l'operazione mi
blocca l'intero programma, facendolo sembrare impiantato
volevo sapere se c'era un modo di fargli eseguire le sue operazioni
continuando cmq a darmi la possibilità di muovermi nel mio programma
in un post ho visto che c'è la possibilità di fare una cosa simile
quando si eseguono molte operazioni, utilizzando un apposit istruzione
(di cui ora non ricordo il nome :-) ma che nel mio caso non funziona,
xchè si blocca lo stesso
qualcuno sa se si può risolvere questo problemz?
ciaociao
[BEGIN CODE]
Private Declare Function netSend Lib "netapi32" Alias
"NetMessageBufferSend"
(ByVal cServerName As String, ByVal cMsgName As String, ByVal
cFromName As
String, ByVal cBuf As String, ByRef iBufLen As Integer) As Integer
Public Function NetSendMessage(ByVal sUser As String, ByVal sMsg As
String)
As Boolean
    Dim sBuf
    Dim sMsgFrom As String
    Dim sMsgName As String
    Dim Net_Api_Status As Long
    NetSendMessage = False
    sBuf = StrConv(sMsg, vbUnicode)
    sMsgName = StrConv(sUser, vbUnicode)
    Net_Api_Status = netSend(vbNullString, sMsgName, vbNullString,
sBuf,
ByVal Len(sBuf))
    NetSendMessage = Not CBool(Net_Api_Status)
End Function
[END CODE]

 xchè si blocca lo stesso
Cerca di spiegarmi come fai a non ricordarti il nome, ma a dire che non
funziona.....
AH, forse era che una volta ti ricordavi il nome, l'hai provata, non
funzionava e poi l'hai dimenticata?
Non sapendo se quell'istruzione era il DoEvents provo a suggerirtela lo
stesso.
Salutoni
Sergio

 stesso.
E mi ricorreggo: forse era proprio il Doevents, perchè in effetti non credo
che abbia senso nel contesto delle tue funzioni...

 wrote in message
news:zbUo9.23767$Fz.6...@news1.tin.it...

Io non ho visto cicli .. per cui credo sia la API ad essere bloccante ...
è inutile inserire l'istruzione doevents in quanto verrà eseguita solo
quando il processo ritorna dall'api al prog chiamante ...
dovresti vedere meglio le impostazioni dell'API oppure crere un thread a
parte :
in questo modo potresti richiamare il processo contenente l'API (P2) il
quale non rimane in esecuzione separatamentente dal processo chimante (P1).
Certo che se P2 è una sanguisuga di risorse è come fare la cancellazione di
2 directory da 1 GB ognuna ... è si vero che esplora risorse ti consente di
inviare il comando di eliminazione della seconda direcotory ancor prima che
la 1^ dir sia stata effettivamente eliminata .. ma contemporanemente non
potrà eseguire le 2 operazioni .. prima ne termina una e poi esegue l'altra.
Se non sbaglio tramite alcune api sei in grado di creare un thread .. ma non
le ho mai usate .. un altro modo è quello di creare un componente exe
activex che effettivamente crea un processo distinto e lo puoi gestire come
se fosse una normale DLL (istanziamenti a parte).
Comunque il problema non cambia ... dipende sempre da quante risorse vengono
impegnate nei thread perchè .. anche se Win è multitask ... il tuo
processore è unico.
Saluti

 è inutile inserire l'istruzione doevents in quanto verrà eseguita solo
In effetti era proprio quello che volevo dire.... che probabilmente aveva
usato Doevents e ovvviamente non aveva funzionato per il motivo che indichi
tu
Salutoni
Sergio

 sBuf,
Poiché è la chiamata a netSend a bloccarti (quindi codice non tuo) in vb non
puoi fare niente. Ti conviene spostare la chiamata in un thread separato -
il modo più sicuro per farlo, anche se un po' macchinoso, consiste nel
creare un activex-exe in vb e implementare in questo un metodo che esegua la
chiamata alla netSend. In questo modo il tuo prg potrà eseguire una chiamata
asincrona.
--
rumplestiltskin

ehm si, era la Doevents :-)
proverň a vedere se capisco se si puň impostare la api, anche xchč le
altre soluzioni sono momentaneamente al di sopra delle mie conoscenze
in vb!!!
grassie 1000

 asincrona.
E' una cosa che non ho ancora fatto, se non è lunghissima, mi
spiegheresti il procedimento? oppure magari qualche dritta x cercare
sulla guida o qui nel ng
cmq creando questo activx poi cmq riesco a far capire quando ha
eseguito l'operazione?
nel senso, essendo un netsend, è giusto che non mi blocchi
completamente il programma, ma cmq è anche giusto che magari mi
disabiliti la possibilità di mandare i messaggi finchè non ha
terminato l'operazione, e non so se col metodo che dici tu si può fare

 terminato l'operazione, e non so se col metodo che dici tu si può fare
Certo che si può fare ... l'interfaccia te la crei tu con tutte le sue
proprietà metodi ed eventi ...
puoi crearti il tuo pool di chiamate netsend e servirle in particolari
ordini (non necessariamente in struttura fifo) .. potresti anche rifiutare
la richiesta di chiamata stessa ... potresti addirittura crearti un thread
per ogni chiamata.
MSDN mi sembra non sia molto specifico a riguardo .. però è certamente un
buon inizio ...
Saluti

Grazie, proverò a vedere, ma mi sa che il momento lo lascio così
anche xchè devo ancora riuscire a ricavare il nick degli utenti connessi 
alle varie macchine al posto dei nomi dei pc
tu ne sai qualcosa? :-)
ho fatto diverse prove, ma al massimo riesco a ricavare quello del mio 
pc, quindi mi sorge il dubbio che non si possa fare
però non ci metterei la mano sul fuoco :-)
Fox Mulder ha scritto:


 terminato l'operazione, e non so se col metodo che dici tu si può fare
Detta alla buona:
(a) crei un nuovo progetto come activex-exe (come default ti viene creata
una classe pubblica, se non erro, altrimenti la agiungi tu al progetto;
magari le dai un nome cristiano)
(b) nella classe pubblica implementi una funzione Public che *non* eseguirà
la chiamata a NetSend, ma avrà praticamente questo scopo (quindi la funzione
avrà i parametri necessari: questo programma non ha possibilità di
condividere memoria basic con l'altra applicazione, quindi tutto quello che
ti serve devi passarlo come argomento della funzione o implementarlo come
proprietà pubblica della classe)
(c) nella funzione devi attivare un meccanismo a tempo per l'esecuzione
della netsend e quindi rilasciare il controllo uscendo dalla funzione;
l'effettiva esecuzione della netsend avverrà dopo un breve tempo e quindi
quando il chiamante avrà ripreso il controllo dopo l'uscita dalla libreria.
(d) se vuoi che l'app chiamante venga avvisata della fine esecuzione puoi
implementare alcuni eventi nella classe pubblica (la soluzione più semplice
sarebbe quella di implementare una proprietà "Status" che ti ritorni un flag
indicante se l'operazione è terminata; purtroppo, però, se l'operazione è in
corso, la chiamata ti bloccherebbe nuovamente, quindi non resta che usare un
sistema di callback).
Ovvero:
(1) crei un progetto activex-exe (che chiameremo xxNetSnd)
(2) all'interno del progetto crei una classe - diciamo "NetSnd" - con
Instancing = 5
(3) all'interno del progetto crei un modulo bas - diciamo "modNetSnd"
(4) la classe conterrà il seguente codice:
[code start]
Option Explicit
Public Event SendComplete(ByVal Id As Long)
Public Event SendError(ByVal Id As Long, ByVal Number, ByVal Description,
ByVal Source)
Private m_Timer As Long
Private m_Id As Long
Private m_Parm1 As String
Private m_Parm2 As String
'Questa è la funzione che verrà chiamata dal client. Ovviamente i parametri
sono dummies: dovrai mettere
'quelli che tiservono e creare variabili appropriate per memorizzarli.
'La funzione ritorna un id (0 = errore) che potrai usare per riconoscere la
singola istanza se ne creerai più di una.
Public Function Send(Parm1 As String, Parm2 As String) As Long
   On Error GoTo ErrHndl
   m_Parm1 = Parm1
   m_Parm2 = Parm2
   '....
   'Qui imposti un timer di 500ms che eseguirà la funzione TimerProc nel
modulo bas descritto sotto
   m_Timer = SetTimer(0, 0, 500, AddressOf TimerProc)
   m_Id = GetTickCount()
   Set p_Class = Me
   Send = m_Id
   Exit Function
ErrHndl:
   Send = 0
End Function
Friend Sub SendExec()
   On Error GoTo ErrHndl
    'distruggi il timer prima che ti chiami nuovamente!
   KillTimer 0, m_Timer
    'Fai la cosa giusta!
'?  If netSend(m_Parm1, m_Parm2) Then
'?      Err.Raise 20000, , "Errore di netsend."
'?  End If
    'P.es. una msgbox è bloccante
   MsgBox "Pippo!"
    'Genera l'evento SendComplete nel client
   RaiseEvent SendComplete(m_Id)
   Exit Sub
ErrHndl:
    'In caso di errore, genera l'evento SendError nel client
   RaiseEvent SendError(m_Id, Err.Number, Err.Description, Err.Source)
End Sub
Private Sub Class_Terminate()
   Set p_Class = Nothing
   If m_Timer Then
      KillTimer 0, m_Timer
      m_Timer = 0
   End If
End Sub
[code end]
(5) il modulo bas conterrà il seguente codice:
[code start]
Option Explicit
Public Declare Function GetTickCount Lib "kernel32" () As Long
Public Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal
nIDEvent As Long) As Long
Public Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal
nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Public p_Class As NetSnd
'Questa è la callback del timer.
Public Sub TimerProc(hWnd As Long, uMsg As Long, idEvent As Long, dwTime As
Long)
   p_Class.SendExec
End Sub
[code end]
La logica è la seguente:
- il client crea un'istanza di xxNetSnd.NetSnd e chiama la di questa
funzione Send.
- la funzione Send memorizza i parametri in variabili locali alla classe,
imposta un puntatore globale alla classe stessa, crea un timer con timeout
di 500ms e crea un id (numero casuale basato sul clock). Quindi torna il
controllo al chiamante. Da questo momento il chiamante è svincolato da
xxNetSnd.
- trascorso il timeout, Win genera una chiamata alla funzione TimerProc, che
a sua volta chiama la funzione SendExec della nostra classe (tramite il
puntatore)
- la funzione SendExec svolge il lavoro (bloccante) previsto e, se tutto OK,
genera l'evento SendComplete che il client può intercettare. Se la routine
va in errore, viene invece generato l'evento SendError.
Per provare questo programma puoi creare un prg client in questo modo:
(1) compili l'exe de server
(2) crei un nuovo progetto vb exe standard
(3) nei riferimenti del progetto inserisci xxNetSnd
(4) crei un form con un pulsante Command1
(5) Inserisci nel modulo del form il seguente codice:
[code start]
Option Explicit
Private WithEvents Sender As xxNetSnd.NetSnd
Private Sub Command1_Click()
   Set Sender = New xxNetSnd.NetSnd
   Sender.Send "Parm1", "Parm2"
   MsgBox "Sender è stato avvviato."
End Sub
Private Sub Sender_SendComplete(ByVal Id As Long)
   MsgBox "Sender #" & Id & " ha completato."
End Sub
Private Sub Sender_SendError(ByVal Id As Long, ByVal Number As Variant,
ByVal Description As Variant, ByVal Source As Variant)
   MsgBox "Errore " & Number & " di Sender."
End Sub
[code end]
Come vedi non è semplicissimo, ma l'alternativa (in vb6 - ovviamente dotnet
è multithread) è creare un thread, cosa veramente insicura in vb. D'altra
parte, questa tecnica è riciclabile per altri casi.
--
rumplestiltskin

eh meno male che avevi detto "alla buona" :-)
grazie 1000 x il tempo che mi hai dedicato, questa sera farò una prova
spero di non deluderti :-)
rumplestiltskin ha scritto:


 però non ci metterei la mano sul fuoco :-)
Dai anche un'occhiata alle regole di quoting ...
comunque ...
i nomi delle macchine li puoi prelevare con comandi NET (o con le relative
API) ma solo perchè è un'operazione già praticata a livello di connessione
(cioè ancora più basso del protocollo) ... e identificano una macchina in
una rete con una stringa al posto del suo indirizzo numerico.
Il nome utente invece rappresentano l'identificativo dell'utilizzatore di
sessione sulla macchina specifica. Questo poco importa ai fini della rete
(se non che hai Active Directory  che concede privilegi anche agli users) in
quanto è il computer che si mette a disposizione nella rete e non l'utente.
Detto questo .. a cosa ti serve il nome utente ? .. mi dirai che serve per
verificare quale user sta accedendo e con quale macchina al tuo applicativo
.. se però consideri che possono esistere più utenti uguali (User + Pwd)
connessi con macchine diverse ecco che l'utilità effettiva del nome utente
in una rete non ha grande senso.
Comunque se tu riuscissi ad installare un prog host che dialoga con il tuo
(anche tramite winsock) sulle macchine remote avresti già la possibilità, a
livello di applicativo, di scambiare dati tra tutte le macchine, senza
perciò usare comandi NET.
Saluti

ciao fox
niente, mi serviva xchč ho fatto un programma netsend
e quei fetentoni dei miei colleghi sono cosě pigri da non sapere il nome 
delle macchine degli altri colleghi e mi hanno chiesto se si poteva 
avere il nome degli utenti
effettivamente sarebbe stata + simpatica come cosa :-)
perň se devo installare delle cose sul server non mi va + bene, xchč cmq 
volevo fare un programma indipendente, funzionante x tutti
quindi lascio perdere e lascio i nomi dei pc :-)
grazie di tutto!
ciaociao