# Lavorare celle DDE rispetto al variare del loro valore



## giamoros (Jul 15, 2011)

Mi sono fato un migliaio di giri su vari siti e sono arrivato alla conclusione che l'unico sistema per intercettare *automaticamente* se una cella DDE sia cambiata è usare il sistema *setlinkondata* (per me emerito sconosciuto). 
Comunque ho preparato qualcosa per verificare se ciò sia possibile ma ho subito un errore che non riesco a capire. 
Nello screenshot14 come si presente la cartella Excel quando la lancio. http://www.mediafire.com/?ipmtprciui954qi 
Nello screenshot15 l'errore che ho all'inizio dell'arrivo degli stessi. http://www.mediafire.com/?hlhkzz4ewftgg1z 
Nello screenshot16 le istruzioni del foglio2 sezione generale. http://www.mediafire.com/?vm28e13forxxj97 
Nello screenshot17 le istruzioni della sezione worksheet. http://www.mediafire.com/?wou8esw44o2ojbl 
Qualcuno sa darmi una mano a correggere tale errore?]


----------



## giamoros (Jul 20, 2011)

Come si fa a chiudere questo topic.
Grazie e saluti.


----------



## Greg Truby (Jul 20, 2011)

Sei riuscito a trovare una risposta alla tua domanda? E se sì, dove hai trovato la risposta?


----------



## giamoros (Jul 21, 2011)

Sto preparando un resoconto delle mie esperienze e quando sarà pronto te lo posterò sperando di farti cosa gradita.
In caso contrario farmelo sapere.
Saluti.


----------



## giamoros (Jul 21, 2011)

Nell’accingermi a raccontare le mie esperienze con il DDE mi sento in dovere prima di tutto di ringraziare coloro che, in egual misura, con il loro costante aiuto, suggerimenti, spiegazioni e sopratutto con la loro infinita pazienza mi hanno permesso di risolvere il mio problema.

  Mi riferisco agli utenti:

  Antony47        del forum pc-facile.com
  Scossa             del forum archi.forumup.it
  Icecube           del forum finanzaonline.com
  Paolo1956      del forum finanzaonline.com

*Alcune considerazioni sul DDE :*

  1°        so perfettamente che la tecnica del DDE è antiquata ma questa ho e questa devo usare
  2°        non è adatto a gestire grandi moli di dati specialmente in relazione al real time (millesimo di secondi) 
  3°        non vuole assolutamente sostituirsi agli strumenti professionali delle banche, Sim ecc. ecc
  4°        pur tuttavia fa onestamente il proprio lavoro.

*Come funziona il mio DDE :*

  1°        sul sito della banca viene attivata la funziona DDE
  2°        sul PC utente viene lanciato un programma generalmente fornito dalla stessa banca 
  3°        i due programmi si sincronizzano e nella barra del PC utente l’icona diventa verde
  4°        si lancia la cartella Excel utente e nelle celle dove ci sono le formule DDE arrivano i dati.

              Cosa sono , come sono fatte e dove vanno messe le formule DDE :

  Ogni fornitore di dati usa propri parametri per indicare nelle formule quali dati l’utente            vuole ma sostanzialmente alla fine sono moto simili fra di loro.

  Nel mio caso la formula è 





> FDF|Q!'ASR.MI;2'


