2012-10-18 12 views
5

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ć.

Odpowiedz

3

długo C++ ma 32 bitów. Co sprawia, że ​​jest on w C#. Zastąp długie z int w deklaracji pinvoke.

Powinieneś otrzymać ostrzeżenie PInvokeStackImbalance na ten temat. Pamiętaj, aby ponownie włączyć to ostrzeżenie, jeśli je wyłączyłeś. Łatwo byłoby zauważyć, że wartość * posicion_inicio * jest błędna w debugerze. Pamiętaj, aby włączyć niezarządzane debugowanie, kartę Project + Właściwości, kartę Debugowanie. Teraz możesz ustawić punkt przerwania w swoim kodzie C++.

+0

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

+0

Technicznie "long" w ** Microsoft Visual C++ ** ma 32 bity. IIRC, w Linuksie/G ++ to często 64 bity, tak jak w C#. – MSalters

Powiązane problemy