Sign in to follow this  

Use of static dll

This topic is 2844 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

This might be the wrong place to ask, in which case I hope a moderator might be so kind as to move the thread to where it belongs. The question: I have a dll in which I have a class I want to use in another project. I prefix the class in the dll like so: class __declspec(dllexport) MyClass I then import the headers to the other project and reference the dll, thus using the class as I normaly would. This works as it should. In MyClass is a Init-metod which takes a single HWND and attemps to make a DX10 device and swapchain. However, whenever I try to use the Hwnd, it is always NULL, ie as if not initialized. This is not true, since I use the same HWND for creating the window the device is to be running in (this occurs in the main project, not in the dll), prior to calling the Init-metod. So the question is: Is HWND always null? Or is there something wrong in how I use the class from the dll?

Share this post


Link to post
Share on other sites
Moving to General Programming.

There's some problem with the way you're using your class. How do you know the HWND is null? Have you tried printing the value out? Are you absolutely sure that the variable is non-NULL when you call the function in the DLL? Have you checked with your debugger?

Share this post


Link to post
Share on other sites
Quote:

How do you know the HWND is null?


It's a global variable and I set it to NULL like so:
g_hWnd = NULL;

Quote:

Have you tried printing the value out?


No, but when I step through the breakpoints it never changes to anything other than 0x00000000 {unused=???} so I suppose it's just NULL? Or?

Quote:

Are you absolutely sure that the variable is non-NULL when you call the function in the DLL?


It never changes when looking at the breakpoints, altough is _must_ change to something since the window i create with it displays correctly.

Quote:

Have you checked with your debugger?


Well, only the watchwindows, using breakpoints, and the Callstack. Other than that is beyond me, I'm affraid.



Share this post


Link to post
Share on other sites
Quote:
Original post by Bangladesh
Quote:

Are you absolutely sure that the variable is non-NULL when you call the function in the DLL?


It never changes when looking at the breakpoints, altough is _must_ change to something since the window i create with it displays correctly.
What do you use the HWND for exactly? Can we see some code? There's plenty of Win32 functions which will succeed with a NULL HWND.

Share this post


Link to post
Share on other sites
Certainly, but it's nothing fancy. First I create a window with this function:


HWND g_hWnd = NULL;

// Make window
bool WinInit(HWND hWnd, HINSTANCE hInstance, int width, int height)
{
WNDCLASSEX wcex;
ZeroMemory(&wcex, sizeof(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 = 0;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = TEXT("BlackBird");
wcex.hIconSm = 0;
if( !RegisterClassEx(&wcex) )
return FALSE;

RECT rc = { 0, 0, width, height };
AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
hWnd = CreateWindow( TEXT("BlackBird"), TEXT("BlackBird"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL,
hInstance, NULL);

if( !hWnd )
return false;

ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
return true;
};


Then I try to create a device and swapchain from a class defined in my dll. The method that does this looks like this:

HRESULT Ghost3D::Init(HWND hWnd, UINT windowWidth, UINT windowHeight, bool window)
{
if(!hWnd)
{ return E_FAIL; }

m_hWndMain = hWnd;
m_nBufferWidth = windowWidth;
m_nBufferHeight = windowHeight;
m_bWindowed = window;
return Go();
};

HRESULT Ghost3D::Go(void)
{
// DirectX
// Define a swapchain
//
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof(sd) );
sd.BufferCount = 1;
sd.BufferDesc.Width = m_nBufferWidth;
sd.BufferDesc.Height = m_nBufferHeight;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = m_hWndMain;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = m_bWindowed;

// Test if hardware supports DX10, if not we have to run on the Reference-driver
HRESULT hr = E_FAIL;
D3D10_DRIVER_TYPE driverType = D3D10_DRIVER_TYPE_NULL;
D3D10_DRIVER_TYPE driverTypes[] =
{
D3D10_DRIVER_TYPE_HARDWARE,
D3D10_DRIVER_TYPE_REFERENCE
};
UINT numDriverTypes = sizeof(driverTypes)/sizeof(driverTypes[0]);
for(UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++)
{
// Try to create the driver
driverType = driverTypes[driverTypeIndex];
hr = D3D10CreateDeviceAndSwapChain(NULL, driverType, NULL, 0, D3D10_SDK_VERSION,
&sd, &m_pSwapChain, &m_pDevice);
if(SUCCEEDED(hr))
{
if(driverType == D3D10_DRIVER_TYPE_HARDWARE)
{
//Log(m_pLogFile, "GhostD3D:\t Using HardWare-enabled rendering");
}
else
{
//Log(m_pLogFile, "GhostD3D:\t Using Reference-rendering");
}
break;
}
}
if( FAILED(hr) )
return hr;
};


Edit:
However it never goes further than the first hWnd-check when I look if it's NULL or not. But if hWnd can be null without failing then I guess I've been shooting myself in the foot all along.

Share this post


Link to post
Share on other sites
Quote:

In MyClass is a Init-metod which takes a single HWND and attemps to make a DX10 device and swapchain. However, whenever I try to use the Hwnd, it is always NULL, ie as if not initialized.

It's a global variable and I set it to NULL like so:
g_hWnd = NULL;

Based on the code you provided, g_hWnd is always null because you never assign anything to it. All the code you showed manipulated HWNDs that are passed as parameters to the functions in question or are members of the class. Doesn't seem like you even need the global HWND.

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
Based on the code you provided, g_hWnd is always null because you never assign anything to it. All the code you showed manipulated HWNDs that are passed as parameters to the functions in question or are members of the class. Doesn't seem like you even need the global HWND.


Sorry, the code was taken out of context: I acctually feed the g_hWnd to the function when I create the window. Here is the actual code which I think should work. Or do I have it backwards?

HWND g_hWnd = NULL;

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
int width = 640;
int height = 480;

if (!WinInit(g_hWnd, hInstance, width, height))
return 0;

Ghost3D* pDevice = new Ghost3D();
if(FAILED(pDevice->Init(g_hWnd, (UINT)width, (UINT)height, true)))
{
}

MSG msg = {0};
while(msg.message != WM_QUIT)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == TRUE)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Do other stuff
if(!Render())
return 0;
}