dove 

              FDF|Q! è l’identificativo delle mia banca
              'FNC.MI; è il codice del titolo usato dalla banca in questo caso sigla di Finmeccanica
              2' indica il dato che si vuole in questo caso l’ultimo prezzo

              Quindi per ottenere tale dato dovremmo immettere in una cella Excel la formula :
                          = FDF|Q!'FNC.MI;2'

  Per ottenere il Last Time dello stesso titolo la formula da mettere in un’altra cella sarà : 
  =FDF|Q!'FNC.MI;14'  

  e così per altri dati quali open, volume, percent change, bid, ask ecc.ecc 

  Le formule possono essere messe in qualsiasi cella di qualunque foglio della cartella.
  Va tenuto presente comunque che per ogni formula e quindi per ogni titolo viene aperto un
     canale DDE il che significa che se ci sono 8 formule in un foglio, 12 in un altro e 7 in un terzo anche se ridondanti fra di loro ed i titoli sono 10 si avranno un totale di 
              8 * 12* 7 * 10 = 6720 canali
     quindi è giocoforza diminuire drasticamente il loro numero.
  Nel mio caso, cartella con 6 fogli, quello per me primario era formato da 11 righe ,una per titolo che voglio ottenere, così composta :

     sigla titolo, denominazione, prezzo, last time ed altre colonne e quindi 4 formule per riga.

  Inoltre in ordine diverso le stesse formule per gli stessi dati esistevano anche negli altri 5 fogli.

  Allora cosa ho fatto:

              1° sostituite le formule della sigla titolo e denominazione con delle costanti
                         in quanto so perfettamente che se chiedo il prezzo della sigla FNC.MI si tratta                        del titolo con denominazione FINMECCANICA. 

              2° le formule rimaste ridondanti degli altri fogli le ho sostituite con la funzione
                         Excel ” =nomefoglio!J8”  dove J8 è la coordinata della cella dove è stata                         immessa la formula appropriata.

  Come senz’altro, ai più noto, per visualizzare il codice VBA cliccando il tasto destro del    mouse sul nome delle linguette dei fogli si apre una finestra che fra le altre ha anche           la scelta “VISUALIZZA CODICE” evidenziando il quale e cliccando con il destro si         ottiene il codice VBA.

  A questo punto scegliendo in alto “VISUALIZZA” si apre una finestra e scegliendo la riga riportante “GESTIONE PROGETTI” si ha sulla destra una sezione così composta :

  VbaProject (nome della mia cartella)  

     Microsoft Excel Oggetti 
          Foglio1 (Formule)                    fra parentesi il nome che ho dato al foglio1 
          Foglio2 (Ordinario)                 fra parentesi il nome che ho dato al foglio2
            ……
            ……        
           fino al Foglio6 (Movimenti azioni)       fra parentesi il nome che ho dato al foglio6
         ThisWorkbook 
     Form 
          Userform1 
          Userform2 
     Moduli 
          Moduli1 
          Moduli2 
          ..... e così riga per riga fino alla fine 
     Moduli di classe 
          Classe1 
          Classe2 
          Classe3

  Alcune considerazioni su questa struttura :

              1° Nei fogli, si consiglia da più parte, di mettere solo gli eventi Excel quali:
                          Worksheet_SelectionChange(ByVal Target As Range)
Worksheet_Calculate
  <code></code><code>........ e cosi via dicendo</code>
  <code>            </code>
  2° Nei moduli, si consiglia da più parti, vanno messe le routine public.

  3° Alcuni chiamano i moduli anche con il nome Standard quindi quando vi suggeriscono di       mettere delle istruzioni fatevi spiegare esattamente dove e perché.

  4° Tenete presente che per visualizzare il codice di un Foglio o ThisWorkbook o di un          modulo o form o Classe dovete evidenziare cioè che volete quindi tasto destro e       poi       visualizza codice. 

  E finalmente passiamo ad commentare tutti i passi fatti.

*1°  ho inserito in ThisWorkbook il codice*


```
Private Sub Workbook_Open()
                 Call LinkList
                 End Sub
```
                          All’apertura della cartella queste istruzioni sono eseguite per prime e passano il      controllo alla routine, di nome a piacere, LinkList 

*2° ho inserito nel Modulo1 la routine pubblica Linklist*


