2012-10-18 14 views
5

首先,請原諒我,如果我說什麼傻,我也不IT的傢伙,但電子工程師,但我被分配到的東西,需要更多的技能,我做的。SetFilePointer不會失敗,也不會移動指針

我需要編寫,並在讀取SD卡的物理扇區。我已經用C++完成了它,但主要的應用程序是用C#編寫的,所以我認爲這是編寫我的第一個dll的好時機。

這裏是C++的工作寫扇區的代碼。

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); 
    } 

然後我做了DLL。功能是這樣的:

[DllImport("AccesoBajoNivel.dll", CallingConvention = CallingConvention.Cdecl)] 
static extern int EscribeBloqueFisico(char numeroDisco, byte[] buffer, long BytesQueEscribir, long posicion_inicio); 

然後我調用該函數::

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); 
} 

然後我在C#項目進口

int ResultEscribir = EscribeBloqueFisico(numeroDiscoFisico, BufferEscritura, 512, SectorEscribir * 512); 

始終寫入第一個扇區,無論價值「posicion_inicio」(起始偏移量,對西班牙語標記抱歉)所以這就是爲什麼我改變了api中的寫入函數以返回dwPtr(SetFilePointer的結果)而不是寫入的字節。這似乎總是零,這顯然不是我想要的。但無法找到爲什麼第一個功能的作品和DLL呼叫不。

也許是應該第一眼看到的,但正如我所說,我是電子人,不習慣這種編程...

其他功能(如在閱讀DISK_GEOMETRY或VOLUME_DISK_EXTENTS)的工作,我用它來確定哪個物理驅動器是給定的邏輯單元。正如我說的,也寫入和讀出工作做好了,這只是我總是指着部門零...提前

感謝。另外,這是我第一次在這裏發帖。重複多次(這就是爲什麼我選擇在這裏問),但如果我在發佈問題時犯了一些錯誤,請指出。

回答

3

在C++甲是32位。這使得它在C#中成爲int。在pinvoke聲明中將long替換爲int。

你應該得到一個PInvokeStackImbalance警告有關。如果關閉它,請確保重新啓用該警告。在調試器中可以很容易地看到* posicion_inicio *的值是錯誤的。一定要啓用非託管調試,項目+屬性,調試選項卡。現在你可以在你的C++代碼中設置一個斷點。

+0

非常感謝。那(在c#中聲明爲int是什麼在C++中長)解決了這個問題。也非常感謝你在非託管代碼調試中的提示,不知道這個選項。現在它按預期工作。我想這應該讓我在切換語言時更注重數據類型。再次感謝!請原諒我的英語:)編輯:不能投票答案,因爲似乎我需要聲望15這樣做。 – JeToMad

+0

從技術上講,Microsoft Visual C++ **中的「long」是32位。 IIRC,在Linux/G ++上它通常是64位,就像在C#中一樣。 – MSalters