È possibile modificare la HANDLE che è stata aperta per l'I/O sincrono in modo che venga aperta per l'I/O asincrono durante la sua vita?

StackOverflow https://stackoverflow.com/questions/2475713

Domanda

La maggior parte del mio lavoro quotidiano di programmazione in Windows riguarda oggigiorno operazioni di I/O di tutti i tipi (pipe, console, file, socket, ...).Sono ben consapevole dei diversi metodi di lettura e scrittura da/su diversi tipi di handle (attesa sincrona e asincrona per il completamento degli eventi, attesa sugli HANDLE di file, porte di completamento I/O e I/O avvisabile).Ne usiamo molti.

Per alcune nostre applicazioni sarebbe molto utile avere un solo modo di trattare tutte le maniglie.Voglio dire, il programma potrebbe non sapere che tipo di handle ha ricevuto e vorremmo utilizzare, diciamo, porte di completamento I/O per tutti.

Quindi prima vorrei chiedere:

Supponiamo che io abbia un handle:

HANDLE h;

che è stato ricevuto dal mio processo per I/O da qualche parte.Esiste un modo semplice e affidabile per scoprire con quali flag è stato creato?La bandiera principale in questione è FILE_FLAG_OVERLAPPED.

L'unico modo che conosco finora è provare a registrare tale handle nella porta di completamento I/O (utilizzando CreateIoCompletionPort()).Se ciò riesce, l'handle è stato creato con FILE_FLAG_OVERLAPPED.Ma in questo caso è necessario utilizzare solo la porta di completamento I/O, poiché non è possibile annullare la registrazione dell'handle senza chiudere il file HANDLE h si.

A condizione che esista un modo semplice per determinare la presenza di FILE_FLAG_OVERLAPPED, arriverebbe la mia seconda domanda:

Esiste un modo per aggiungere tale flag all'handle già esistente?Ciò renderebbe un handle originariamente aperto per le operazioni sincrone aperto per le operazioni asincrone.Ci sarebbe un modo per creare il contrario (rimuovere il file FILE_FLAG_OVERLAPPED creare un handle sincrono da asincrono)?

Non ho trovato alcun modo diretto dopo aver letto MSDN e aver cercato molto su Google.Ci sarebbe almeno qualche trucco che potrebbe fare lo stesso?Come ricreare la maniglia nello stesso modo utilizzando CreateFile() funzione o qualcosa di simile?Qualcosa di documentato anche in parte o di non documentato affatto?

Il luogo principale in cui ne avrei bisogno è determinare il modo (o modificare il modo) in cui il processo dovrebbe leggere/scrivere dagli handle inviati da applicazioni di terze parti.Non possiamo controllare il modo in cui i prodotti di terze parti creano i propri handle.

Cari guru di Windows:aiuto per favore!

Con saluti

Martino

È stato utile?

Soluzione 2