```
Public Sub LinkList()
                 ActiveWorkbook.SetLinkOnData "FDF|Q!'ASR.MI;2'", "Macro1"
                 ActiveWorkbook.SetLinkOnData "FDF|Q!'C40.PAR;2'", "Macro2"
                 ActiveWorkbook.SetLinkOnData "FDF|Q!'BP.MI;2'", "Macro3"
                 ActiveWorkbook.SetLinkOnData "FDF|Q!'BNG.MI;2'", "Macro4"
                 ActiveWorkbook.SetLinkOnData "FDF|Q!'CED.MI;2'", "Macro5"
                 ActiveWorkbook.SetLinkOnData "FDF|Q!'ENEL.MI;2'", "Macro6"
                 ActiveWorkbook.SetLinkOnData "FDF|Q!'EGPW_C.MI;2'", "Macro7"
                 ActiveWorkbook.SetLinkOnData "FDF|Q!'ENG.MI;2'", "Macro8"
                 ActiveWorkbook.SetLinkOnData "FDF|Q!'FNC.MI;2'", "Macro9"
                 ActiveWorkbook.SetLinkOnData "FDF|Q!'IRE.MI;2'", "Macro10"
                 ActiveWorkbook.SetLinkOnData "FDF|Q!'UCG.MI;2'", "Macro11"
                 End Sub
```
                 Perché ho scartato l’esempio di seguito esposto fornito dai più Microsoft compresa?


```
Public Sub LinkList()
                 Dim Links As Variant
                 ' Obtain an array for the links to Excel workbooks
                 ' in the active workbook.
                 Links = ActiveWorkbook.LinkSources(xlOLELinks)
                 ' If the Links array is not empty, then open each
                 ' linked workbook. If the array is empty, then
                 ' display an error message.
                 If Not IsEmpty(Links) Then
                 For i = 1 To UBound(Links)
                 ActiveWorkbook.SetLinkOnData Links(i), "LinkChange"
                 Next i
                 Else
                 MsgBox "This workbook does not contain any links " & _
                 "to other workbooks"
                 End If
                 End Sub
```
                 A – Il sistema delle 11 macro mi permette di avere immediatamente l’indicazione della            riga in cui il prezzo è variato.
                          Notare che se anche manca il DDE time o di altri dati gli stessi arriveranno nelle             celle dei fogli in cui sono immesse le relative formule.
                          In definitiva non è tanto importante avere tanti SetLinkOnData ma solo uno per          titolo; la scelta dipende dall’architettura del vostro progetto.

                 B - Il sistema dell’unico SetLinkOnData ha lo svantaggio che poi costringe a          programmare dei controlli ( loop od on timer) per individuare quale cella è variata         anche in considerazione del fatto che gli eventi :

                                     <!--[if gte mso 9]><xml>  <w:WordDocument>   <w:View>Normal</w:View>   <w:Zoom>0</w:Zoom>   <w:HyphenationZone>14</w:HyphenationZone>   <w:Compatibility>    <w:BreakWrappedTables/>    <w:SnapToGridInCell/>    <w:WrapTextWithPunct/>    <w:UseAsianBreakRules/>   </w:Compatibility>   <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>  </w:WordDocument> </xml><![endif]--><!--[if gte mso 10]> <style>  /* Style Definitions */  table.MsoNormalTable     {mso-style-name:"Tabella normale";     mso-tstyle-rowband-size:0;     mso-tstyle-colband-size:0;     mso-style-noshow:yes;     mso-style-parent:"";     mso-padding-alt:0cm 5.4pt 0cm 5.4pt;     mso-para-margin:0cm;     mso-para-margin-bottom:.0001pt;     mso-pagination:widow-orphan;     font-size:10.0pt;     font-family:"Times New Roman";} </style> <![endif]-->  Worksheet_SelectionChange(ByVal Target As Range)
Worksheet_Calculate
non scattano per effetto del variare di una cella DDE (parola di Microsoft)

  <code></code><code></code>*3° ho inserito nel Modulo2  le tredici macroN*


