Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C++
Hello
 
I have been trying to create a DLL in C++ using Visual Studio 2012. The aim is to convert the MFPLayer sample which uses the Microsoft Media Foundation to play a video file into a DLL that does the same thing. The MFPlayer samples is a win32 application and it compiles and runs.
 
The sample can be found in MFSamples.zip at :
http://archive.msdn.microsoft.com/mediafoundation
 
Previously I successfully created a Dll version of the BasicPlayback sample which also plays videos. I managed to call the dll functions from a c# application. I use the same procedure for this new dll.
 
However, MFPlayer sample doesn't work. The dll calls the following function
 
BOOL MainDialog::ShowDialog(HINSTANCE hinst)
{
    // Show the dialog. Pass a pointer to ourselves as the LPARAM
    INT_PTR ret = DialogBoxParam(
        hinst, 
        MAKEINTRESOURCE(m_nID), 
        NULL, 
        DialogProc, 
        (LPARAM)this
        );
 
    if (ret == 0 || ret == -1)
    {
        MessageBox( NULL, L"Could not create dialog", L"Error", MB_OK | MB_ICONERROR );
        return FALSE;
    }
 
    return (IDOK == ret);
}
 
After calling DialogBoxParam the DialogProc is called to handle several messages but the WM_INITDIALOG message is never sent.
 
Here's some of the other relevant code....
 
BOOL APIENTRY DllMain (HINSTANCE hInstance, DWORD reason, LPVOID reserved)
{
	g_hInstance = hInstance;
	return TRUE;
}
extern "C"
{
__declspec(dllexport) int PlayMovie()
{
    HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
 
    // Initialize the COM library.
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
 
    if (FAILED(hr))
    {
        MessageBox(NULL, L"CoInitialize failed.", NULL, MB_ICONSTOP);
        return 0;
    }
 
    // Initialize the common control library.
    INITCOMMONCONTROLSEX icc;
    icc.dwSize = sizeof(icc);
    icc.dwICC = ICC_STANDARD_CLASSES | ICC_BAR_CLASSES;
    if (!InitCommonControlsEx(&icc))
    {
        MessageBox(NULL, L"InitCommonControlsEx failed.", NULL, MB_ICONSTOP);
        CoUninitialize();
        return 0;
    }
 
    // Initialize our custom slider class.
    hr = Slider_Init();
    if (FAILED(hr))
    {
        MessageBox(NULL, L"Slider_Init failed.", NULL, MB_ICONSTOP);
        CoUninitialize();
        return 0;
    }
 
    // Create and show the dialog.
    MainDialog *pDlg = new (std::nothrow) MainDialog();
    if (pDlg == NULL)
    {
        MessageBox(NULL, L"Out of memory.", NULL, MB_ICONSTOP);
    }
    else
    {
        pDlg->ShowDialog(g_hInstance);
 
        delete pDlg;
    }
 
    CoUninitialize();
    return 0;
}
 
You will notice that I capture the HINSTANCE sent to DllMain and use this for the API calls. Play PlayMovie function is called from C#.
 
I have to say that I am completely new to windows programming and I might be missing something simple. However, I was hoping someone could give me some clues as to where to look.
 

In summary, the dll compiles. It is called from a c# application. It runs without error but the WM_INITDIALOG message is never sent to DialogProc. Any ideas..
 
Here's some additional information...
 
I put a breakpoint in DialogProc and get the following messages:
48 = WM_SETFONT 
85 = WM_NOTIFYFORMAT 
297 = WM_QUERYUISTATE  
144 = Not Defined
2 = WM_DESTROY 
130 = WM_NCDESTROY 
 
INT_PTR CALLBACK MainDialog::DialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    MainDialog *pDlg = 0;  // Pointer to the dialog class that manages the dialog 

    LRESULT lresult = 0;
 
    if (msg == WM_INITDIALOG)
    {
        // Get the pointer to the dialog object and store it in 
        // the window's user data

        SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)lParam);
 
        pDlg = (MainDialog*)lParam;
        if (pDlg)
        {
            pDlg->m_hDlg = hDlg;
            HRESULT hr = pDlg->OnInitDialog();
            if (FAILED(hr))
            {
                pDlg->EndDialog(0);
            }
        }
        return FALSE;
    }
 
    // Get the dialog object from the window's user data
    pDlg = (MainDialog*)(DWORD_PTR) GetWindowLongPtr(hDlg, DWLP_USER);
 
    if (pDlg != NULL)
    {
        switch (msg)
        {
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
            case IDOK:
            case IDCANCEL:
                pDlg->EndDialog(LOWORD(wParam));
                return TRUE;
 
            default:
                return pDlg->OnCommand((HWND)lParam, LOWORD(wParam), HIWORD(wParam));
            }
            break;
 
        case WM_NOTIFY:
            lresult = pDlg->OnNotify((NMHDR*)lParam);
 
            // The LRESULT from WM_NOTIFY can be meaningful. Store the result in DWLP_MSGRESULT.
            SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LONG_PTR)lresult);
            return TRUE;
 
        default:
            return pDlg->OnReceiveMsg(msg, wParam, lParam);
        }
    }
    else
    {
        return FALSE;
    }
}
 
