First, please forgive me if I say something silly, I am no IT guy but electronics engineer, but I have been assigned to something that needs more skills that I do.
I need to write and read physical sectors in a SD card. I have accomplished it in C++, but the main application is written in C#, so I thought that it was a good moment to write my first dll.
Here is the code working in c++ for writing a sector.
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);
}
Then I made the DLL. Function is this:
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);
}
Then I imported in the C# project:
[DllImport("AccesoBajoNivel.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int EscribeBloqueFisico(char numeroDisco, byte[] buffer, long BytesQueEscribir, long posicion_inicio);
Then I call the function:
int ResultEscribir = EscribeBloqueFisico(numeroDiscoFisico, BufferEscritura, 512, SectorEscribir * 512);
Always writes to the first sector, no matter the value of “posicion_inicio” (Is the start offset, sorry about the spanish tags) So that’s why I changed the writing function in the api to return dwPtr (Result of SetFilePointer) instead of bytes written. This always seems to be zero, which is obviously not what I want. But can’t find why the first function works and the dll call don’t.
Maybe is something that should be seen at first glance, but as I said, I am electronics guy, not used to this kind of programming…
Other functions (As reading DISK_GEOMETRY or VOLUME_DISK_EXTENTS) work, which I use to determine which Physical Drive is a given logical unit. As I say, also, writing and reading work well, it’s just that I am always pointing to sector zero…
Thanks in advance. Also, this is the first time I post here. Readed many times (That is why I chosed to ask here) but if I made some mistake when posting the question, please point it out.
A long in C++ is 32-bits. Which makes it an int in C#. Replace long with int in the pinvoke declaration.
You should have gotten a PInvokeStackImbalance warning about that. Be sure the re-enable that warning if you turned it off. And it would have been easy to see that the value for *posicion_inicio* is wrong in the debugger. Be sure to enable unmanaged debugging, Project + Properties, Debug tab. Now you can set a breakpoint in your C++ code.