Implementando Win32 FileWrite
-
12-09-2019 - |
Pergunta
[DllImport("kernel32.dll", SetLastError=true)]
public static extern unsafe bool WriteFile(IntPtr hFile, void* lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
Estou implementando isso através de um Write (..) método com uma assinatura:
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;
}
}
Como eu aprendi olhando este (a uso do homólogo de leitura é discutido) Eu preciso implementar um loop while no meu código porque a leitura / gravação do buffer pode não passar de uma só vez. Este é o lugar onde o problema começar:
Se eu quero manter o meu C # assinatura método como a aceitar a * vazio, ao contrário do exemplo Leia ligada onde um byte * é aceito como um parâmetro para o buffer.
Isto significa que após um passe do WriteFile, eu deveria mudar meu void *, juntamente com o início do buffer que não tenha sido escrito ainda. Eu não posso, aparentemente, fazer isso por apenas incrementar void * com o uint que contém o número de bytes escritos ... Eu entendo que void * não tem um tamanho pré-determinado e que incrementação não é, portanto, possível, mas eu me pergunto como eu, em seguida, deve alcançar o que Eu estou tentando fazer.
Solução
Você deve ser capaz de buffer
fundido a um byte*
e depois incrementá-lo. Um ponteiro nulo não tem tamanho associado com ele, então se você quiser movimento que um determinado número de bytes em qualquer direção que você pode lançá-lo para um tipo diferente de ponteiro (qualquer tipo para que o assunto) e, em seguida, usar o tamanho do tipo fundido na aritmética de ponteiro, assim:
buffer = (void *)((byte*)buffer + wrtn);
A linha de cima moldes buffer
para um byte ponteiro, em seguida, incrementa a sua posição por número wrtn
de bytes e, em seguida, molda o apontador novo de volta para uma * vazio. Claro, lançando a um byte*
é a escolha óbvia se você está querendo para executar a aritmética de ponteiro arbitrário.
Outra possibilidade é buffer
deleite como um byte*
o tempo todo e só lançá-lo aos void*
quando você passá-lo para 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, como uma última sugestão, eu consideraria mudar a assinatura do Write
completamente para usar um byte*
vez de void*
porque iria torná-lo mais compatível com outras chamadas de C # e um byte*
faz mais sentido nesse caso. Você não deveria ter que se preocupar em fazer-lo coincidir com a assinatura da API nativa WriteFile desde que você pode lançar o byte*
como mostrado acima para uma void*
ao passar-lo.
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;
}
}
Infelizmente, eu tenho que concordar com um dos comentadores. Por que você está fazendo isso? Lá são melhores maneiras de realizar uma gravação de arquivo em c #, usando muitas das classes fluxo orientado.