6

I've got this

WCHAR fileName[1];

as a returned value from a function (it's a sys 32 function so I am not able to change the returned type). I need to make fileName to be null terminated so I am trying to append '\0' to it, but nothing seems to work.

Once I get a null terminated WCHAR I will need to pass it to another sys 32 function so I need it to stay as WCHAR.

Could anyone give me any suggestion please?

================================================

Thanks a lot for all your help. Looks like my problem has to do with more than missing a null terminated string.

//This works:

WCHAR szPath1[50] = L"\\Invalid2.txt.txt";
    dwResult = FbwfCommitFile(szDrive, pPath1); //Successful

//This does not:

std::wstring l_fn(L"\\");  
    //Because Cache_detail->fileName is \Invalid2.txt.txt and I need two
l_fn.append(Cache_detail->fileName);
l_fn += L""; //To ensure null terminated
fprintf(output, "l_fn.c_str: %ls\n", l_fn.c_str()); //Prints "\\Invalid2.txt.txt"

    iCommitErr = FbwfCommitFile(L"C:", (WCHAR*)l_fn.c_str()); //Unsuccessful

//Then when I do a comparison on these two they are unequal.

int iCompareResult = l_fn.compare(pPath1);  // returns -1

So I need to figure out how these two ended up to be different.

Thanks a lot!

2
  • Which function are you getting the string from? Are you sure it's not already NULL-terminated? Commented Nov 27, 2009 at 0:52
  • WCHAR fileName[1] will only ever hold 1 character (the zero termination character). You probably want WCHAR fileName[MAX_PATH] if you're on win32/mfc. Commented Nov 27, 2009 at 6:06

4 Answers 4

7

Since you mentioned fbwffindfirst/fbwffindnext in a comment, you're talking about the file name returned in FbwfCacheDetail. So from the fileNameLength field you know length for the fileName in bytes. The length of fileName in WCHAR's is fileNameLength/sizeof(WCHAR). So the simple answer is that you can set

fileName[fileNameLength/sizeof(WCHAR)+1] = L'\0'

Now this is important you need to make sure that the buffer you send for the cacheDetail parameter into fbwffindfirst/fbwffindnext is sizeof(WCHAR) bytes larger than you need, the above code snippet may run outside the bounds of your array. So for the size parameter of fbwffindfirst/fbwffindnext pass in the buffer size - sizeof(WCHAR).

For example this:

// *** Caution: This example has no error checking, nor has it been compiled ***
ULONG error;
ULONG size;
FbwfCacheDetail *cacheDetail;

// Make an intial call to find how big of a buffer we need
size = 0;
error = FbwfFindFirst(volume, NULL, &size);
if (error == ERROR_MORE_DATA) {
    // Allocate more than we need
    cacheDetail = (FbwfCacheDetail*)malloc(size + sizeof(WCHAR));
    // Don't tell this call about the bytes we allocated for the null
    error = FbwfFindFirstFile(volume, cacheDetail, &size);
    cacheDetail->fileName[cacheDetail->fileNameLength/sizeof(WCHAR)+1] = L"\0";

    // ... Use fileName as a null terminated string ...

    // Have to free what we allocate
    free(cacheDetail);
}

Of course you'll have to change a good bit to fit in with your code (plus you'll have to call fbwffindnext as well)

If you are interested in why the FbwfCacheDetail struct ends with a WCHAR[1] field, see this blog post. It's a pretty common pattern in the Windows API.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot! Your help got me further. But for some reasons the appending (of the L'\0') didn't seem to do anything. Would you mind taking a look at my latest post please? Thanks.
4

Use L'\0', not '\0'.

1 Comment

Thanks. Any suggestion on how to do the append? Cheers.
0

As each character of a WCHAR is 16-bit in size, you should perhaps append \0\0 to it, but I'm not sure if this works. By the way, WCHAR fileName[1]; is creating a WCHAR of length 1, perhaps you want something like WCHAR fileName[1024]; instead.

3 Comments

Thanks for the suggestion. Any idea how I actually go about appending it to the WCHAR? I should mention that I am very new to c++ so more details the better :) Cheers.
In this case it would help if you post more of your code, because what you posted could be used in any way.
No, there is no need. You're correct that a wchar is a 2 byte char. But WCHAR fileName[1] references a 2 byte number, which is 0.
0

WCHAR fileName[1]; is an array of 1 character, so if null terminated it will contain only the null terminator L'\0'.

Which API function are you calling?

Edited

The fileName member in FbwfCacheDetail is only 1 character which is a common technique used when the length of the array is unknown and the member is the last member in a structure. As you have likely already noticed if your allocated buffer is is only sizeof (FbwfCacheDetail) long then FbwfFindFirst returns ERROR_NOT_ENOUGH_MEMORY.

So if I understand, what you desire to do it output the non NULL terminated filename using fprintf. This can be done as follows

fprintf (outputfile, L"%.*ls", cacheDetail.fileNameLength, cacheDetail.fileName);

This will print only the first fileNameLength characters of fileName.

An alternative approach would be to append a NULL terminator to the end of fileName. First you'll need to ensure that the buffer is long enough which can be done by subtracting sizeof (WCHAR) from the size argument you pass to FbwfFindFirst. So if you allocate a buffer of 1000 bytes, you'll pass 998 to FbwfFindFirst, reserving the last two bytes in the buffer for your own use. Then to add the NULL terminator and output the file name use

cacheDetail.fileName[cacheDetail.fileNameLength] = L'\0';
fprintf (outputfile, L"%ls", cacheDetail.fileName);

4 Comments

Actually I printed it out fprintf(outputfile, %ls\n", fileName) and it contains more than one characters. It's printing \Mydirectory\Myfile.txt. I am using the fbwfapi. I am calling the fbwffindfirst/fbwffindnext (which returns a non-null terminated WCHAR fileName[1]) to find a list of files in my overlay, and then call fbwfcommitfile (which requires a null terminated wide string) to commit the file. Any idea how to do the append?
the filename is then already null terminated - whether intentional or not. By definition, fprintf() with those arguments prints the full string into outputfile (side note: be careful that filename can never be longer than outputfile or you'd have a buffer overrun vuln). By definition, a string ends in a null. If fprintf did not run into a null character, then it would continue printing until it it ran off the edge of accessible memory. That said: what are you really trying to accomplish - what result do you want to achieve?
I've edited my original post to contain more information now I understand what you are trying to do.
Thanks Stephen. Your help got me further. For some reasons the appending (of the L'\0') didn't seem to do anything. Would you mind taking a look at my latest post please? Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.