delete pDevice; pDevice = NULL;
return 0;
};

Share this post


Link to post
Share on other sites
hWnd = CreateWindow

That line assigns the local copy of the HWND parameter to the return value of CreateWindow(). The value you passed in is unaffected.

If you want to change the value of the HWND passed, pass it as a pointer or (preferably) reference instead, or return the HWND from the function.

Share this post


Link to post
Share on other sites
Quote:

Sorry, the code was taken out of context: I acctually feed the g_hWnd to the function when I create the window. Here is the actual code which I think should work. Or do I have it backwards?

But you never assign to the global HWND. You assign to copies of that HWND, because it's passed by value to all your functions. Also, if you just pass this HWND around like this there really isn't any reason to make it global. It can be a local variable in WinMain.

A HWND is an opaque type, but in practice it is really a pointer to some structure. Observe:

#include <iostream>

int i = 0;
void f(int* q) {
q = &i;
}

int main() {
int* p = 0;
f(p);
std::cout << p;
}

This prints 0, not some arbitrary address (of the global i), because we modified q, a copy of p -- not p itself. This code is the same as:

#include <iostream>

typedef int* HWND;
int i = 0;
void f(HWND q) {
q = &i;
}

int main() {
HWND p = 0;
f(p);
std::cout << p;
}

and is conceptually equivalent to your own code. You're copy the HWND each time you pass it -- not passing it by reference.

You could modify your code to pass the HWND around by reference (HWND& in the parameter list), but that isn't a very elegant design. Better to encapsulate everything -- the creation of the window, the device setup, et cetera -- in the Ghost3D object (or some object that Ghost3D will depend on). That way you don't need the global HWND or the local that you pass around in a cumbersome fashion.

Share this post


Link to post
Share on other sites
Thanks Evil Steveand jpetrie; I did a quick test and reference solved it. Proof I need to read up on my c++.

I am curious about jpetrie suggestion as to encapsulate everything. Would that mean I should wrap the WndProc into the Ghost3D-class as well?

Since I'm thinking about putting the "graphic-engine" in the dll and the "game" in the app, shouldn't I put the creation of the window and the main game loop "outside" the render-code?

Thoughts on best practice?

Share this post


Link to post
Share on other sites
Quote:

I am curious about jpetrie suggestion as to encapsulate everything. Would that mean I should wrap the WndProc into the Ghost3D-class as well?

Maybe. You should wrap the window handling stuff in its own class, probably, so you no longer need to deal with HWNDs directly. Depending on how complex you want your window usage to be, you can make this wrapper a distinct class or simply roll it up into the "Ghost3D" object. The basic implementation is the same in either case.

Quote:

Since I'm thinking about putting the "graphic-engine" in the dll and the "game" in the app,

Why are you thinking about using a DLL? What advantages does it bring to your project? Because it also brings a lot of disadvantages and management overhead, such that it may be better simply to use a static library.

Quote:

shouldn't I put the creation of the window and the main game loop "outside" the render-code?

Generally, yes. If the scope of your framework code is narrow enough, it can be fine to roll it into the object setting up the graphics device, because they two are pretty tightly coupled anyhow. However, it's generally better to split the window and the graphics code because the window code is also coupled to input pretty tightly as well.

Regardless, though, the process of wrapping the window management into its own class is the same -- doesn't matter which class you put it in. So you can roll everything into a Window object and then pass that window to both the graphics device constructor and the input system constructor.

Share this post


Link to post
Share on other sites

This topic is 2844 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this