tags:

views:

770

answers:

5

Hi,

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!

A: 

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.

schnaader
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.
WBun
In this case it would help if you post more of your code, because what you posted could be used in any way.
schnaader
A: 

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);
Stephen Nutt
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?
WBun
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?
atk
I've edited my original post to contain more information now I understand what you are trying to do.
Stephen Nutt
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.
WBun
A: 

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

Mark Byers
Thanks. Any suggestion on how to do the append? Cheers.
WBun
Why aren't you voting up any of the answers that you found helpful?
Mark Byers
A: 

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.

shf301
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.
WBun
A: 

Thanks a lot guys. Your help got me further. But for some reasons I am still not getting a null terminated wchar. I can't think of anything else I can try. I've attached my codes below, would you mind to take a look please? Thanks again!

PFbwfCacheDetail Cache_detail = (PFbwfCacheDetail)malloc(280);
ULONG cdSize = sizeof(Cache_detail);

iErr = FbwfFindFirst(L"C:",Cache_detail,&cdSize);
while(iErr == ERROR_MORE_DATA)
{
    free(Cache_detail);
    Cache_detail = (PFbwfCacheDetail) malloc (cdSize);
    iErr = FbwfFindFirst(szDrive,Cache_detail,&cdSize);
}

fprintf(output, "%d\n", Cache_detail->fileNameLength) //outputs 46 

**//Tried both below
Cache_detail->fileName[Cache_detail->fileNameLength] = L'\0';
//Cache_detail->fileName[Cache_detail->fileNameLength/sizeof(WCHAR)+1] = L'\0';
fprintf(output, "%ls\n", Cache_detail->fileName) 
// outputs \MyDirectory\MyFile.txt, no carriage return, which indicates that null
// terminated character not appended??
iCommitErr = FbwfCommitFile(L"C:", (WCHAR*)(Cache_detail->fileName)); 
//Returns ERROR_FILE_NOT_FOUND**


//Since the above didn't work, I tried copying to another string
ULONG fsize = Cache_detail->fileNameLength;
wchar_t * pFileName = Cache_detail->fileName;
WCHAR buffer1[500];
wmemcpy(buffer1, pFileName, fsize);

**//Tried all three below
buffer1[fsize] = L'\0';
//buffer1[fsize+1] = L'\0';  
//buffer1[fsize/sizeof(WCHAR) +1] = L'\0';  
fprintf(output, "%ls\n", buffer1) 
// outputs \MyDirectory\MyFile.txt, no carriage return, which indicates that null
// terminated character not appended??
iCommitErr = FbwfCommitFile(L"C:", buffer1); 
//Returns ERROR_FILE_NOT_FOUND**








int iCommitErr = FbwfCommitFile(L"C:", (WCHAR*)(Cache_detail->fileName));


while (iErr != 18) //iError != ERROR_NO_MORE_FILES
{
    iErr = FbwfFindNext(Cache_detail, &cdSize);

    if (iErr == ERROR_MORE_DATA)
    {
        free(Cache_detail);
        Cache_detail = (PFbwfCacheDetail) malloc (cdSize);
        iErr = FbwfFindNext(Cache_detail,&cdSize);
    }

}

iErr = FbwfFindClose();
WBun
You need to understand the diference between being null terminated and appending a carriage return. "null terminated" means that yur string ends with a NUL character - that is, the character (single byte) value of 0. Not having a carriage return does NOT mean that your string is not null terminated. It means only that there's no carriage return. When you fprintf(output, "%ls\n", buffer1) (missing a semicolon, BTW), fprintf() copies all data from the location where buffer1 starts until a NUL is encountered. (continued next comment)
atk
For example, let's say buffer1 has been assigned the string "abc", this is explicitly assigning buffer1[0] = 'a', buffer1[1] = 'b', buffer1[2] = c, and buffer1[3] = 0. That means buffer1 is null terminated. (continued next comment)
atk
Now, the question becomes: exactly what is the error you're trying to resolve? Is it the ERROR_FILE_NOT_FOUND that you're trying to fix?
atk
Don't reply to a question with a new question. Edit your original question.
Mark Byers
Thanks a lot Mark. You are right. So maybe my problem had nothing to do with the string being null terminated or not.Sorry I wasn't aware of the edit button. Cheers.
WBun