The DialogBoxParam returns -1 but a call to GetLastError() gives 0 signifying that there has not been an error.
 
Many thanks....
Posted 12-Feb-13 3:36am
Edited 12-Feb-13 17:47pm
v2
Comments
Richard MacCutchan at 12-Feb-13 11:20am
   
How do you know that the WM_INITDIALOG message is never sent?
FlurryKnox at 12-Feb-13 23:48pm
   
Hi, I put a breakpoint in DialogProc and check each message. I've updated the question with the messages and the code for DialogProc.
Richard MacCutchan at 13-Feb-13 4:03am
   
I have seen this sequence of messages in the past, when the dialog, or some part of it, is invalid. You need to do some more investigation to try and discover why the system is rejecting the dialog.
Andrew Cherednik at 12-Feb-13 17:47pm
   
Can you show your CMainDialog::DialogProc function implementation
FlurryKnox at 12-Feb-13 23:49pm
   
Hi, sure, I've updated the question with the DialogProc code.
Andrew Cherednik at 13-Feb-13 0:43am
   
this is how microsoft does the handling for WM_INITDIALOG. See, if you can apply it to your case
 
if (message == WM_INITDIALOG)
{
// special case for WM_INITDIALOG
CDialog* pDlg = DYNAMIC_DOWNCAST(CDialog, CWnd::FromHandlePermanent(hWnd));
if (pDlg != NULL)
return pDlg->OnInitDialog();
else
return 1;
}
return 0;
 
Anyway, why do you need to create your own DlgProc? I believe if you pass NULL values, the framework will take care of it
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

The only thing that makes sense to me in this scenario, other than a straight bug in the Windows code, is that the DLL version must be trying to load the dialog template resource from the resources of the executable rather than the DLL itself.
See if you can load the dialog template resource yourself in the dllmain function and if you can make that work you can create the dialog from the already loaded resource to avoid the default code going and looking in the wrong place.
  Permalink  
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

Hello,
 
I think you should check if dialog resource is valid and exists with ID you specify, if exists and loads properly problem could be with dialog styles.
 
Regards,
Maxim.
  Permalink  
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

Hello
 
