News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Problems with GetOpenFileNameW

Started by x64Core, March 17, 2013, 08:32:39 AM

Previous topic - Next topic

x64Core

Hi guys, I have a problem with GetOpenFileNameW so want to know if anyone can given me any idea.
In a VC project with two winproc procedures , mainProc and Controlproc

This ControlProc is subclassing a control and calls to GetOpenFileNameW >

{
    switch(msg)
    {
    WM_COMMAND:
        // CHECK CONTROL HANDLE
        {
            OPENFILENAMEW    MYFILE;

            ZeroMemory(&MYFILE,sizeof(MYFILE));
            MYFILE.lStructSize = sizeof(MYFILE);
           
            //MYFILE.hwndOwner = NULL;
            MYFILE.lpstrFile = Buffer;
            MYFILE.lpstrFile[0] = L'\0';
            MYFILE.nMaxFile = MAX_PATH;
            MYFILE.lpstrFilter = StrFilterType;
            MYFILE.nFilterIndex = 1;
            MYFILE.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

            GetOpenFileNameW(&MYFILE);
        }
        break;
    }
    return CallWindowProcW((WNDPROC)ControlSC, hWnd, msg,wParam, lParam);   
}
   
all is ok, but when I press the Close button (title bar) the app is not closed because it has some still some thread running in the process
( threads which are created by such api ). I have tried several things ( creating aditional thread to call to the API function, assignment of owner, instance ) but without successful.
I know that GetOpenFileNameW is the problem because I have run the app withput any call to the function and the application is finishing correctly. also, I have checked with a thread viewer all thread which are created, and GetOpenFileName creates several threads.

well, it's c++ but i'm asking here because you guys have a lot of experience. any ideas? thanks.

EDIT>
I dont want to finish my app with ExitProcess obviously, nasty habit.

jj2007

You are up for some bug chasing...
- which OS? Win7-64?
- any strange things when looking at it with a debugger?
- Buffer is a wchar with MAX_PATH chars, i.e. 2*MAX_PATH bytes?
- tried to call HeapValidate before and after?
- same with OPENFILENAMEA?
- StrFilterType has a double zero delimiter? Tried with a nullstring?
- Can you create a small test app that shows this behaviour, and post the exe here?

x64Core

Quote from: jj2007 on March 17, 2013, 08:54:33 AM
You are up for some bug chasing...
- which OS? Win7-64?
- any strange things when looking at it with a debugger?
- Buffer is a wchar with MAX_PATH chars, i.e. 2*MAX_PATH bytes?
- tried to call HeapValidate before and after?
- same with OPENFILENAMEA?
- StrFilterType has a double zero delimiter? Tried with a nullstring?
- Can you create a small test app that shows this behaviour, and post the exe here?

Hi jochen

- Yes Win7 64bit but also, I have tested my app ( debug mode and rel mode ) on WinXP 32bit, win7 32bit, Win8 32bit and same problem
- well, normally I'm debugging in debug mode.I think that any difference with another debugger  :P
- is WCHAR buffer[MAX_PATH+1]; I think that it's ok
-
- yes
- I made this program and same problem  :

HMODULE GlobalInstance;
HWND hwMainWindow;
HWND hMainTab;
LONG TabControlSubClass;
HWND hUniqueButton;
WCHAR Buffer[MAX_PATH+1];

INT OpenFileDlg(PWCHAR StrFilterType, PWCHAR Buffer)
{
    OPENFILENAMEW    MYFILE;

    ZeroMemory(&MYFILE,sizeof(MYFILE));
    MYFILE.lStructSize = sizeof(MYFILE);

    MYFILE.hInstance = GetModuleHandleW(NULL);
    MYFILE.hwndOwner = NULL;
    MYFILE.lpstrFile = Buffer;
    MYFILE.lpstrFile[0] = L'\0';
    MYFILE.nMaxFile = MAX_PATH;
    MYFILE.lpstrFilter = StrFilterType;
    MYFILE.lpstrFileTitle = NULL;
    MYFILE.nMaxFileTitle = 0;
    MYFILE.nFilterIndex = 1;
    MYFILE.lpstrInitialDir = NULL;
    MYFILE.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    return GetOpenFileNameW(&MYFILE);
}



