0

I'm new to using Visual Studio and need to compile an application but I'm getting the error: error C2440: '=': cannot convert from 'const char *' to 'LPCWSTR' on line:

std::string open_file_dialog(
    std::string title,
    std::string filter)
{
    char filename[MAX_PATH];

    OPENFILENAME ofn;
    ZeroMemory(&filename, sizeof(filename));
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = NULL;
    ofn.lpstrFilter = filter.c_str();
    ofn.lpstrFile = filename;

I believe it might have to do with my project settings as the source code I am looking at should compile as it is. However, I'm not 100% sure. Can anyone help me out here?

stdcerr
  • 13,725
  • 25
  • 71
  • 128

2 Answers2

3

What you need to know about the windows API is that it comes in 2 flavors ,namely UNICODE flavor and non-UNICODE flavor.

When you include windows.h

the flavor selected depends on whether UNICODE is defined.

Many if not most WINAPI structures and function are just macros that basically just add either a W or an A to the macro-name to get the real name of the thing you want.

The UNICODE flavor requires character types of wchar_t and non-UNICODE takes char types (or pointers to them).

So you either must use the non-macro names for structs and/or functions or adjust your usage of types to the required macro-definition (in your case use std::wstring in stead of std::string).

engf-010
  • 3,980
  • 1
  • 14
  • 25
  • Thast's what I meant - so I guess I need to select **UNICODE** or **non**-UNICODE somewhere in the project settings – stdcerr Dec 13 '18 at 22:49
  • I found it! Project->Proprieties->Configuration Properties/General->Character Set set to **Use Multi-Byte Character Set** – stdcerr Dec 13 '18 at 22:52
  • 1
    @cerr :that is the usual way to approach it ,but there are other (better) ways. – engf-010 Dec 13 '18 at 22:52
  • 2
    @cerr: Yes. That's the one. The one you *most definitely* do not want. File names are outside your control. Using ANSI encoding will *inevitably* fail. Use Unicode. – IInspectable Dec 13 '18 at 22:53
  • 2
    @cerr The simpler solution is to just use the `A` version of affected APIs/structs directly (to match your use of `std::string`), then you don't have to worry about configuring a charset at the project level at all. `std::string open_file_dialog(...) { ...; OPENFILENAMEA ofn; ... GetOpenFileNameA(&ofn); ... }` – Remy Lebeau Dec 13 '18 at 23:10
  • @cerr: No ,you should not mess with 'Character set'. I can't remember when and where ,but a long time ago somewhere it was advised not to use multibyte character set. – engf-010 Dec 13 '18 at 23:25
  • @rem: How does this *"simple solution"* pan out when the user selects a file, that cannot be represented in the currently active ANSI encoding? – IInspectable Dec 14 '18 at 06:58
  • @IInspectable the API will either fail, or return string(s) where unencodable characters are replaced with `?`. To avoid that, the OP would have to use the `W` version of the API, but then decide whether to change the rest of the code to use `std::wstring` or UTF-8 encoded `std::string`. – Remy Lebeau Dec 14 '18 at 08:35
  • @rem: Failure is not a solution, however simple. – IInspectable Dec 14 '18 at 09:52
0

You probably have UNICODE activated so OPENFILENAME becomes OPENFILENAMEW, not OPENFILENAMEA which is why your ofn.lpstrFilter = filter.c_str(); fails.

lpstrFilter is a wchar_t* in the W version.

You should probably stick with UNICODE and change to use std::wstrings which is gets you the best access to the WinAPI. Some functions work differently (worse) in A (Ansi) mode.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108