Implementazione Win32 FileWrite
-
12-09-2019 - |
Domanda
[DllImport("kernel32.dll", SetLastError=true)]
public static extern unsafe bool WriteFile(IntPtr hFile, void* lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
Io sono l'attuazione del presente attraverso un metodo Write (..) con una firma:
Write(IntPtr handleFile, void* bufferData, uint length){
void* buffer = bufferData
while (length > 0)
{
uint wrtn;
if (!WriteFile(handle, buffer, len, out wrtn, IntPtr.Zero))
{
// Do some error handling
}
// THIS DOESNT WORK!
// I want to move along the buffer to be able to write its remainder...
// I tried many variations of this as well, but it seems even '+' is not valid for a void*
buffer += wrtn;
len -= wrtn;
}
}
Come ho imparato, cercando in questo (il uso della controparte di lettura viene discussa) ho bisogno di implementare un ciclo while nel mio codice, perché la scrittura / lettura del buffer potrebbe non passare attraverso in un colpo solo. Questo è dove inizia il problema:
Se voglio mantenere la mia C # firma del metodo per accettare un void *, a differenza del Leggi esempio connessi in cui un byte * viene accettato come parametro per il buffer.
Ciò significa che dopo un passaggio del WriteFile, avrei dovuto spostare la mia void * lungo l'inizio del buffer che non è stato ancora scritto. Non posso fare questo a quanto pare semplicemente incrementando void * con l'uint che contiene il numero di byte scritti ... Capisco che void * Non ha una dimensione predeterminata e che di incremento non è quindi possibile, ma mi chiedo come ho poi dovuto realizzare che cosa io sto cercando di fare.
Soluzione
Si dovrebbe essere in grado di lanciare buffer
ad un byte*
e poi incrementarlo. Un puntatore nullo non ha dimensioni ad esso associati, quindi se si vuole mossa è un certo numero di byte in qualsiasi direzione si può lanciarlo a un diverso tipo di puntatore (qualsiasi tipo per quella materia) e quindi utilizzare le dimensioni del tipo di fuso nel aritmetica dei puntatori, in questo modo:
buffer = (void *)((byte*)buffer + wrtn);
La riga precedente getta buffer
a un puntatore byte, quindi incrementa la sua posizione numero wrtn
di byte e quindi getta il nuovo puntatore di nuovo ad un void *. Naturalmente, lanciando ad un byte*
è la scelta più ovvia, se si vogliono eseguire arbitraria aritmetica dei puntatori.
Un'altra possibilità è quella di trattare buffer
come byte*
tutti insieme e solo gettarlo ai void*
quando si passa a WriteFile
Write(IntPtr handleFile, void* bufferData, uint length)
{
byte* buffer = (byte*)bufferData;
while (length > 0)
{
uint wrtn;
if (!WriteFile(handle, (void*)buffer, len, out wrtn, IntPtr.Zero))
{
// Do some error handling
}
buffer += wrtn;
len -= wrtn;
}
}
E, come ultimo suggerimento, vorrei prendere in considerazione la modifica della firma di Write
del tutto di usare un byte*
invece di void*
perché sarebbe renderlo più compatibile con altri chiamanti da C # e un byte*
ha più senso in questo caso. Non dovreste preoccuparvi di rendendolo corrisponde alla firma delle API native WriteFile dato che è possibile lanciare la byte*
come indicato sopra per un void*
quando passa in.
Write(IntPtr handleFile, byte* bufferData, uint length)
{
while (length > 0)
{
uint wrtn;
if (!WriteFile(handle, (void*)bufferData, len, out wrtn, IntPtr.Zero))
{
// Do some error handling
}
bufferData+= wrtn;
len -= wrtn;
}
}
Ahimè, io sono d'accordo con uno dei commentatori. Perché stai facendo questo? Là sono modi migliori per realizzare un file di scrittura in C # utilizzando molte delle classi stream oriented.