```
Public Sub Macro1()
                 nriga = 8
                 Call LinkChange(nriga)
                 End Sub
                 Public Sub Macro2()
                 nriga = 9
                 Call LinkChange(nriga)
                 End Sub
                 Public Sub Macro3()
                 nriga = 10
                 Call LinkChange(nriga)
                 End Sub
                 Public Sub Macro4()
                 nriga = 11
                 Call LinkChange(nriga)
                 End Sub
                 Public Sub Macro5()
                 nriga = 12
                 Call LinkChange(nriga)
                 End Sub
                 Public Sub Macro6()
                 nriga = 13
                 Call LinkChange(nriga)
                 End Sub
                 Public Sub Macro7()
                 nriga = 14
                 Call LinkChange(nriga)
                 End Sub
                 Public Sub Macro8()
                 nriga = 15
                 Call LinkChange(nriga)
                 End Sub
                 Public Sub Macro9()
                 nriga = 16
                 Call LinkChange(nriga)
                 End Sub
                 Public Sub Macro10()
                 nriga = 17
                 Call LinkChange(nriga)
                 End Sub
                 Public Sub Macro11()
                 nriga = 18
                 Call LinkChange(nriga)
                 End Sub
```
  Qui si capisce perché la scelta è caduta sul metodo A in quanto ogni macro imposta la riga del 
  proprio titolo e chiama la routine LinkChange (anche essa nome a piacere)

*4° ho inserito la routine LinkChange nel Modulo2 ma potrebbe andare in qualunque altro modulo :*


```
Public Sub LinkChange(priga)
   
                  If IsError(Range("J" & priga).Value) Then GoTo finejob
                  If IsError(Range("N" & priga).Value) Then GoTo finejob
      
                  If Range("J" & priga) > Range("Q" & priga).Value Then
                           Range("J" & priga).Interior.ColorIndex = 4
                           lSuono = 10
      Else
                  If Range("J" & priga) < Range("Q" & priga).Value Then
                           Range("J" & priga).Interior.ColorIndex = 3
                          lSuono = 11
                           End If
      End If
                  Range("J" & priga).Select
                 
                 Range("Q" & priga).Value = Range("J" & priga).Value
                 Range("R" & priga).Value = Range("N" & priga).Value
                 
                 GeneraSuono lSuono
              
  finejob:
  End Sub
```
  Considerazioni e spiegazioni:

                 1° Quando si passa una variabile ad una routine non è che si passa la variabile ma il suo   contenuto quindi la Call LinkChange(nriga) passa il valore della sua variabile nriga.
                          La Public Sub LinkChange(priga) prende quel valore e lo mette nella sua variabile      priga.

                 2° (Range("J" & priga).Value) significa considerare il valore della cella Jx dove x sarà il          numero della riga passato da una delle 11 macro cioè da  J8 fino a J18.

                 3° IsError è necessaria perché se una cella DDE non viene calcolata, se non arriva il          relativo dato ad esempio il titolo entra in contrattazione ad orario successivo ad altri         titoli oppure è sospeso per l’intera giornata, all’apertura della cartella Excel calcola la       formula come errore ma pur tenendone conto lascia la visualizzazione precedente.
                          Di conseguenza qualsiasi istruzione con quella cella dà l’errore 13 Tipo non          corrispondente.
                          Con tale istruzione quindi si bypassano le celle che darebbero l’errore perché la      colonna J contiene i prezzi mentre la colonna N contiene il last time dell’ultimo           prezzo.
                          Infatti da J8 a J18 ci sono le formule DDE per chiedere il prezzo mentre da N8 a       N18     ci sono le formule DDE per ottenere il last time.

                 4° Per capire se l’ultimo prezzo arrivato è maggiore o minore al precedente occorre avere            delle aree che i più chiamano “ombra” io direi di salvataggio o d’appoggio.
                          Tale aree possono stare anche su altri fogli e possono essere dichiarati invisibile ecc.          ecc.
                          Nel mio caso sono state individuate nello stesso foglio rispettivamente nelle colonne        Q ed R e nelle stesse righe da 8 a 18 ma potevono stare se celle libere anche nelle   colonne J ed N alla righe 1289 ecc. ecc. adattando opportunamente le relative        posizioni nelle istruzioni. 
                          Supponendo che la riga in questione sia  la 13° il primo if dice se il valore di J13 è            maggiore del precedente salvato in Q13 allora colora la cella J13 di verde ed imposta     il suono numero 10.
                          Il secondo if analogamente se minore colora la cella J13 di rosso ed imposta il suono           numero 11.

                 5° Comunque la cella viene evidenziata e si procede a salvare i valori della cella J13 ed          N13 rispettivamente in Q13 ed R13 per il controllo del prossimo arrivo.          
                          Quindi si procede alla generazione del suono.