I just did an experiment. I created a empty win32 exe project. I copied the .h,.cpp, the .rc (resource file for dialog) and some images used by the dialog over to the project folder and add them to the project. I then remove the DllMain function and change the PlayMovie function from
<pre lang="cs">extern "C"
{
__declspec(dllexport) int PlayMovie()
{
 
to this
<pre lang="cs">int WINAPI wWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
 
I copy over the additional dependencies. Now the application compiles and runs without error or warning..The dialog is displayed successfully for the .exe.
 
This suggests that the original problem must be with the conversion to Dll. Originally, to create the Dll I create an empty win32 dll project. I copy the same files over and add them to project. I add the DllMain function and convert the WinMain function to the PlayMovie() (however, I leave the function body the same.
 
I call PlayMovie from c# application. The function is called but the WM_INITDIALOG is never sent.
 
Any ideas as to where I might look...????
  Permalink  
Comments
Maxim Kartavenkov at 13-Feb-13 7:49am
   
Had you try to debug and check what g_hInstance value? Does your code get to the DialogBoxParam function once you call it from .NET (bcs CoInitialize already called in case you call dll from .NET and may return failure)? Had you try to call LoadResource and SizeOfResource to check proper resource ID once you call it from .NET?
Maxim Kartavenkov at 13-Feb-13 7:51am
   
Maybe your Dialog have style that it is main application window but you call it from other application?
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 4

Hi folks,
 
I tried this...
 
BOOL MainDialog::ShowDialog(HINSTANCE hinst)
{
 
HRSRC hSrc = NULL;
HGLOBAL hHndl = NULL;
HMODULE hMod = GetModuleHandle(TEXT("DLLTEST.dll"));
hSrc = FindResource(hMod, MAKEINTRESOURCE(IDD_DIALOG1), MAKEINTRESOURCE(5));
if(hSrc == NULL)
      return 0;
hHndl = LoadResource(hMod, hSrc);
if(hHndl == NULL)
      return 0;
hSrc = FindResource(hMod, MAKEINTRESOURCE(IDR_MENU1), MAKEINTRESOURCE(4));
if(hSrc == NULL)
      return 0;
hHndl = LoadResource(hMod, hSrc);
if(hHndl == NULL)
      return 0;
hSrc = FindResource(hMod, MAKEINTRESOURCE(IDD_OPENURL), MAKEINTRESOURCE(5));
if(hSrc == NULL)
      return 0;
hHndl = LoadResource(hMod, hSrc);
if(hHndl == NULL)
      return 0;
hSrc = FindResource(hMod, MAKEINTRESOURCE(IDB_MUTE), MAKEINTRESOURCE(2));
if(hSrc == NULL)
      return 0;
hHndl = LoadResource(hMod, hSrc);
if(hHndl == NULL)
      return 0;
hSrc = FindResource(hMod, MAKEINTRESOURCE(IDB_PLAY), MAKEINTRESOURCE(2));
if(hSrc == NULL)
      return 0;
hHndl = LoadResource(hMod, hSrc);
if(hHndl == NULL)
      return 0;
hSrc = FindResource(hMod, MAKEINTRESOURCE(IDB_SLIDER), MAKEINTRESOURCE(2));
if(hSrc == NULL)
      return 0;
hHndl = LoadResource(hMod, hSrc);
if(hHndl == NULL)
      return 0;
hSrc = FindResource(hMod, MAKEINTRESOURCE(IDB_VOLUME), MAKEINTRESOURCE(2));
if(hSrc == NULL)
      return 0;
hHndl = LoadResource(hMod, hSrc);
if(hHndl == NULL)
      return 0;
 
	// Show the dialog. Pass a pointer to ourselves as the LPARAM
    INT_PTR ret = DialogBoxParam(
        hinst, 
        MAKEINTRESOURCE(m_nID), 
        NULL, 
        DialogProc, 
        (LPARAM)this
        );
 
    if (ret == 0 || ret == -1)
    {
        MessageBox( NULL, L"Could not create dialog", L"Error", MB_OK | MB_ICONERROR );
        return FALSE;
    }
 
    return (IDOK == ret);
}
 
All the project resources are found and loaded successfully...however DialogBoxParam returns -1 and dialog fails to display...MSDN docs says this "If the function fails because the hWndParent parameter is invalid, the return value is zero. The function returns zero in this case for compatibility with previous versions of Windows. If the function fails for any other reason, the return value is -1. To get extended error information, call GetLastError.". However, GetLastError returns 0 signifying no error....
 
I am at a loss....am I looking in the wrong place???
 
Update...I tried this....
BOOL MainDialog::ShowDialog(HINSTANCE hinst)
{
 
HMODULE hModule = ::GetModuleHandle(TEXT("DLLTEST.dll"));
  HINSTANCE hInst = hModule;
 
  HRSRC hrsrc = ::FindResource(hModule, 
                  MAKEINTRESOURCE(IDD_DIALOG1), RT_DIALOG);
 
  HGLOBAL hglobal = ::LoadResource(hModule, hrsrc);
 
 INT_PTR ret =  ::DialogBoxIndirectParam(hInst, 
                  (LPCDLGTEMPLATE) hglobal, 0, 0, 0);
   return (IDOK == ret);
}
 
The hInst == hinst (e.g. getmodulehandle returns same handled as passed to dllmain)...DialogBoxIndirectParam returns -1.
  Permalink  
v4
Comments
Matthew Faithfull at 14-Feb-13 6:08am
   
OK so you can get all the resource bits you need from the DLL but you've not tried changing the handle passed to DialogBoxParam to hMod or tried loading the actual template resource and making a call to DialogBoxIndirectParam instead. I would give that a go before you call Steve Ballmer to complain, it's a small change compared to what you've already done. ;-)
FlurryKnox at 14-Feb-13 6:46am
   
I've tried DialogBoxIndirectParam quickly (copied and pasted from internet). I tried using hMod in the previous example....
 
Hehehe..Thinking of launching a crowded sourcing project to kidnap Ballmer and get him to solve this....
FlurryKnox at 14-Feb-13 6:49am
   
I'm not sure how to load the resource template...???
Matthew Faithfull at 14-Feb-13 7:03am
   
You've done that bit, it's attached to hrsrc now if the load worked.
Matthew Faithfull at 14-Feb-13 7:02am
   
DialogBoxIndirectParam needs the dialog proc as the 4th parameter and your data parameter ( this pointer ) as the 5th parameter to send with WM_INITDIALOG if it ever gets that far. You should be able to leave the 3rd parameter ( parent window ) null but if that worries you replace it with handle of the Desktop, GetDesktopWindow?- not sure but you'll find it.
Have you checked that the hrsrc and hglobal handles are non-null before the call?
FlurryKnox at 14-Feb-13 7:14am
   
Ooops, sorry that was a mistake...
INT_PTR ret = ::DialogBoxIndirectParam(hInst,
(LPCDLGTEMPLATE) hglobal, 0, DialogProc, (LPARAM)this);
returns -1
and hInst, hglobal are not null...
 
I was wondering if I am making a silly mistake relating to using the Dll. I have assumed that the only files i need for my c# application is the .dll...do I need anything else? What about the compiled resource file...??? As I said earlier I'm new to this type of programming....?????
Matthew Faithfull at 14-Feb-13 7:34am
   
No the compiled resources for the DLL are built into the DLL itself along with the code. This is confirmed and working if hrsrc is not null and not 0XFFFFFFFF (Invalid handle value constant) . In that case I am stumped for the moment. It probably is something simple but I have no idea what. It's your call to keep trying with what you have, post a new question or seek help elsewhere. My final suggestion is to try exactly what you have now but swap hInst with hModule again in the DialogBoxIndirectParam call. It would indicate a bug or at least an inconsistency in the Windows Dialog code if you need to do this when your already passing in the template but it wouldn't be the first time.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 OriginalGriff 540
1 Sergey Alexandrovich Kryukov 402
2 Yogesh Kumar Tyagi 384
3 Prakriti Goyal 280
4 Maciej Los 205
0 OriginalGriff 6,632
1 Sergey Alexandrovich Kryukov 5,404
2 Maciej Los 3,474
3 Peter Leow 3,299
4 DamithSL 2,495


Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 14 Feb 2013
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100