LRESULT CALLBACK TabProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case WM_COMMAND:
        if((HWND)lParam == hUniqueButton)
        {
            OpenFileDlg(L"jpg files \0*.jpg\0",Buffer);
        }
        break;

    }

    return CallWindowProcW((WNDPROC)TabControlSubClass, hWnd, message,wParam, lParam);
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
{
    case WM_DESTROY:
        SetWindowLongW(hMainTab, GWL_WNDPROC,(LONG) TabControlSubClass);
        PostQuitMessage(0);
        break;
    default:
            return DefWindowProc(hWnd, message, wParam, lParam);
}

return 0;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW    wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style         = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra     = 0;
wcex.cbWndExtra     = 0;
wcex.hInstance = hInstance;
wcex.hIcon         = NULL;
wcex.hCursor = 0;
wcex.hbrBackground =  (HBRUSH)COLOR_BTNSHADOW;
wcex.lpszMenuName = 0;
wcex.lpszClassName = L"TEST";
wcex.hIconSm = NULL;

return RegisterClassExW(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance)
{
    TCITEM    mTC = {0};


    hwMainWindow = CreateWindowW(L"TEST",L"WINDOW 1", DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU,
               CW_USEDEFAULT, CW_USEDEFAULT,300,300, NULL, NULL, hInstance, NULL);
     
    if (!hwMainWindow)
        return FALSE;

    hMainTab = CreateWindowW(L"SysTabControl32",0,WS_CHILDWINDOW | WS_VISIBLE,10,40,200,200,hwMainWindow,0,GlobalInstance,0);
    if(hMainTab)
    {
            hUniqueButton = CreateWindowW(L"button",L"OPEN",WS_CHILDWINDOW | WS_VISIBLE,20,40,120,40,hMainTab,0,0,0);

            TabControlSubClass = SetWindowLongW(hMainTab ,GWL_WNDPROC,(LONG) TabProc);

            /* All OK */
            ShowWindow(hMainTab, nCmdShow);
            UpdateWindow(hMainTab);
            return TRUE;

    }

    return FALSE;
}

int main()
{
    MSG            msg;
    GlobalInstance = GetModuleHandleW(0);
    MyRegisterClass(GlobalInstance);
    if (InitInstance (GlobalInstance, SW_SHOW))
    {
        while(GetMessageW(&msg, NULL, 0, 0) > 0)
        {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }       
    }
    return FALSE;
}



EDIT>

Exe in attahced

qWord

One problem that I see is that the main function is specified as entry point thus returning yields in only exiting that thread. Using ExitProcess at this point is correct. BTW, if compile your code as console application (because of main()), it works perfectly.
For all that thread (which are in an wait state), it seems to be common that they are not removed - maybe to speed up future usage (as a thread pool?).
MREAL macros - when you need floating point arithmetic while assembling!

x64Core

Quote from: qWord on March 17, 2013, 10:39:16 AM
One problem that I see is that the main function is specified as entry point thus returning yields in only exiting that thread. Using ExitProcess at this point is correct. BTW, if compile your code as console application (because of main()), it works perfectly.
For all that thread (which are in an wait state), it seems to be common that they are not removed - maybe to speed up future usage (as a thread pool?).
hello,
if the entrypoint is the problem then MASM code would fail too.
main() is the ep by default for console mode programs, but the compiler will add its library ( i'm trying to avoid this library too ).
I'm really not convinced by using ExitProcess  :P

qWord

Quote from: x64Core on March 17, 2013, 11:01:49 AMif the entrypoint is the problem then MASM code would fail too
they do not fail because we use ExitProcess() - you will find that these threads are also present for ASM programs.
Quote from: x64Core on March 17, 2013, 11:01:49 AMi'm trying to avoid this library too
it that case there is no way around using ExitProcess.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

Quote from: x64Core on March 17, 2013, 09:42:28 AMExe in attahced


I see. Inside OpenFile it throws an exception 6BA, but apparently you can ignore that (First-chance exception 0x000006BA: The RPC server is unavailable). I've debugged it with Olly until the ret, it then calls ExitThread.

If you let it go, the program terminates but one thread remains active.

If instead of continuing in ExitThread you set the origin some lines below to a push whatever, call ExitProcess, it exits without leaving threads open. Which confirms what qWord suggests.

So what's wrong with ExitProcess? Why do you want to avoid it?

x64Core

#7
alright thank you guys I really appreciate your help