*5° ho inserito in testa al Modulo2 queste tre righe perché dichiarazione private* 


```
Private Declare Function sndPlaySound Lib "WINMM.DLL" Alias "sndPlaySoundA" (ByVal lpszSoundName As String, ByVal uFlags As Long) As Long
                 Const SND_ASYNC = &H1
```
 *6° ho inserito nel Modulo2 la routine GeneraSuono* 


```
Public Sub GeneraSuono(ByVal TipoSuono As Long)
   
                 Dim P As Long, SoundName As String
   
                          Select Case TipoSuono
                                     Case 1
                                     SoundName = "c:\windows\media\Chimes.wav"
                                     Case 2
                                     SoundName = "c:\windows\media\Chord.wav"
                                     Case 3
                                     SoundName = "c:\windows\media\Ding.wav"
                                     Case 4
                                     SoundName = "c:\windows\media\Notify.wav"
                                     Case 5
                                     SoundName = "c:\windows\media\Recycle.wav"
                                     Case 6
                                     SoundName = "c:\windows\media\Ringing.wav"
                                     Case 7
                                     SoundName = "c:\windows\media\Ringout.wav"
                                     Case 8
                                     SoundName = "c:\windows\media\Start.wav"
                                     Case 9
                                     SoundName = "c:\windows\media\Tada.wav"
                                     Case 10
                                     SoundName = "c:\Programmi\MemoRex\Suoni\Fanfare.wav"
                                     Case 11
                                     SoundName = "c:\Programmi\MemoRex\Suoni\Allarme.wav"
                          Case Else
                 'Beep
                 Exit Sub
                 End Select
   
                 P = sndPlaySound(SoundName, SND_ASYNC)
   
                 End Sub
```
  Tenere presente che le precedenti due fasi (5° e 6°) devono risiedere sullo stesso modulo.

*7° Esiste nel Modulo3 la seguente routine da me ancora non usata ne provata :*


```
Public Sub AnnullaLinkList()
                 Dim Links As Variant
                 Links = ActiveWorkbook.LinkSources(xlOLELinks)
                 If Not IsEmpty(Links) Then
                 For i = 1 To UBound(Links)
                 ActiveWorkbook.SetLinkOnData Links(i), ""
                 Next i
                 End If
                 End Sub
```
                 che se attivata chiude tutti i canali DDE aperti tramite quei doppi apici nell’istruzione ActiveWorkbook.SetLinkOnData Links(i), "" 

  Credo che ho detto tutto , che sia stato chiaro e spero che possa essere di aiuto a qualcuno.


----------



## galici (May 15, 2012)

Non mi è chiaro perchè deve essere necessario fare tutto quello che viene descritto.
Se il problema è non duplicare i canali DDE, non basta concentrali in un
unico foglio e negli altri fare riferimento a quell'unico foglio?

In altre parole:
mi serve avere =FDF|Q!'FNC.MI;14'  in 10 fogli diversi.
Basta farsi un foglio che chiamerò DATIFDF dove metto nella cella C4 (esempio) =FDF|Q!'FNC.MI;14' 

