Po pierwsze, proszę mi wybaczyć, jeśli powiem coś głupiego, nie jestem facetem, ale elektronika inżynier IT, ale zostały przypisane do czegoś, co wymaga więcej umiejętności, które robię.SetFilePointer nie zawodzi, ale również nie Przesuwanie kursora
Potrzebuję pisać i czytać sektory fizyczne na karcie SD. Zrobiłem to w C++, ale główna aplikacja jest napisana w języku C#, więc pomyślałem, że to był dobry moment na napisanie mojej pierwszej biblioteki DLL.
Oto kod działający w języku C++ do pisania sektora.
private: System::Void button4_Click(System::Object^ sender, System::EventArgs^ e) {
HANDLE hFile = INVALID_HANDLE_VALUE;
BOOL fSuccess = FALSE;
DWORD dwBytesWritten = 0;
unsigned char chBuffer[SIZE];
long SectorActual = 39;
long PosicionInicio = SectorActual * 512;
for (int i=0; i<SIZE; i++) // Garbage values to be written
{
chBuffer[i]= i % 16;
if((i/16)%2==0)
{
chBuffer[i]= 15 - chBuffer[i];
}
}
hFile = CreateFileA("\\\\.\\PhysicalDrive5",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
textBox1->Text += "Could not open file (error " + GetLastError() + ") \r\n";
return;
}
DWORD dwPtr = SetFilePointer(hFile,
PosicionInicio,
NULL,
FILE_BEGIN);
if (dwPtr == INVALID_SET_FILE_POINTER) // Test for failure
{
textBox1->Text += "Error moving pointer (error " + GetLastError() + ") \r\n";
return; // Deal with failure
} // End of error handler
fSuccess = WriteFile(hFile, chBuffer, TAMANYO_SECTOR, &dwBytesWritten, NULL);
if (!fSuccess)
{
textBox1->Text += "WriteFile failed\r\n";
}
else
{
textBox1->Text += "WriteFile wrote " + dwBytesWritten.ToString() + " bytes\r\n";
}
CloseHandle(hFile);
}
Następnie utworzyłem DLL. Funkcja jest taka:
int AccesoBajoNivel::EscribeBloqueFisico(char numeroDisco, unsigned char * buffer, long BytesQueEscribir, long posicion_inicio)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
BOOL fSuccess = FALSE;
DWORD dwBytesWritten = 0;
char ArrayDeChars[] = "\\\\.\\PhysicalDrive5";
ArrayDeChars[17] = numeroDisco;
LPCSTR pathAlDisco = ArrayDeChars;
hFile = CreateFileA(pathAlDisco,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
//printf("Could not open file (error %d)\n", GetLastError());
CloseHandle(hFile);
return -1;
}
DWORD dwPtr = SetFilePointer(hFile,
posicion_inicio,
NULL,
FILE_BEGIN);
if (dwPtr == INVALID_SET_FILE_POINTER) // Test for failure
{
CloseHandle(hFile);
return -2; // Deal with failure
} // End of error handler
fSuccess = WriteFile(hFile, buffer, BytesQueEscribir, &dwBytesWritten, NULL);
if (!fSuccess)
{
CloseHandle(hFile);
return -3;
}
else
{
CloseHandle(hFile);
//return dwBytesWritten;
return dwPtr;
}
CloseHandle(hFile);
}
Potem importowany w projekcie C#:
[DllImport("AccesoBajoNivel.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int EscribeBloqueFisico(char numeroDisco, byte[] buffer, long BytesQueEscribir, long posicion_inicio);
Wtedy nazywamy funkcję:
int ResultEscribir = EscribeBloqueFisico(numeroDiscoFisico, BufferEscritura, 512, SectorEscribir * 512);
zawsze zapisuje się do pierwszego sektora, bez względu na wartość z "posicion_inicio" (jest przesunięcie początkowe, przepraszam za tagi hiszpańskie) Dlatego właśnie zmieniłem funkcję zapisu w interfejsie API, aby zwrócić dwPtr (Result of SetFilePointer) zamiast zapisanych bajtów. To zawsze wydaje się być zerowe, co oczywiście nie jest tym, czego chcę. Ale nie można znaleźć, dlaczego pierwsza funkcja działa i wywołanie dll nie.
Może jest coś, co powinno być widoczne na pierwszy rzut oka, ale jak już mówiłem, jestem elektronika facet, nie używane do tego rodzaju programowania ...
Inne funkcje (jak czytanie DISK_GEOMETRY lub VOLUME_DISK_EXTENTS) pracy, które używam do określenia, który dysk fizyczny jest daną jednostką logiczną. Jak mówię, też, pisząc i czytając pracę dobrze, tylko że ja zawsze wskazując sektorze zerowym ...
Z góry dzięki. Również tutaj po raz pierwszy zamieszczam. Czyta się wiele razy (dlatego chciałem zapytać tutaj), ale jeśli popełniłem jakiś błąd, publikując pytanie, proszę wskazać.
Dziękuję bardzo. To (deklarując jako int w C#, co było długo w C++) rozwiązało problem. Również bardzo dziękuję za podpowiedź w niezarządzanym debugowaniu kodu, nie wiedziałem o tej opcji. Teraz działa zgodnie z przeznaczeniem. Przypuszczam, że powinno to spowodować, że zwracam większą uwagę na typy danych podczas zmiany języków. Dzięki jeszcze raz! Proszę wybaczyć mój angielski :) EDYCJA: Nie mogę głosować na odpowiedź, ponieważ wydaje mi się, że muszę mieć reputację 15, aby to zrobić. – JeToMad
Technicznie "long" w ** Microsoft Visual C++ ** ma 32 bity. IIRC, w Linuksie/G ++ to często 64 bity, tak jak w C#. – MSalters