Newsgroup: it.comp.lang.c++
Titolo: RegOpenKeyEx

 Potreste mica darmi un esempio di come funziona quest'API? In particolare
ho dei problemi non indifferenti con l'ultimo parametro.
(Se potete fatemi l'esempio con
System\CurrentControlSet\Services\RemoteAccess)
Grazie
Francesco Mapelli ( 
mape...@tin.it
 )
http://members.xoom.com/Francesco
Mousestats, il contachilometri per il mouse
http://members.xoom.com/mousestats
Sito comune programmatori Visual Basic
http://members.xoom.com/it_lang_vb

TCHAR	tszKey[] = _T("System\\CurrentControlSet\\Services\\RemoteAccess");
HKEY	hKey;
RegOpenKeyEx(	
		HKEY_LOCAL_MACHINE,
		tszKey,
		0,
		KEY_ALL_ACCESS,
		&hKey
		);
Il primo parametro è una delle costanti che identificano gli handle delle
sei chiavi principali del registro (mi pare che la chiave che indichi si
trovi sotto HKEY_LOCAL_MACHINE).
Il secondo parametro punta una stringa contenente il nome (con percorso)
della chiave da aprire.
Il terzo parametro è riservato.
Nel quarto parametro indichi i diritti di accesso che ti vuoi riservare.
Infine il quinto e ultimo parametro è l'indirizzo (notare l'operatore &) di
una variabile di tipo HKEY che, dopo il ritorno della funzione, conterrà un
handle che identifica la chive aperta (ammesso che la funzione non
fallisca); questo handle dovrà essere passato ad eventuali successive
funzioni operanti sulla chiave aperta: ad esempio l'apertura di una
sottochiave, l'inserimento, la modifica o la lettura di un valore,
l'enumerazione delle sottochiavi, ecc. Vediamo qualche esempio pratico:
Apertura della sottochiave 'CallAccess':
HKEY hKey1;
RegOpenKeyEx(
		hKey,
		_T("CallAccess"),
		0,
		KEY_ALL_ACCESS,
		&hKey1
		);
Dato che, dopo la prima chiamata, la chiave da te indicata è aperta, e
'CallAccess' ne è una sottochiave, sarà sufficiente passare come primo
parametro l'handle della chiave aperta e come secondo parametro la stringa
'CallAccess'; dopo il ritorno, hKey1 conterrà l'handle alla chiave appena
aperta.
Lettura dei dati contenuti nel valore 'Remote Connection':
DWORD dwDim;
BYTE  *pb;
RegQueryValueEx(
		hKey,
		_T("Remote Connection"),
		NULL,
		REG_BINARY,
		NULL,
		&dwDim
		);
pb = ...allocare un numero di bytes specificato da dwDim
RegQueryValueEx(
		hKey,
		_T("Remote Connection"),
		NULL,
		REG_BINARY,
		pb,
		&dwDim
		);
Con la prima chiamata si ottengono le dimensioni dei dati; poi si alloca
memoria sufficiente per contenerli e con la seconda chiamata li si leggono
effettivamente. Se le dimensioni dei dati sono già note è sufficiente una
sola chiamata con buffer già allocato e dwDim impostato sulla dimensione
del buffer. Consulta la documentazione per tipi di dati diversi da
REG_BINARY.
Modificare il valore di 'Remote Connection':
BYTE b[8] = { 255, 255, 255, 255, 255, 255, 255, 255 };
RegSetValueEx(
		hKey,
		_T("Remote Connection"),
		NULL,
		REG_BINARY,
		(BYTE *)b,
		8
		);
Beh, questa non ricordo di averla mai provata, ma è così che dovrebbe
funzionare. Questa funzione, così com'è scritta, ha una doppia funzione:
nel nostro caso si limita ad impostare i dati del valore, ma se il valore
non fosse stato presente nella sottochiave, lo avrebbe aggiunto; quindi,
attento a quello che scrivi.
Stefano.

pb = ...allocare un numero di bytes specificato da dwDim
[...]
hem... non vorrei sembrare ignorante (beh... lo sono...) ma come si fa? io
vengo dal vb in cui bastava usare len(dwDim) e era tutto finito... solo che
qui non va...
grazie, il resto funziona alla perfezione!