Poi nei dieci fogli in cui ho bisogno del valore 14 del titolo FNC basta fare
=DATIFDF!C4

Io ho fatto in questa maniera. Ho però letto attentamente i suggerimenti dati pensando che venisse spiegato qualche trucco per ottenere qualcosa di più, ma a me sembra che si ottenga lo stesso risultato. O c'è qualcosa che mi sfugge?

Per esempio a me farebbe comodo poter ricevere i dati non tramite una cella, ma tramite codice Visual Basic. Cioè ho un codice che avrebbe bisogno del valore 14 del titolo FNC, 
deve per forza leggerlo dalla cella corrispondente nel foglio Excel o può andare a farselo dare direttamente da FDF tramite DDE?

Se capisco bene in questo Thread non viene detto nulla a riguardo.  
Qualcuno è a conoscenza di un altro Thead che spiega quanto sopra?
Grazie


----------



## giamoros (May 15, 2012)

Per galici:
ma è quello che ho già scritto:

""Allora cosa ho fatto:

              1° sostituite le formule della sigla titolo e denominazione con delle costanti
                         in quanto so perfettamente che se chiedo il  prezzo della sigla FNC.MI si tratta                        del titolo  con denominazione FINMECCANICA. 

2° le formule rimaste ridondanti degli altri fogli le ho sostituite con la funzione
                         Excel ” =nomefoglio!J8”  dove J8 è la  coordinata della cella dove è stata                         immessa la  formula appropriata.

Per il resto che io sappia la formula deve stare nella cella.


----------



## galici (May 16, 2012)

Non capisco però a cosa servano le SetLinkOnData.

Faccio la domanda in altro modo.
Se uno parte col piede giusto, nel fare un nuovo foglio da zero, non
ha bisogno delle SetLinkOnData e di scrivere macro.
Scrive direttamente le formule DDE in un singolo foglio e poi fa riferimento
a quel foglio. Tutto senza nessun SelectLinkOnData.

Faccio queste domande, non per criticare, ma perchè per un foglio che
stavo scrivendo adesso mi sono trovato a litigare con la SetLinkOnData e per questo mi sono messo a navigare cercando qualcuno che l'avesse già usata.

Ti spiego adesso quale è il problema che mi ha portato ad interessarmi di questo thread.

Il problema che ho io con la SetLinkOnData e che funziona *solo* con link che sono *già* presenti in *LinkSources. *Se un link non è già presente in
LinkSources non si può usarlo in SetLinkOnData.
Quello che cercavo di fare io (senza successo) era di *aggiungere un nuovo **link* senza digitare la formula, ma appunto con un programma VBA.
Mi ha incuriosito il tuo messaggio, perchè tu citi la *LinkSources* solo quando citi spezzoni di codice, consigliati da altri, che tu *NON* hai usato. Immagino però che da qualche altra parte hai inserito una LinkSources.
A meno che semplicemente *sai* quali sono i link già presenti nel tuo foglio e usi quelli, associati al SetLinkOnData. Ma in questo caso il tuo codice VBA funziona solo sul tuo foglio.


----------



## giamoros (May 16, 2012)

Se leggi tutta la spiegazione troverai anche :

Public Sub LinkList()                  Dim Links As Variant                  ' Obtain an array for the links to Excel workbooks                  ' in the active workbook.                  Links = ActiveWorkbook.*LinkSources*(xlOLELinks)                  ' If the Links array is not empty, then open each                  ' linked workbook. If the array is empty, then                  ' display an error message.                  If Not IsEmpty(Links) Then                  For i = 1 To UBound(Links)                  ActiveWorkbook.SetLinkOnData Links(i), "LinkChange"                  Next i                  Else                  MsgBox "This workbook does not contain any links " & _                  "to other workbooks"                  End If                  End Sub</pre>altro non so dirti.


----------

