1. Ugh, stupid TCHAR problems. Anyone able to tell me how to fix this in EUcode?
- Posted by ssallen Jul 05, 2010
- 1476 views
The function should return a text buffer I can parse to get the local system's drives. Unfortunately the API function returns the text in a TCHAR buffer which creates garbage output when I try to read it. Here is my code:
constant kernel32 = open_dll( "kernel32.dll" ), xGetFreeSpace = define_c_func(kernel32, "GetDiskFreeSpaceExA", {C_POINTER, C_POINTER, C_POINTER, C_POINTER}, C_INT), xGetMetrics = define_c_func(kernel32, "GetDiskFreeSpaceA", {C_POINTER, C_POINTER, C_POINTER, C_POINTER, C_POINTER}, C_INT), xGetDriveType = define_c_func(kernel32, "GetDriveTypeA", {C_POINTER}, C_INT), xGetDriveStrings = define_c_func(kernel32, "GetLogicalDriveStringsA", {C_DOUBLE, C_POINTER}, C_INT) global function get_all_drives() sequence drivestrings atom retptr, converted_addr atom buflen retptr = allocate(8) -- allocate 8 bytes for the pointer to the buffer buflen = c_func(xGetDriveStrings, {200, retptr}) -- bufeln s/b size of buffer, 200 = max size I am allowing buffer, retptr should catch -- address of buffer if buflen > 0 then -- function has given me a vale > 0 so function succeeded -- ok to work drivestrings = sprintf("GOOD RETURN: %d ", {buflen}) -- convert 8 bytes to address converted_addr = peek4u(retptr)+(peek4u(retptr+4) * #100000000) -- peek the text from the buffer drivestrings &= w32peek_string(converted_addr) else drivestrings = "BAD RETURN" end if free(retptr) return drivestrings end function
On my system this code creates the output: GOOD RETURN: 37 222222
EDIT: The output should show the character representations of all my computer drives. (i.e. C:, D:, etc.) EDIT2: I have 9 drives on my system so 3 chars + null * 9 + end null = 37. The function seems to be returning correctly... just don't know how to read the buffer. :(
The MSDN reference site for GetLogicalDriveStringsA says that it creates a buffer using TCHARs. So how can I convert these to a regular euphoria character string?
Any help, as always, is greatly appreciated! I'm using EU 3.1.1
Thanks! Steve A.
2. Re: Ugh, stupid TCHAR problems. Anyone able to tell me how to fix this in EUcode?
- Posted by jimcbrown (admin) Jul 05, 2010
- 1472 views
The function should return a text buffer I can parse to get the local system's drives. Unfortunately the API function returns the text in a TCHAR buffer which creates garbage output when I try to read it. Here is my code:
constant kernel32 = open_dll( "kernel32.dll" ), xGetFreeSpace = define_c_func(kernel32, "GetDiskFreeSpaceExA", {C_POINTER, C_POINTER, C_POINTER, C_POINTER}, C_INT), xGetMetrics = define_c_func(kernel32, "GetDiskFreeSpaceA", {C_POINTER, C_POINTER, C_POINTER, C_POINTER, C_POINTER}, C_INT), xGetDriveType = define_c_func(kernel32, "GetDriveTypeA", {C_POINTER}, C_INT), xGetDriveStrings = define_c_func(kernel32, "GetLogicalDriveStringsA", {C_DOUBLE, C_POINTER}, C_INT) global function get_all_drives() sequence drivestrings atom retptr atom buflen retptr = allocate(8) buflen = c_func(xGetDriveStrings, {200, retptr}) if buflen > 0 then -- ok to work drivestrings = sprintf("GOOD RETURN: %d ", {buflen}) drivestrings &= w32peek_string(peek4u(retptr)+(peek4u(retptr+4) * #100000000)) else drivestrings = "BAD RETURN" end if free(retptr) return drivestrings end function
On my system this code creates the output: GOOD RETURN: 37 222222
EDIT: The output should show the character representations of all my computer drives. (i.e. C:, D:, etc.)
The MSDN reference site for GetLogicalDriveStringsA says that it creates a buffer using TCHARs. So how can I convert these to a regular euphoria character string?
Any help, as always, is greatly appreciated! I'm using EU 3.1.1
Thanks! Steve A.
http://msdn.microsoft.com/en-us/library/cc842072.aspx
So a TCHAR, for the ANSI version, is just a regular char. So using peek_string() should work fine.
The real issue is not TCHAR related, but I suspect, it is because you are using the function incorrectly. An 8 byte buffer is not large enough to hold 200 chars, and the buffer is filled with multiple null terminated strings right next to each other, which makes your code (which appears to attempt to derive a pointer from the contents of a buffer) hard to understand.
3. Re: Ugh, stupid TCHAR problems. Anyone able to tell me how to fix this in EUcode?
- Posted by ssallen Jul 05, 2010
- 1397 views
Hi Jim,
The MSDN documentation describes the parameters for the function as follows: DWORD WINAPI GetLogicalDriveStrings( in DWORD nBufferLength, out LPTSTR lpBuffer );
"nBufferLength [in] The maximum size of the buffer pointed to by lpBuffer, in TCHARs. This size does not include the terminating null character. If this parameter is zero, lpBuffer is not used.
lpBuffer [out] A pointer to a buffer that receives a series of null-terminated strings, one for each valid drive in the system, plus with an additional null character. Each string is a device name."
So when I am calling the function I am using retptr as the pointer that holds the address of the txt buffer. The 8 bytes is just to hold the address of the buffer... not the buffer itself. At least thats how I understand it. The 200 that is passed was just an arbitrary value that I felt was big enough of a buffer to hold my system information... since I am not entirely sure what the output from the c function will actually look like. The function itself is WINAPI. Buflen is the functin return that tells me how long the buffer actually is. Does that clear it up? I'm going to clear up the code and comment it a bit more maybe then it will be easier to explain what I am doing wrong.
EDIT: commented original code better.
4. Re: Ugh, stupid TCHAR problems. Anyone able to tell me how to fix this in EUcode?
- Posted by jimcbrown (admin) Jul 05, 2010
- 1492 views
Hi Jim,
So when I am calling the function I am using retptr as the pointer that holds the address of the txt buffer. The 8 bytes is just to hold the address of the buffer... not the buffer itself. At least thats how I understand it.
This is wrong. I feel the confusion comes from C code, in which any array or string is automatically a pointer as well.
You need to allocate a space of size 200, to match the buffer length you are passing in. Or, you could call the function with 0 and NULL, in which case only the length of the buffer is returned. Then you can allocate a buffer of the right size and call the function again.
The 200 that is passed was just an arbitrary value that I felt was big enough of a buffer to hold my system information... since I am not entirely sure what the output from the c function will actually look like. The function itself is WINAPI. Buflen is the functin return that tells me how long the buffer actually is. Does that clear it up? I'm going to clear up the code and comment it a bit more maybe then it will be easier to explain what I am doing wrong.
From this, I believe I have understood your code correctly and I maintain that you are calling it incorrectly, based on this example: http://www.codeguru.com/forum/archive/index.php/t-252784.html
That example can be converted to Euphoria code like this:
atom pch atom szBuffer szBuffer = allocate(1024) ? c_func(GetDriveLogicalSpace_, {1024, szBuffer}) pch = szBuffer while peek(pch) != 0 do puts(1, peek_string(pch) & '\n') pch = pch + length(peek_string(pch)) + 1 end while
5. Re: Ugh, stupid TCHAR problems. Anyone able to tell me how to fix this in EUcode?
- Posted by LarryMiller Jul 05, 2010
- 1386 views
Your code is incorrect.
The second parameter to GetLogicalDriveStrings() is a pointer to a buffer that holds the returned strings. It is not a pointer to a pointer. The first parameter is the length of this buffer.
The result is a series of null terminated strings. This will in the form: C:\(NULL)D:\(NULL)
(NULL) is a single zero character.
I have used this function as described and know it works.
6. Re: Ugh, stupid TCHAR problems. Anyone able to tell me how to fix this in EUcode?
- Posted by ssallen Jul 05, 2010
- 1410 views
Ok, so I replaced my code with what Jim provided and my output still looks like rubbish:
37 2 rubbish characters.
My new code looks like this:
constant kernel32 = open_dll( "kernel32.dll" ), xGetFreeSpace = define_c_func(kernel32, "GetDiskFreeSpaceExA", {C_POINTER, C_POINTER, C_POINTER, C_POINTER}, C_INT), xGetMetrics = define_c_func(kernel32, "GetDiskFreeSpaceA", {C_POINTER, C_POINTER, C_POINTER, C_POINTER, C_POINTER}, C_INT), xGetDriveType = define_c_func(kernel32, "GetDriveTypeA", {C_POINTER}, C_INT), xGetDriveStrings = define_c_func(kernel32, "GetLogicalDriveStringsA", {C_DOUBLE, C_POINTER}, C_INT) global function get_all_drives() atom pch atom szBuffer szBuffer = allocate(1024) ? c_func(xGetDriveStrings, {1024, szBuffer}) pch = szBuffer while peek(pch) != 0 do puts(1, peek_string(pch) & '\n') pch = pch + length(peek_string(pch)) + 1 end while return "" end function
Obviously I just added the code into my old function to see the console output. Is my declaration calling the dll incorrect then?
Thanks! Steve A.
7. Re: Ugh, stupid TCHAR problems. Anyone able to tell me how to fix this in EUcode?
- Posted by jimcbrown (admin) Jul 05, 2010
- 1396 views
Obviously I just added the code into my old function to see the console output. Is my declaration calling the dll incorrect then?
Thanks! Steve A.
Yes. The first parameter should be C_INT, not C_DOUBLE.
8. Re: Ugh, stupid TCHAR problems. Anyone able to tell me how to fix this in EUcode?
- Posted by ssallen Jul 05, 2010
- 1390 views
That did the trick! Thanks gentlemen!