3 anni passati e Windows 8 è stato rilasciato. Grazie alla regressione introdotta in attuazione della console in Windows 8 ho avuto modo di fare qualcosa per il problema che ha scatenato questa domanda. Così ho finalmente provato ad usare ReOpenFile) chiamata di funzione (.

In una frase:. Per i miei scopi è inutile

Il ReOpenFile () API viene utilizzato per “prendere un handle di file esistente e ottenere un altro manico che ha un diverso insieme di diritti di accesso”. Almeno questo è sancito dal originale articolo .

Ho provato ad utilizzare The ReOpenFile () sulla maniglia ingresso Console:

  stdin_in = GetStdHandle(STD_INPUT_HANDLE);
  stdin_in_operlapped = ReOpenFile(stdin_in, GENERIC_READ | GENERIC_WRITE,
                                   FILE_SHARE_READ, FILE_FLAG_OVERLAPPED);
  if (stdin_in_operlapped ==  INVALID_HANDLE_VALUE)
    {
      my_debug("failed to ReOpen stdin handle with OVERLAPPED flag: %d", GetLastError());
      exit(1);
    }

E che cosa ottengo è: Errore 1168: “Elemento non trovato”. “Grazie di Microsoft”. Non voglio nemmeno provare a usarlo per tubi anonimi, dal momento che la documentazione afferma:

“asincroni (sovrapposti) lettura e scrittura non sono supportate da tubi anonimi. Questo significa che non è possibile utilizzare le funzioni ReadFileEx e WriteFileEx con tubi anonimi. Inoltre, il parametro lpOverlapped di ReadFile e WriteFile viene ignorato quando queste funzioni vengono utilizzate con tubi anonimi “.

voi, la gente, Grazie a tutti per i vostri suggerimenti. Durante la lettura da ansa modo asincrono, si deve essere pronti anche per il fatto che l'operazione possa completare sincrono. Questo lo so. Il motivo principale che è stato chiesto questa domanda è:

quando una lettura sincrona è stato rilasciato su alcuni oggetti (almeno anonimi tubi e console di input in Windows 8) quindi chiamando CloseHandle () da un altro thread sulla stessa maniglia sarà o non riuscire, o appendere, fino a quando il ReadFile () completa; questo significa che si bloccherà a tempo indeterminato, in molti casi. Questo è il motivo per cui ho voluto sostituire il manico sincrono con asincrono.

Ora è chiaro che non è semplicemente possibile in sistemi operativi Windows per annullare alcune operazioni di lettura in modo semplice. Quando si legge da maniglie sincroni, si deve solo per uscire dall'applicazione, anche se ReadFile () è ancora leggendo da un manico in qualche discussione, perché è semplicemente impossibile svegliarsi in modo affidabile un tale operazione di lettura. In sapere ... In più recente sistema operativo è possibile annullare l'operazione. Tuttavia, non v'è alcun modo di sapere tempo il thread è nella chiamata ReadFile () già, o non ancora. Se ReadFile () non è ancora chiamato allora non c'è alcuna operazione per annullare e la successiva lettura si bloccherà. L'unico modo sarebbe quello di chiudere la maniglia, ma tale operazione si blocca, o non su alcuni oggetti e in alcuni sistemi operativi. L'unica soluzione adeguata a questo è I / O asincrono. Ma, come ho detto all'inizio, la nostra APP viene avviato da applicazioni di terze parti e non possiamo costringerli tutto per creare sempre named pipe con sovrapposto flag set per la stdio.

sto dando e andando a implementare brutte hack brutto ... dovremo continuare a leggere senza struttura OVERLAPPED dalle maniglie che sono stati creati con la bandiera OVERLAPPED, e perde le maniglie e le discussioni ....

Altri suggerimenti

Vedo che ero un cattivo lettore di MSDN: / I funzione totalmente perso ReOpenFile() che è stato introdotto probabilmente già nel giugno 2003 a Windows Server 2003 (in base al questo articolo ). Per difendermi almeno un po ': mi aspetterei la descrizione CreateFile() per attraversare riferimento alla ReOpenFile() descrizione. C'è un riferimento a pagina ReOpenFile() per CreateFile() pagina, ma non viceversa.

Questa funzione sembra consentire esattamente quello che mi serve: aggiunta o la rimozione di FILE_FLAG_OVELRAPPED da / per le maniglie già esistenti con la creazione di nuova maniglia con proprietà desiderate! :-D Non ho ancora provato, però. E ', purtroppo, disponibile solo su Windows 2003 Server, Windows Vista e poi. Domanda sulle versioni precedenti del sistema operativo è stato risposto qui . La funzione non esiste in API pubblica in OS precedenti a Windows Server 2003. E 'utilizzato dall'implementazione sottostante, ma non è disponibile per gli sviluppatori su tali sistemi (non supportato).

Ciò significa in pratica che non c'è speranza per me, almeno per i prossimi anni, fino a quando lasciamo cadere il supporto per le piattaforme Windows meno recenti. Significa anche che la situazione per quanto riguarda l'I / O è stato davvero male su OS più vecchio di Windows Vista. Dall'altra dolorosa che è scomparso tutto è la possibilità di cancellare sincrono e asincrono I / O su quei sistemi più vecchi.

Inoltre, mi manca una parte della risposta: può la presenza di bandiere essere testato con qualsiasi mezzo? Non ho trovato la funzione per farlo. Ciò significa che, se vogliamo garantire la presenza di qualche bandiera in oggetto file, il file deve sempre essere riaperto.

Se ho capito quello che stai dopo, vorrei suggerire che non si cura se è stato aperto con il flag sovrapposta o meno. Io credo che è possibile passare in modo sicuro in una struttura OVERLAPPED in entrambi i casi sincroni e asincroni. Il codice deve essere in grado di gestire il ritorno ReadFile() false e GetLastError() ritorno ERROR_IO_PENDING. Avrete anche bisogno di aggiungere le chiamate appropriate per GetOverlappedResult(), WaitForSingleObject(), ecc

L'articolo MSDN su ReadFile() ha alcune utili informazioni su questo sotto "Considerazioni per lavorare con i file handle sincrone", e "Considerazioni per lavorare con i file handle asincroni" nella sezione "Sincronizzazione di file e di posizione".

bandiere maniglia test dovrebbero probabilmente essere fatto allo stesso modo di testare i permessi del manico è stato creato con. Provalo. Se l'API non riesce, provare il fallback. Se non funziona, restituisce un errore.

Credo che la cosa veramente dicendo è il modo in cui la documentazione per ReadFile dice: "Se hFile viene aperto con FILE_FLAG_OVERLAPPED, ... funzione può segnalare erroneamente che l'operazione di lettura è stata completata."

La mia interpretazione dell'errore è, (e la domanda è necessario porsi è): se è stato possibile verificare lo stato sovrapposta di un handle di file, perché avrebbe ReadFile non farlo di controllo e quindi convalidare la struttura OVERLAPPED conseguenza , di fallire in modo esplicito se chiamati in modo non sovrapposta con una maniglia sovrapposta?

Non conosco un modo per determinare il flag di un handle e gli effetti collaterali dell'utilizzo dell'api ReOpen, ma poiché il tuo obiettivo era

sarebbe molto utile avere un solo modo per trattare tutte le maniglie

Se desideri un comportamento sincrono (intendo utilizzare API sincrone per handle non sovrapposti e API asincrone alimentate con struttura OVERLAPPED con successiva attesa sull'evento sovrapposto) puoi sempre utilizzare l'API asincrona anche se l'handle è stato aperto in modalità non sovrapposta come già affermato da @Brett
Posso confermare che funziona (ALMENO per le pipe denominate) es:

void connectSynchronous(HANDLE hPipeThatWeDontKnowItsFlag){
    ...
    BOOL bRet = ::ConnectNamedPipe(hPipeThatWeDontKnowItsFlag, pOverlapped);

    if(bRet == FALSE){
        DWORD dwLastErr = ::GetLastError();

        if(dwLastErr == ERROR_IO_PENDING){
            //The handle was opened for asynchronous IO so we have to wait for the operation
            ...waitFor on the overlapped hEvent;

        }else if(dwLastErr == ERROR_PIPE_CONNECTED){
            //The handle was opened for synchronous IO and the client was already connected before this call: that's OK!
            return;
        }else{
            throw Error(dwLastErr);
        }
    }/*else{
        //The handle was opened for synchronous IO and the client has connected: all OK
    }*/
}

Un'alternativa a l'hack CreateIoCompletionPort è di fare un ReadFile a zero byte con un NULL lpOverlapped. Se fallisce con ERROR_INVALID_PARAMETER assumere è stato aperto con FILE_FLAG_OVERLAPPED.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top