hem... non vorrei sembrare ignorante (beh... lo sono...) ma come si fa? io
Non ho seguito l'inizio della discussione, comunque, in C++,
per "allocare un numero di bytes specificati", hai vari modi;
supponiamo ad esempio che pb sia un "char *", per cui quel
che vuoi allocare sono appunto dei char, i piu` tipici sono:
    pb = new char[dwDim];                      // 1
    pb = reinterpret_cast<char*>(malloc(dwDim));    // 2
Il caso 1 e` il modo standard C++; tanti usano ancora
il modo 2 per mantenere compatibilita` con C, o piu`
probabilmente perche` non si sono ancora abituati a
fare le cose "alla C++" (e` il "difetto" di venire al C++
dal C... e anche il pregio... le cose all'antica continuano
a funzionare!).
Su Windows, inoltre, possono servire: CoTaskMemAlloc,
altre implementazioni dell'interfaccia com IMalloc, la
HeapAlloc, per stringhe di tipo VB la SysAllocString ecc,
_alloca() [l'unica che non richiede esplicita deallocazione,
poiche` usa invece lo stack come auto] e tante altre ancora.
Alcuni, inoltre, non hanno ancora imparato a usare il
reinterpret_cast<> (benche` sia da anni nei draft dello
standard, e in particolare da 1 anno e + in quello finale
divenuto Standard Internazionale quest'estate), e quindi
usano altri costrutti (deprecati dallo standard), come
    pb = (char*)malloc(dwDim);
E` cruciale usare, per liberare la memoria cosi` allocata,
lo schema giusto, corrispondente al modo di allocazione.
Nel caso 1, "delete[] pb;"; nel 2, "free(pb);"; e cosi` via,
CoTaskMemFree, HeapFree, ecc ecc, sempre secondo quel
che hai usato per allocare.  Come accennavo, _alloca non
ha un "modo corrispondente" di liberare la memoria: essa
si libera automaticamente uscendo dalla funzione, o dal
blocco, dove hai chiamato l'_alloca (questa memoria "vive"
in stack; e` quindi MOLTO piu` rapido allocarla, e c'e` la
comodita` di non doverla deallocare; il prezzo e` che non
puo` sopravvivere al blocco allocante!); nota che il carattere
di '_' all'inizio suggerisce "funzione non standard", e infatti
lo standard non la prevede, ma una qualche versione di alloca
la trovi un po' dappertutto (anche in C, spesso!).
Il metodo 2, come tanti degli altri, segnala eventuali errori
_col suo stesso valore di ritorno_: DEVI verificare se il pb
rimane nullo dopo il tentativo di "allocare", se si`, significa
che manca memoria.  Di solito i programmatori si scordano
di controllare, e i programmi piu` vari, in condizioni di
scarsita` di memoria, terminano con errori strani invece
di dare una chiara diagnosi del problema e salvare almeno
quanto fatto sino a quel punto.
Il metodo 1, se "torna" normalmente, tornera` sempre un
risultato valido; in caso di errore, _solleva un'eccezione_
(questo e` quanto specifica lo standard; molti compilatori,
presumibilmente per compatibilita` con il Cretaceo, hanno
un modo di operare "standard", e un altro invece che non
rispetta questa specifica -- verifica quale opzione nel tuo
compilatore garantisce il comportamento standard!).
Venendo dal VB, dovresti essere ragionevolmente a tuo
agio con il concetto di eccezione: un errore interrompe il
normale flusso di esecuzione del codice e deve venire
gestito esplicitamente (beh, in VB puoi specificare
"On Error Resume Next" e perdere questo obbligo di
controllo, ma, non e` bello farlo!-).  Le eccezioni C++
sono piu` potenti perche` puoi gestirle, non solo nella
funzione dove si verificano, ma a qualsiasi livello
"superiore" (il chiamante di essa, o il chiamante del
chiamante, ecc ecc, su su fino al programma principale);
"risalendo" da chiamato a chiamante, finche` non si
trova un gestore per la specifica eccezione successa --
tutti i livelli intermedi, privi di gestori, sono terminati
automaticamente (vengono eseguiti i distruttori delle
variabili locali dei blocchi via via terminati).  La gestione
e` selettiva, cioe` la clausola "catch" del gestore puo`
specificare quale tipo di errore voglia gestire.
Purtroppo, il VC++, che mi pare avessi indicato che
usi, per default non segue lo standard in questa parte;
per ottenere una exception da una new fallita, bisogna
istallare un new_handler (meccanismo che, comunque,
ha anch'esso la sua utilita`, e lo standard infatti pure
prevede), e il "throw" dell'eccezione (equivalente al
"raise" di errore in VB) va fatto in questo handler.  In
alternativa, puoi, come sempre prevede il C++ standard,
ridefinire globalmente l'operator new e operator delete,
per avere il dettagliato comportamento che preferisci.
Sospetto che, come principiante, preferirai non entrare
in problematiche di questo tipo, per ora!
Degli altri metodi di allocazione, quelli che possono
essere soggetti a diagnosi d'errore via eccezione sono
quelli legati a COM; per default, e per compatibilita`
con C, tutte le funzioni e i metodi COM segnalano il
successo o fallimento tornando un HRESULT che puo`
(deve!) essere testato con le macro FAILED() e/o
SUCCEEDED(); ma VC++ permette di "avvolgere"
i puntatori a interfaccia COM in "puntatori furbi", che,
oltre a varie altre comodita`, trasformano gli errori
in eccezioni (di tipo _com_error), togliendo al codice
"cliente" la necessita` di testare ad ogni passo se le
cose siano riuscite o meno.
Alex