Click here to Skip to main content
15,888,068 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello

I have been trying to create a DLL in C++ using Visual Studio 2012. The aim is to convert the BasicPlayback sample which uses the Microsoft Media Foundation to play a video file into a DLL that does the same thing.

The sample can be found in MFSamples.zip at :
http://archive.msdn.microsoft.com/mediafoundation

The BasicPlay sample compiles and runs showing a window with a File Menu. However, when I convert it to a dll and call the relevant function (see later), the window displays without a menu. I use GetLastError after the CreateWindow function and I get "Invalid Menu Handle". The thing is I am not sure what is going wrong.

To create the DLL, I create a empty Win32 DLL project. I copy over the .H, .CPP, .RC files from BasicPlayback folder and add them to the Header Files, Resource Files and Source files in Solution explorer. I then copy the Additional Dependencies using the VS Menu(Project, Properties, Linker, Input) and overwrite the Additional Dependencies of the DLL project.

I change the WinMain function from this:
C++
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    MSG msg;

    ZeroMemory(&msg, sizeof(msg));

    // Perform application initialization.
    if (!InitInstance(hInstance, nCmdShow))
    {
        NotifyError(NULL, L"Could not initialize the application.",
            HRESULT_FROM_WIN32(GetLastError()));
        return FALSE;
    }

    // Main message loop.
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // Clean up.
    if (g_pPlayer)
    {
        g_pPlayer->Shutdown();
        g_pPlayer->Release();
    }
    return 0;
}


To to this (e.g. I change the function name) :

C++
<pre lang="cs">extern "C"
{
    // int PlayMovie(HINSTANCE hInstance)
    __declspec(dllexport) int PlayMovie(HINSTANCE hInstance)
    {
        MSG msg;

        ZeroMemory(&msg, sizeof(msg));

        // Perform application initialization.
        if (!InitInstance(hInstance, 0))
        {
            NotifyError(NULL, L"Could not initialize the application.",
                HRESULT_FROM_WIN32(GetLastError()));
            return FALSE;
        }

        // Main message loop.
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        // Clean up.
        if (g_pPlayer)
        {
            g_pPlayer->Shutdown();
            g_pPlayer->Release();
        }
        return 0;
    }
}



I then call the PlayMovie function from within a c# program by including the following:
C#
[DllImport(@"BasicDll.dll", EntryPoint="PlayMovie", ExactSpelling=false,CallingConvention=CallingConvention.Cdecl)]
public static extern int PlayMovie(IntPtr hInstance);


I then call the PlayMovie function as follows:

C#
IntPtr windowHandle = new WindowInteropHelper(this).Handle;
PlayMovie(windowHandle);


The dll project compiles without error or warning. When I call the PlayMovie function from c#, the window opens as expected. However the Menu is missing.

Investigating with GetLastError finds the problem to be here (Maybe??? but I'm not sure) :

C++
BOOL InitInstance(HINSTANCE hInst, int nCmdShow)
{
	HWND hwnd;
	WNDCLASSEX wcex;

	g_hInstance = hInst; // Store the instance handle.

	// Register the window class.
	ZeroMemory(&wcex, sizeof(WNDCLASSEX));
	wcex.cbSize         = sizeof(WNDCLASSEX);
	wcex.style          = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc    = WndProc;
	wcex.hInstance      = hInst;
	wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_MFPLAYBACK);
	wcex.lpszClassName  = szWindowClass;

	if (RegisterClassEx(&wcex) == 0)
	{
		return FALSE;
	}

	// Create the application window.
	hwnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);

	if (hwnd == 0)
	{
		return FALSE;
	}

	ShowWindow(hwnd, SW_SHOW);
	UpdateWindow(hwnd);

	return TRUE;
}


Using GetLastError after CreateWindow Gives 1401 Invalid Menu Handle.

Now, since the project work as an exe and given the steps I used to create the dll, I am at a loss to know what has gone wrong. However, I am not experienced with DLLs and Windows programming so it could easily be something silly. I was hoping someone could through me a few clues as to what I've done wrong....I have strggle to find the solution on Google...

Many thanks....
Posted

Your Window class and hence its instance gets its menu from this line
wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_MFPLAYBACK);

so make sure IDC_MFPLAYBACK is being defined and the associated MENU resource is being built into your DLL. Otherwise I don't see any obvious reason why this wouldn't work given that it gets as far as displaying the window.
 
Share this answer
 
Comments
FlurryKnox 6-Feb-13 13:28pm    
Thanks for your response. I have include the resource header file using solution explore (under header files) and have included the BasicPlayback.rc file under resource files. In code, i have assigned IDC_MFPLAYBACK to a variable and the menu id does get copied into the variable.

However, after adding the files, all I do is build and run. I am not aware of any additional steps to handle resource files. I can't seem to find any reference to this on google. Presumably, once complied, all I need is the dll file...

Is there something I could do to narrow this problem down that I could try????

Thanks...
Matthew Faithfull 6-Feb-13 13:43pm    
It's not the header then and the .rc file with the definition of your menu in it BasicPlayback.rc that needs to be run through the resource compiler sounds like it is, check the build setting to confirm. You could try loading the menu resource yourself in the code before the point of failure and checking the result.
You'll need something like
<pre>
HANDLE hMenu = LoadMenu( hInstance, MAKEINTRESOURCE(IDC_MFPLAYBACK) );
</pre>
Check the value of the handle you get back, and make sure hInstance isn't null aswell. I'm not 100% certain where that would be coming from in a Dll as part of a C# application but I don't think you'd be getting a window without it so its probably OK.
Hi
I managed to fix this problem.

I added a DllMain function. See description in:
http://en.wikibooks.org/wiki/Windows_Programming/Dynamic_Link_Libraries

Windows calls the library's DllMain function and passes an HINSTANCE handle.

C++
BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID lpReserved)
{
   g_hInstance = hInst
   return TRUE;
}


In the DllMain, I capture the HINSTANCE passed by windows. I then use this in the CreateWindow function. I think the original problem of the menu not appearing was with the Handle i was passing from c# (as suggested above by Mathew Faithful).

I'll mark this reply as answered.

Cheers....
 
Share this answer
 
v2
Comments
Matthew Faithfull 6-Feb-13 18:42pm    
Good stuff, glad it's working. So it was the horrible HINSTANCE after all. To be honest mixing C# and C++ scares me a good deal but I've probably read too much library source code. Sometimes it's easier not to know :-)

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900