I need to find files with certain extentions, for example *.doc, *.docx
First, i'm looking for all files
lstrcat(szPath, L"*");
hFind = FindFirstFile(szPath, &fdFindData);
Then, i compare founded file with extention i need
PCWSTR str1 = L".doc";
if(NULL != StrStr(fdFindData.cFileName,str1)) {
FoundFileFunction(fdFindData.cFileName);
}
And then I got problem with cout
VOID FoundFileFunction(HANDLE hFile)
{
std::cout<<hFile;
}
This is output:
009AE50000
009AEB0000
009AEBBB00
and so on. What's the problem?
WIN32_FIND_DATA::cFileName is a TCHAR[MAX_PATH], not a HANDLE.
I don't know why you wrote HANDLE, as that's not uttered on the documentation page even once.
Your function is trying to print out the C-string filename as if it were a HANDLE, which is a different kind of pointer to a TCHAR*. It doesn't know to take the pointer as a TCHAR* so it doesn't know you want it to format the output as a string. It can only know to print the address represented by the pointer.
Your function FoundFileFunction should take a TCHAR*.
The problem would have been automatically detected had you used STRICT mode. If (for example) NO_STRICT is defined then HANDLE is an alias for void* which, per the rules of the language, can be initialised implicitly from a TCHAR*. You should always compile with STRICT defined: that would have changed the types not to be implicitly convertible to one another, and you would have received a compilation error for your mistake.
Furthermore, if your program is using Unicode, then TCHAR is not char but wchar_t, so you need to use not std::cout but std::wcout.
Related
I've just started doing some Win32 programming and I'm confused on the function:
BOOL BuildCommDCB(LPCTSTR szSettings, LPDCB lpDCB);
The description of the LPDCB struct states that "it points to the DCB structure in which the control settings information is
returned". But my question is how is the DCB structure returned when the return value is a BOOL?
LPDCB is a pointer to a structure you provide(1), and BuildCommDCB() will populate that structure, as well as returning a success indicator.
It's no different to the function:
int setTo13AndReturn42 (int *pInt) {
*pInt = 13;
return 42;
}
which, when called with:
int i1 = -1;
int i2 = setTo13AndReturn42 (&i1);
printf ("%d %d\n", i1, i2);
will output:
13 42
(1) From the earliest days of Windows when we had to suffer with the bizarre x86 {tiny, small, medium, large, huge, gargantuan} (or whatever they were actually called) memory models, LP stood for long pointer.
With the Windows API you can usually tell what something is by looking at the variable name and type. The function:
BOOL BuildCommDCB (LPCTSTR szSettings, LPDCB lpDCB);
Has the types and arguments:
LPCTSTR aka a Long Pointer to C-style (Type) STRing. The type is really a TCHAR* which if you have UNICODE defined1 eventually is of the type wchar_t*. The variable name gives you an additional hint (sz or string, zero-terminated). A Unicode string would be LPCWSTR.
LPDCB which stands for Long Pointer to DCB. In the header which defines it, the type is defined as DCB* (Again the variable name re-inforces that.)
So the function takes a string, and a pointer to a structure, (think of this as a form of passing by reference), and returns a BOOL2 to tell you whether it was successful. If it wasn't successful, then the values in the DCB have not been set, and you shouldn't use them.
The rules are not always followed, but they are often enough that you can translate the API types into C types without too much effort.
For example if I tell you that a HMODULE is a module handle, you should know what a HDEVICE3 is.
As always the best place for information about what a function does, and what is expected of it's parameters is MSDN. The documentation says that the lpDCB parameter is,
A pointer to a DCB structure that receives the information.
To use this knowledge with the example function:
DCB dcb;
if (BuildCommDCB(L"Settings", &dcb))
{
// dcb is valid.
}
else
{
// dcb is uninitialized garbage
}
References:
Windows Types
BuildCommDCB at MSDN
1You do have unicode defined, right?
2A word of warning, BOOL is not bool
3A handle to a device of course.
As per this, the second parameter is _Inout_ LPDCB lpDCB, which is a pointer. This situation is like any other pass by pointer/reference case, where information is returned out of function using a reference
I am trying to convert a std::string to a TCHAR* for use in CreateFile(). The code i have compiles, and works, but Visual Studio 2013 comes up with a compiler warning:
warning C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'
I understand why i get the warning, as in my code i use std::copy, but I don't want to define D_SCL_SECURE_NO_WARNINGS if at all possible, as they have a point: std::copy is unsafe/unsecure. As a result, I'd like to find a way that doesn't throw this warning.
The code that produces the warning:
std::string filename = fileList->getFullPath(index);
TCHAR *t_filename = new TCHAR[filename.size() + 1];
t_filename[filename.size()] = 0;
std::copy(filename.begin(), filename.end(), t_filename);
audioreader.setFile(t_filename);
audioreader.setfile() calls CreateFile() internally, which is why i need to convert the string.
fileList and audioreader are instances of classes i wrote myself, but I'd rather not change the core implementation of either if at all possible, as it would mean I'd need to change a lot of implementation in other areas of my program, where this conversion only happens in that piece of code. The method I used to convert there was found in a solution i found at http://www.cplusplus.com/forum/general/12245/#msg58523
I've seen something similar in another question (Converting string to tchar in VC++) but i can't quite fathom how to adapt the answer to work with mine as the size of the string isn't constant. All other ways I've seen involve a straight (TCHAR *) cast (or something equally unsafe), which as far as i know about the way TCHAR and other windows string types are defined, is relatively risky as TCHAR could be single byte or multibyte characters depending on UNICODE definition.
Does anyone know a safe, reliable way to convert a std::string to a TCHAR* for use in functions like CreateFile()?
EDIT to address questions in the comments and answers:
Regarding UNICODE being defined or not: The project in VS2013 is a win32 console application, with #undef UNICODE at the top of the .cpp file containing main() - what is the difference between UNICODE and _UNICODE? as i assume the underscore in what Amadeus was asking is significant.
Not directly related to the question but may add perspective: This program is not going to be used outside the UK, so ANSI vs UNICODE does not matter for this. This is part of a personal project to create an audio server and client. As a result you may see some bits referencing network communication. The aim of this program is to get me using Xaudio and winsock. The conversion issue purely deals with the loading of the file on the server-side so it can open it and start reading chunks to transmit. I'm testing with .wav files found in c:/windows/media
Filename encoding: I read the filenames in at runtime by using FindFirstFileA() and FindNextFileA(). The names are retrieved by looking at cFilename in a WIN32_FIND_DATAA structure. They are stored in a vector<string> (wrapped in a unique_ptr if that matters) but that could be changed. I assume this is what Dan Korn means.
More info about the my classes and functions:
The following are spread between AudioReader.h, Audioreader.cpp, FileList.h, FileList.cpp and ClientSession.h. The fragment above is in ClientSession.cpp. Note that in most of my files i declare using namespace std;
shared_ptr<FileList> fileList; //ClientSession.h
AudioReader audioreader; //ClientSession.h
string _storedpath; //FileList.h
unique_ptr<vector<string>> _filenames; //FileList.h
//FileList.cpp
string FileList::getFullPath(int i)
{
string ret = "";
unique_lock<mutex> listLock(listmtx);
if (static_cast<size_t>(i) < _count)
{
ret = _storedpath + _filenames->at(i);
}
else
{
//rather than go out of bounds, return the last element, as returning an error over the network is difficult at present
ret = _storedpath + _filenames->at(_count - 1);
}
return ret;
}
unique_ptr<AudioReader_Impl> audioReaderImpl; //AudioReader.h
//AudioReader.cpp
HRESULT AudioReader::setFile(TCHAR * fileName)
{
return audioReaderImpl->setFile(fileName);
}
HANDLE AudioReader_Impl::fileHandle; //AudioReader.cpp
//AudioReader.cpp
HRESULT AudioReader_Impl::setFile(TCHAR * fileName)
{
fileHandle = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
return HRESULT_FROM_WIN32(GetLastError());
}
if (SetFilePointer(fileHandle, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
return HRESULT_FROM_WIN32(GetLastError());
}
return S_OK;
}
If you do not need to support the string containing UTF-8 (or another multi-byte encoding) then simply use the ANSI version of Windows API:
handle = CreateFileA( filename.c_str(), .......)
You might need to rejig your code for this as you have the CreateFile buried in a function that expects TCHAR. That's not advised these days; it's a pain to splatter T versions of everything all over your code and it has flow-on effects (such as std::tstring that someone suggested - ugh!)
There hasn't been any need to support dual compilation from the same source code since about 1998. Windows API has to support both versions for backward compatibility but your own code does not have to.
If you do want to support the string containing UTF-8 (and this is a better idea than using UTF-16 everywhere) then you will need to convert it to a UTF-16 string in order to call the Windows API.
The usual way to do this is via the Windows API function MultiByteToWideChar which is a bit awkward to use correctly, but you could wrap it up in a function:
std::wstring make_wstring( std::string const &s );
that invokes MultiByteToWideChar to return a UTF-16 string that you can then pass to WinAPI functions by using its .c_str() function.
See this codereview thread for a possible implementation of such a function (although note discussion in the answers)
The root of your problem is that you are mixing TCHARs and non-TCHARs. Even if you get it to work on your machine, unless you do it precisely right, it will fail when non-ASCII characters are used in the path.
If you can use std::tstring instead of regular string, then you won't have to worry about format conversions or codepage versus Unicode issues.
If not, you can use conversion functions like MultiByteToWideChar but make sure you understand the encoding used in the source string or it will just make things worse.
Try this instead:
std::string filename = fileList->getFullPath(index);
#ifndef UNICODE
audioreader.setFile(filename.c_str());
#else
std::wstring w_filename;
int len = MultiByteToWideChar(CP_ACP, 0, filename.c_str(), filename.length(), NULL, 0);
if (len > 0)
{
w_filename.resize(len);
MultiByteToWideChar(CP_ACP, 0, filename.c_str(), filename.length(), &w_filename[0], len);
}
audioreader.setFile(w_filename.c_str());
#endif
Alternatively:
std::string filename = fileList->getFullPath(index);
#ifndef UNICODE
audioreader.setFile(filename.c_str());
#else
std::wstring_convert<std::codecvt<wchar_t, char, std::mbstate_t>> conv;
std::wstring w_filename = conv.from_bytes(filename);
audioreader.setFile(w_filename.c_str());
#endif
I need a function that is supplied a LPTSTR and an enumerated value, constructs a string based on the value and puts it in the LPTSTR.
I've written the following function which uses an array of names indexed by an enumerated value:
bool GetWinClassName(const int &WinType, LPTSTR *className, const int bufSize)
{
bool allOk = true;
LPTSTR tempName = new TCHAR[bufSize];
_stprintf_s(tempName, bufSize, TEXT("Win%sClass"), g_WinNames[WinType]);
std::cout << (char*)tempName << std::endl;
if (FAILED(StringCchCopy(*className, (bufSize+1)*sizeof(TCHAR), tempName)))
{
allOk = false;
}
delete[] tempName;
return allOk;
}
(Originally I just had the _stprintf_s line using className instead of tempName, this has been broken up to find where the error lies.)
The above code compiles in VC2010 Express but gives an unhandled exception: "Access violation writing" to (presumably) *className when it tries to execute the StringCchCopy line.
I can get this to work by doing
className = new TCHAR[bufSize];
before calling the function (with a matching delete[] after it) but do I really need to do that each time I want to call the function?
I understand where the problem lies but not why which is hampering my efforts to come up with a workable solution. The problem appears to me to be that I can't put something in the LPTSTR (via _stprintf_s or StringCchCopy) unless I allocate it some memory by using new TCHAR[bufSize]. I've tried assigning it an intial value of exactly the same size but with the same results which is leading me to think that the memory allocation actually has nothing to do with it. Is it then somehow casting my LPTSTR into a TCHAR[]? I don't see how that's possible but at this stage, I'd believe anything.
Can someone please explain what I'm doing wrong? (Or at least where my understanding is wrong.) And a probably related question is why is my std::cout only showing the first character of the string?
wstring winClassName( int const winType )
{
return wstring( L"Win" ) + g_WinNames[winType] + L"Class";
}
But I'm just completely baffled why you have that global array of names etc.: it's probably a design level error.
do I really need to do that each time I want to call the function?
An LPTSTR value is not a string object, it is simply a pointer-to-TCHAR. If you do not allocate a buffer, where do you think the characters will go? You must make sure that the className pointer argument points to a memory buffer that you can write to. Whether you allocate a new buffer each time is up to you.
As Alf implies, a better alternative is to avoid the direct use of pointers and dynamically allocated arrays altogether, and return a string object.
why is my std::cout only showing the first character of the string?
Use std::wcout instead if UNICODE is defined.
I'm a Javascript developer, so go easy on me! I am trying to write just a patch of C++ to enable printing on a framework. I'm compiling with Unicode, and based on my research, that is what is messing me up.
I think this is a relatively simple thing that I'm over complicating. The application has a std::string that contains the current printer name. The script first checks if it is unset (if it is it utilizes GetDefaultPrinter which outputs a LPTSTR). Finally, the script takes either than std::string or the LPTSTR and converts it to a LPCTSTR for CreateDC.
Here is my code:
std::string PrinterName = window->getPrinter();
LPDWORD lPrinterNameLength;
LPWSTR szPrinterName;
LPCTSTR PrinterHandle;
if (PrinterName == "unset") {
GetDefaultPrinter( szPrinterName, &lPrinterNameLength );
PrinterHandle = szPrinterName; //Note sure the best way to convert here
} else {
PrinterHandle = PrinterName.c_str();
}
HDC hdc = CreateDC( L"WINSPOOL\0", PrinterHandle, NULL, NULL);
When compiling, I only get conversions errors. Such as
Cannot convert parameter 2 from LPDWORD * to LPDWORD (GetDefaultPrinter)
and
Cannot convert from 'const char *' to 'LPCTSTR' (On the PrinterHandle = PrinterName.c_str() line)
I've done quite a bit of SO research on this, but haven't come up with a concrete solution.
Any help is greatly appreciated!
Even if you're compiled for "Unicode" (wide characters strings), you can call the "ANSI" (narrow characters strings) versions of the API functions. Windows will do the conversions for you and call the wide character version under the covers.
For example, for most Windows APIs like CreateDC, there isn't actually a function with that name. Instead, there's a macro named CreateDC that expands to either CreateDCA or CreateDCW, which are the actual function names. When you're compiled for "Unicode", the macros expand to the -W versions (which are the native ones in all modern versions of the OS. Nothing prevents you from explicitly calling either version, regardless of whether you're compiled for Unicode. In most cases, the -A version will simply convert the narrow strings to wide ones for you and then call the corresponding -W version. (There are some caveats here related to creating windows, but I don't think they apply to DCs.)
std::string PrinterName = window->getPrinter();
if (PrinterName == "unset") {
char szPrinterName[MAX_PATH]; // simplified for illustration
DWORD cchPrinterNameLength = ARRAYSIZE(szPrinterName);
GetDefaultPrinterA(szPrinterName, &cchPrinterNameLength);
PrinterName = szPrinterName;
}
HDC hdc = CreateDCA("WINSPOOL", PrinterName.c_str(), NULL, NULL);
First of all, as mentioned in the comments, the proper way is to make a DWORD and pass the address:
DWORD lpPrinterNameLength;
...
GetDefaultPrinter(..., &lpPrinterNameLength);
Why it's like that is so that it can use and change a number:
On input, specifies the size, in characters, of the pszBuffer buffer. On output, receives the size, in characters, of the printer name string, including the terminating null character.
It would just take a DWORD, but the function changes the number in the variable passed in, so the function needs the address of the variable to change in order for those changes to reflect back to the caller.
Secondly, since window->getPrinter() returns a narrow string and you're using UNICODE, which makes the functions take wide strings, you should convert from the narrow string into a wide one. There are several ways to do this (such as the really easy one mentioned in ildjarn's comment), and even this one is slightly better with C++11, though the aforementioned note applies even better with that, but I'll use MultiByteToWideChar and C++03:
std::wstring narrowToWide(const std::string &narrow) {
std::vector<wchar_t> wide;
int length = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, narrow.c_str(), -1, NULL, 0);
if (!length) {
//error
}
wide.resize(length);
if (!MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, narrow.c_str(), -1, &wide[0], length)) {
//error, should probably check that the number of characters written is consistent as well
}
return std::wstring(wide.begin(), wide.end());
}
...
std::wstring PrinterName = narrowToWide(window->getPrinter());
//rest is same, but should be L"unset"
CreateDC( L"WINSPOOL\0", PrinterHandle, NULL, NULL);
So the GetWindowText is declared on MSDN as follows:
int GetWindowText(
HWND hWnd,
LPTSTR lpString,
int nMaxCount
);
However for the code to work we have to declare the second parameter as
TCHAR[255] WTitle;
and then call the function GetWindowText(hWnd,Wtitle,255);
The LPTSTR is a pointer to an array of tchar, so declaring LPTSTR is similar to declaring TCHAR[]? It doesn't work this way though.
When using TCHAR[] the program returns valid GetWindowText result (it is an integer equal to the number of symbols in the title). The question is : how can I get the exact title out of TCHAR[] ? Code like
TCHAR[255] WTitle;
cout<< WTitle;
or
cout<< *Wtitle;
returns numbers. How can I compare this with a given string?
TCHAR[4] Test= __T("TEST")
if (WTitle == Test) do smth
doesn't work also.
Wow, let's see where to start from.
First off, the declaration of WTitle needs to look like this:
TCHAR WTitle[255];
Next, if cout is not working write, it's because you are in Unicode mode so you need to do this:
wcout << WTitle;
Or to fit better with the whole tchar framework, you can add this (actually, I'm surprised that this is not already part of tchar.h):
#ifdef _UNICODE
#define tcout wcout
#else
#define tcout cout
#endif
and then use:
tcout << WTitle;
OK, a few definitions first.
The 'T' types are definitions that will evaluate to either CHAR (single byte) or WCHAR (double-byte), depending upon whether you've got the _UNICODE symbol defined in your build settings. The intent is to let you target both ANSI and UNICODE with a single set of source code.
The definitions:
TCHAR title[100];
TCHAR * pszTitle;
...are not equivalent. The first defines a buffer of 100 TCHARs. The second defines a pointer to one or more TCHARs, but doesn't point it at a buffer. Further,
sizeof(title) == 100 (or 200, if _UNICODE symbol is defined)
sizeof(pszTitle) == 4 (size of a pointer in Win32)
If you have a function like this:
void foo(LPCTSTR str);
...you can pass either of the above two variables in:
foo(title); // passes in the address of title[0]
foo(pszTitle); // passes in a copy of the pointer value
OK, so the reason you're getting numbers is probably because you do have UNICODE defined (so characters are wide), and you're using cout, which is specific to single-byte characters. Use wcout instead:
wcout << title;
Finally, these won't work:
TCHAR[4] Test == __T("TEST") ("==" is equality comparison, not assignment)
if (WTitle == Test) do smth (you're comparing pointers, use wcscmp or similar)
Short answer: Unless you're coding for Win98, use wchar_t instead of TCHAR and wcout instead of cout
Long version:
The TCHAR type exists to allow for code to be compiled in multiple string modes. For example supporting ASCII and Unicode. The TCHAR type will conditionally compile to the appropriate character type based no the setting.
All new Win systems are Unicode based. When ASCII strings are passed to OS functions, they are converted to unicode and the call the real function. So it's best to just use Unicode throughout your application.
Use _tcscmp or a variant (which takes in the number of characters to compare). http://msdn.microsoft.com/en-us/library/e0z9k731.aspx
Like:
if (_tcscmp(WTitle, Test) == 0) {
// They are equal! Do something.
}
In C, wchar_t is a typedef for some integer type (usually short int). In C++, it's required to be a separate type of its own -- but Microsoft's compilers default to using a typedef for it anyway. To make it a separate type of its own, you need to use the /Zc:wchar_t compiler switch. Offhand, I don't know if that will entirely fix the problem though -- I'm not sure if the library has real overloads for wchar_t as a native type to print those out as characters instead of short ints.
Generally speaking, however, I'd advise against messing with Microsoft's "T" variants anyway -- getting them right is a pain, and they were intended primarily to provide compatibility with 16-bit Windows anyway. Given that it's now been about 10 years since the last release in that line, it's probably safe to ignore it in new code unless you're really sure at least a few of your customers really use it.