-1

I am still kinda bad in c++ so pls dont mind my bad code or my missing knowledge. The project is about chosing a file and the paste it in the console for the user to read and i thought the best way would be using a dialog window (and i get more practice using the winapi).

Here my code for the window:

OPENFILENAMEA NameOfFile;
ZeroMemory(&NameOfFile, sizeof(NameOfFile));
NameOfFile.nFileOffset = 1;
char szFile[260];
NameOfFile.lpstrFile[0] = '\0';
NameOfFile.lpstrFile = szFile;
NameOfFile.nMaxFile = 4096;
NameOfFile.Flags = OFN_ALLOWMULTISELECT;
if (GetOpenFileName(&NameOfFile)) {
    
    cout << "opened";
}

Now the wierd thing. The Programm crashes with the error "-1073741819". Google said its an access violation of smth (no clue what exactly it means).

When i comment out the ZeroMemory function i got a linker and compiler error that NameOfFile is apparently not initialized??? (but if its not commented it compiles normally?!)

wohlstad
  • 12,661
  • 10
  • 26
  • 39
Yù dāo
  • 1
  • 3
  • @wohlstad why exactly is the data in szfile uninitialized? and what would fix the problem? i tried to initilieze through "= {}" but that didnt work either – Yù dāo Jan 16 '23 at 10:44
  • Added a complete answer. The initialization of `szFile` is done implicitly, by modifying `NameOfFile.lpstrFile[0]`, where `lpstrFile` points to `szFile`. See my answer for details. – wohlstad Jan 16 '23 at 10:57
  • I rolled back because the question should not be changed after you have valid answer(s). Please post a new one. – wohlstad Jan 16 '23 at 11:30

3 Answers3

1

There are several issues in your code:

  1. You need to set the lStructSize field of your OPENFILENAMEA variable.
  2. You need to swap the 2 lines setting NameOfFile.lpstrFile, so that the pointer that you access (in order to write the zero termination) will point to a valid buffer.
  3. NameOfFile.nMaxFile should be set to the size of the filename pointer by lpstrFile, i.e. the sizeof(szFile).
  4. In order to set the file names filter, you can set lpstrFilter and nFilterIndex. The example below enabled to select either all or txt files.

Fixed version:

#include <Windows.h>
#include <iostream>

int main()
{
    OPENFILENAMEA NameOfFile;
    ZeroMemory(&NameOfFile, sizeof(NameOfFile));
    NameOfFile.lStructSize = sizeof(NameOfFile);   // Item 1 above
    char szFile[260];
    NameOfFile.lpstrFile = szFile;                 // Item 2 above
    NameOfFile.lpstrFile[0] = '\0';                // Item 2 above 
    NameOfFile.nMaxFile = sizeof(szFile);          // Item 3 above
    NameOfFile.Flags = OFN_ALLOWMULTISELECT;
    NameOfFile.lpstrFilter = "All\0*.*\0Text\0*.TXT\0"; // Item 4 above
    NameOfFile.nFilterIndex = 1;                        // Item 4 above
    if (GetOpenFileNameA(&NameOfFile))
    {
        std::cout << "opened " << szFile << std::endl;
    }
}

For additional info you can see the example in the MS documentation here under the "Opening a File" section.
You can also have a look at the OPENFILENAMEA structure for the list of fields you can potentially set for the API.

A side note: better to avoid using namespace std - see here Why is "using namespace std;" considered bad practice?.

wohlstad
  • 12,661
  • 10
  • 26
  • 39
  • Just for me to understand the code in the future and/or in other projects. why exactly do i need to define the struct size? – Yù dāo Jan 16 '23 at 11:09
  • And even tho i dont get any compiler or linker errors anymore i still get a random crash out of nowhere still with the same error code "-1073741819" – Yù dāo Jan 16 '23 at 11:12
  • The size of the struct is requied by windows api. I believe it is for verifying you were compiled with a version that matches the run time. – wohlstad Jan 16 '23 at 11:14
  • Do you still get a crash after using my code? – wohlstad Jan 16 '23 at 11:15
  • Running only my code snippet I couldn't reproduce your crash (whereas your original code crashed immediatly). So msybe the cause is another part of your code not shown here. Keep in mind that you should't change your question to invalidate existing answer(s). Post a new question instead. – wohlstad Jan 16 '23 at 11:22
  • sry for not reseting the question. i saw your comment a bit too late. Is a certained c++ retribution instalation needed to use commdlg.h? cause i tried your code seperate in a new project and it did crash for me again. – Yù dāo Jan 16 '23 at 13:21
  • I tried again and didn't get any crash. I only #included . However - in order to be able to select specific files, you should set the filter. I updated my answer - please have a look and try. – wohlstad Jan 16 '23 at 13:29
  • As you can see my answer contains now a complete program you can build and run. Please try it. – wohlstad Jan 16 '23 at 13:35
-1

So in the end its just the fault of one single line of code.

NameOfFile.lpstrFile[0] = '\0';

it was the fault for the whole thing and it was my mistake for pasting it from another stack overflow post without knowing what it does (it had an explanation that i didnt really understand)

just deleting it fixed the problem

Yù dāo
  • 1
  • 3
  • I don't think this is correct. When you remove setting the `lStructSize` field the api should always fail. And the fault is not in this line, but in the fact that it was executed before the assignment `NameOfFile.lpstrFile = szFile;`. BTW I guess running the code example in my answer did not crash. – wohlstad Jan 16 '23 at 14:17
  • Also your initialization of `nMaxFile` is incorrect. From the documentation it should be _"The size, in characters, of the buffer pointed to by lpstrFile."_. I.e. `sizeof(szFile)` as you can see in my answer. – wohlstad Jan 16 '23 at 15:02
  • @Yù dāo: That might have been pure luck... – Christian Severin Jan 17 '23 at 13:39
  • well yes could be. i got into more problems later on – Yù dāo Jan 18 '23 at 10:50
-1

here the code i use from now on. I fixed the problem with LPWSTR trough making szFile a TCHAR and converting it into LPWSTR in FILE. Not the best but enoght for me right now.

LPWSTR FILE{};
OPENFILENAME NameOfFile;
ZeroMemory(&NameOfFile, sizeof(NameOfFile));
NameOfFile.lStructSize = sizeof(NameOfFile);
TCHAR szFile[MAX_PATH];
NameOfFile.lpstrFile = szFile;
NameOfFile.nMaxFile = sizeof(szFile);
NameOfFile.Flags = OFN_ALLOWMULTISELECT;
if (GetOpenFileName(&NameOfFile))
{
    FILE = (LPWSTR)szFile;
}

For everyone that wants to paste this, don´t forget the file filters. Otherwise you wont be able to see any files if the windows opens for you. More of that in the documentation

Yù dāo
  • 1
  • 3
  • 1
    It's actually still wrong. MS code sample mentions specifically (https://learn.microsoft.com/en-us/windows/win32/dlgbox/using-common-dialog-boxes): `Set lpstrFile[0] to '\0' so that GetOpenFileName does use the contents of szFile to initialize itself.`. My asnwer shows that, as well as set the filter as required. – wohlstad Jan 18 '23 at 14:18
  • Also you can use `GetOpenFileNameA` to spare you the need for dealing with side characters (if you don't really need it, as it seems from the code your posted in the question). – wohlstad Jan 18 '23 at 14:19