I made some code in an empty project (visual studio) it uses Windows.h
i want to put this program inside my c++ windows form application.
so i made a class for it. odd thing is the code gives me an error
#include "ImageCompiler.h"
ImageCompiler::ImageCompiler()
{
}
void ImageCompiler::find_images()
{
}
std::vector<string> ImageCompiler::get_all_files_names_within_folder(string folder)
{
std::vector<std::string> names;
std::string search_path = folder + "/*.*";
WIN32_FIND_DATA fd;
HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
names.push_back(fd.cFileName);
}
} while (::FindNextFile(hFind, &fd));
::FindClose(hFind);
}
return names;
}
it says that search_path (const char *) does not match argument (LPCWSTR)
there is nothing special in the header file (only #include Windows.h)
and some other class things.
if i create a empty program with just windows.h and this code it will work.
but not in the windows form application even when its in another file and
they don't include each other. i don't understand this.
i'm actually really stupid and bad in programming so its probably a stupid
mistake. i hope someone can help me. i can give you the code from the
Myform.h but i don't think that will help.
in windows.h the type strings and string pointer type aliases are defined according to whether or not you are building with or without Unicode support. In this case the W (for wide) in LPCWSTR indicates Unicode build, so char* interfaces are not compatible.
The simplest solution if you don't need it is to switch off Unicode/wide-character string support for the build. I sm not sure however if that is possible for C++/CLI, in which case use 'wchar` interfaces where necessary.
An empty project including windows.h compiles simply because you will not have used any interfaces. If there is no code, there is no attempt to assign incompatible types, so no error.
To begin with, if you're using Managed C++ (C++/CLI), use it as much as possible. Listing all files with Managed C++ is possible and much easier than with unmanaged C++.
Managed C++ uses UNICODE. What is unicode? Shortly, it let's you use letters other than english. In your code you're not using unicode. That means if you happend to find a file which was, say, named with russian letters, you would not get its actual name.
In windows.h there are functions and variables unicode and non-unicode. Unicode version functions differ from non-unicode in name by having letter W at the end of their names in most cases. You can always find it by googling "function or variable name unicode". So you can use them by adding W to your function, for example FindFirstFileW instead of FileFirstFileA. Which your compiler is directing to by accessing FindFirstFile, but you could change that (make compiler seek unicode functions automatically) depeding on what program for compiling your code you're using. Google it.
To answer your question... this is how you edit your code:
all strings to wstrings
WIN32_FIND_DATA to WIN32_FIND_DATAW
"/*.*" to L"/*.*"
Find... functions to Find...W
Related
On Windows I'm trying to use one of the variants of LoadLibrary() to open a dll previously written to an std::filesystem::path with an ofstream.
Note: I know the dll is written correctly as I can use it in the standard fashion by linking to it at runtime.
I've been trying to combine the methods from the two answers below.
How to convert std::string to LPCSTR?
how to convert filesystem path to string
This seems like it should be pretty basic but with anything I've tried so far I either get an error about conversion to LPCSTR or something like C2228: left of '.c_str' must have class/struct/union which I am baffled by.
Here's a simple example:
// Assuming I have
// std::filesystem::path path1
// correctly set, I should be able to directly access it in
// a number of ways; i.e. path1.c_str(), path1.string.c_str(), etc.
// in order to pass it the function or a temp variable.
// However direct use of it in LoadLibrary() fails with the C2228 error.
HINSTANCE hGetProcIDDLL = LoadLibrary(path1.c_str());
I've tried avoiding the macro and calling LoadLibraryA() directly with no luck.
I've also tried various ways of passing path1 with path1.string(), path1.string.c_str(), path1.wstring(), etc. with no luck.
I've also tried using a temp variable in a number of ways to avoid the cast within LoadLibrary().
LPCSTR temp_lpcstr = path1.c_str(); // Also tried things like path1.string() path1.string.c_str()
// Also tried just using a temp string...
std::string temp_string = path1.string(); // and variants.
I'm willing to try playing with the encoding (like path1.u8string() etc.) but I think it shouldn't be necessary with use of LoadLibraryA() directly.
I'm trying to avoid C casts and would prefer a c++ static_ or dynamic_ but I'll use anything that works.
Any help is appreciated.
Thanks in advance.
UPDATE
#eryk-sun's comment and #Gulrak's answer solved it for me.
It looks like with my setup, path1.c_str() alone is wchar_t but the LoadLibrary() macro was not picking that up and directing it to LoadLibraryW() as it should.
Note: For anyone else who might stumble onto this in the future here's more details of my specific setup. I'm using the MSVC compiler from 16.1.0 (~VS2019) but that's getting called from VSCode and CMake. I'm not explicitly defining _UNICODE however VSCode's intellisense certainly thinks it's been defined somewhere and points me to LoadLibraryA(). However, I think the compiler is not actually seeing that define so it interprets path1.c_str() as a wchar_t.
Actually on Windows you should be able to use LoadLibraryW(path1.c_str()) as on Windows the returned type of std::filesystem::path::c_str() should be a const wchar_t* so it's a good fit for the LoadLibraryW expected LPCWSTR.
As for the error of C2228 my guess is, you tried path1.string.c_str() as given by your comment, wich should have been path1.string().c_str(). That would give you a LPCSTR compatible string for LoadLibaryA, but if there is a chance of Non-ASCII in your path I would suggest using the explicit LoadLibaryW version.
In any way: When interfacing WinAPI with std::filesystem::path you should use the explicit A/W-Version to make your code safe independent of the state of _UNICODE, and I allways suggest the *W versions.
You should use string member function of path class which returns std::string. Then call c_stron the returned string.
std::filesystem::path path /* = initialization here */;
std::string str = path.string();
/* some handle = */ LoadLibrary(str.c_str());
Unfortunately I have been tasked with compiling an old C++ DLL so that it will work on Win 7 64 Bit machines. I have zero C++ experience. I have muddled through other issues, but this one has stumped me and i have not found a solution elsewhere. The following code is throwing a C2440 compiler error.
The error: "error C2440: '' : cannot convert from 'std::_String_iterator<_Elem,_Traits,_Alloc>' to 'LPCTSTR'"
the code:
#include "StdAfx.h"
#include "Antenna.h"
#include "MyTypes.h"
#include "objbase.h"
const TCHAR* CAntenna::GetMdbPath()
{
if(m_MdbPath.size() <= 0) return NULL;
return LPCTSTR(m_MdbPath.begin());
}
"m_MdbPath" is defined in the Antenna.h file as
string m_MdbPath;
Any assistance or guidance someone could provide would be extremely helpful. Thank you in advance. I am happy to provide additional details on the code if needed.
std::string has a .c_str() member function that should accomplish what you're looking for. It will return a const char* (const wchar_t* with std::wstring). std::string also has an empty() member function and I recommend using nullptr instead of the NULL macro.
const TCHAR* CAntenna::GetMdbPath()
{
if(m_MdbPath.empty()) return nullptr;
return m_MdbPath.c_str();
}
The solution:
const TCHAR* CAntenna::GetMdbPath()
{
if(m_MdbPath.size() <= 0) return NULL;
return m_MdbPath.c_str();
}
will work if you can guarantee that your program is using the MBCS character set option (or if the Character Set option is set to Not Setif you're using Visual Studio), since a std::string character type will be the same as the TCHAR type.
However, if your build is UNICODE, then a std::string character type will not be the same as the TCHAR type, since TCHAR is defined as a wide character, not a single-byte character. Thus returning c_str() will give a compiler error. So your original code, plus the tentative fix of returning std::string::c_str() may work, but it is technically wrong with respect to the types being used.
You should be working directly with the types presented to your function -- if the type is TCHAR, then you should be using TCHAR based types, but again, a TCHAR is a type that changes definition depending on the build type.
As a matter of fact, the code will fail miserably at runtime if it were a UNICODE build and to fix the compiler error(s), you casted to an LPCTSTR to keep the compiler quiet. You cannot cast a string pointer type to another string pointer type. Casting is not converting, and merely casting will not convert a narrow string into a wide string and vice-versa. You will wind up with at the least, odd characters being used or displayed, and worse, a program with random weird behavior and crashes.
In addition to this you never know when you really will need to build a UNICODE version of the DLL, since MBCS builds are becoming more rare. Going by your original post, the DLL's usage of TCHAR indicates that yes, this DLL may (or even has) been built for UNICODE.
There are a few alternate solutions that you can use. Note that some of these solutions may require you to make additional coding changes beyond the string types. If you're using C++ stream objects, they may also need to be changed to match the character type (for example, std::ostream and std::wostream)
Solution 1. Use a typedef, where the string type to use depends on the build type.
For example:
#ifdef UNICODE
typedef std::wstring tchar_string;
#else
typedef std::string tchar_string;
#endif
and then use tchar_string instead of std::string. Switching between MBCS and UNICODE builds will work without having to cast strin types, but requires coding changes.
Solution 2. Use a typedef to use TCHAR as the underlying character type in the std::basic_string template.
For example:
typedef std::basic_string<TCHAR> tchar_string;
And use tchar_string in your application. You get the same public interface as std::(w)string and this allows you to switch between MBCS and UNICODE build seamlessly (with respect to the string types).
Solution 3. Go with UNICODE builds and drop MBCS builds altogether
If the application you're building is a new one, then UNICODE is the default option (at least in Visual Studio) when creating a new application. Then all you really need to do is use std::wstring.
This is sort of the opposite of the original solution given of making sure you use MBCS, but IMO this solution makes more sense if there is only going to be one build type. MBCS builds are becoming more rare, and basically should be used only for legacy apps.
I have a function which takes two CHAR* as input viz. int _stdcall FileTrans(char* InFile, char* OutFile) in a DLL project.
In the function I'm just calling CopyFile(InFile, OutFile, false); after some process (not related to the files). But it says that it needs both inputs as LPCWSTR. I Googled it but couldn't find anything very interesting.
Like all Windows API functions that accept a string parameter, there are actually two variants of the CopyFile function:
CopyFileA is the ANSI version, which takes narrow (non-Unicode) strings in the system's default character set. Basically, it accepts parameters of type const char*, but the Windows headers use the typedef LPCSTR for this.
CopyFileW is the wide version, which takes Unicode strings. In order to do this, it accepts parameters of type w_char*, but the Windows headers use the typedef LPCWSTR for this (note the additional W in the typedef).
Then, depending on whether the UNICODE preprocessor macro is defined for your project (either in your code before you include the Windows headers, or in your project's properties in Visual Studio), the Windows headers define the unadorned CopyFile as either CopyFileA or CopyFileW. Naturally, if UNICODE is defined, CopyFile will be defined as the Unicode version CopyFileW. Otherwise, it will be defined as CopyFileA. The idea is that the call to the general CopyFile function is automatically resolved at compile time to the correct variant.
Of course, now that you understand all of that, you can mostly forget about it. In modern Windows programming, there is absolutely no reason to call the old ANSI versions of functions or to deal with narrow strings at all. Forget that char* can even be used as a string type—those strings are dead to you. The only strings you're going to be using from now on are Unicode strings, composed of wchar_t characters. Thus the UNICODE symbol should always be defined for your code, and you should only use the W version of Windows API functions.
Looking again at the prototype for the CopyFileW function (the same one you get when you call CopyFile with UNICODE defined), we see:
BOOL WINAPI CopyFile(LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,
BOOL bFailIfExists);
Recall that you learned above that LPCWSTR is just a typedef synonym for const wchar_t*, a C-style string that is composed of wide characters. You already know why the parameters are marked const: because the function doesn't modify those values.
And because you also learned above that these are the only types of strings that you should be using anymore, the next step is to modify your FileTrans function to accept wide strings (and make them const if it's not going to modify them):
int _stdcall FileTrans(const wchar_t* InFile, const wchar_t* OutFile);
Now, from inside of FileTrans, you can call CopyFile without any problems because you have the right type of strings.
But a bit of free, extra advice: never use raw C-style strings in C++. Always use the C++ string class, defined in the std namespace by the <string> header.
There are two common variants of this class, std::string and std::wstring. As before, the w refers to wide strings, which are the only type you want to use in Windows. So std::wstring is your new replacement for CHAR* throughout your code base.
Change your declaration of the FileTrans function to look like this:
#include <string>
// ...some other stuff...
int __stdcall FileTrans(const std::wstring& InFile, const std::wstring& OutFile);
Note that I've changed your original CHAR* parameters to constant references to std::wstring objects. Constant references work well here, since you're not going to be changing either of those values inside of the function.
If you're unclear on what constant means, how to use references, or how class types generally work in C++, please consult your favorite C++ book)—this is required knowledge for all C++ programmers. Remember that C++ is not the same language as C and therefore the same idioms do not apply. In many cases, there is a better way to do things, and this is certainly an example of such a case.
I'm slowly starting to get the hang of the _T stuff in Visual Studio 2008 c++, but a few things still elude me. I can see the benefit of the flexibility, but if I can't get the basics soon, I think I'll go back to the standard way of doing this - much less confusing.
The idea with the code below is that it scans the parameters for -d and then stores the text that follows that in the string variable fileDir. It also ignores any other parameters.
Any help is appreciated.
//Console application
Parameters::Parameters(int argc, _TCHAR* argv[])
{
_Tstring fileDir; // Is there some kind of _t variable to use here for a string?
for (int i = 0; i < argc; i = i + 1)
{
if (_tccmp(argv[i], _T("-d")) == 0) // this appeared to accept anything starting with -
{
i = i + 1;
fileDir = argv[i]
}
}
_tprintf("Parameter value found: %s\n", fileDir);
}
You can use _tstring to represent and std::string with a TCHAR parameter. Also, the name of the function is _tcscmp, not _tccmp so I don't see how that code snippet could even compile?
To be honest, I wouldn't bother with any of that, though. The whole TCHAR stuff was useful back when people were writing code that was to be portable between Windows 9X (which was Ansi internally) and Windows NT (which was/is Unicode internally). These days, there's very little benefit to using the macros.
If you want to do anything, you can switch to wchar_t entirely. That means prefixing string literals with "L", as in L"Some wide-char string" and using the 'w' versions of functions (e.g. std::wstring, wcscmp, etc). But even that might be considered overkill for many scenarios.
If you want to copy a string value and you're using MFC or ATL, your _Tstring can be CString.
If you want to copy a pointer value, your _Tstring can be LPTCSTR. (This works whether or not you're using MFC or ATL.)
As codeka said, your _tccmp needs to be _tcscmp. An alternative, if you're using MFC or ATL, is CString's Compare method.
You didn't show how the caller delivers parameter argv to your constructor. If argv came from your _tmain function, make sure the parameters to _tmain are correct.
I have a class which expects a LPCTSTR.
When i call :
new CFileImageLoader(_T("Splash02.png"))
OR
new CFileImageLoader("Splash02.png")
both don't work.
Why ?
I'm new to cpp...
Thanks
Jonathan d.
This issue is a combination of C++ issues and Windows specific issues.
C++ defines two types of strings, regular and wide. A regular string looks like:
const char *str = "regular string";
while a wide string looks like:
const wchar_t *wstr = L"wide string";
With just standard C++, you have to decide when you write your library whether to use regular or wide strings.
Windows has defined a pseudo type called tchar. With tchar you write something like:
LPCTSTR tstr = _T("regular or wide string");
Whether this is actually a regular (char *) or a wide (wchar_t *) string depends on whether you compile your code for Unicode or not.
Since the function is specified as taking an LPCTSTR, it needs to be called with the appropriate type for how you are compiling.
If you know you are only going to be building with or without Unicode support, you can skip all the TCHAR stuff and directly use either wchar_t or char respectively.
Since CFileImageLoader("Splash02.png") is not working, you must be compiling with Unicode support enabled. You can change that to CFileImageLoader(L"Splash02.png") and commit to always using Unicode or you can change it to CFileImageLoader(_T("Splash02.png")) and let the macro magic do the work.
"both don't work" - could you maybe be a tiny, tiny little bit more specific?
If you compile with _UNICODE defined, then the second shouldn't even compile.
You're also just passing a filename, not a full path. Maybe your image loader class can't find the file because it uses a differen CWD path as you expect. Try passing the full path instead.
Maybe your image library can't support to open PNG format file.
Try passing the full path instead.
Maybe you need to call some initialization functions which provide by your image library