【问题标题】:Is DirextX9 material no longer worthy material for learning win32 API programming?DirextX9 材料不再是学习 win32 API 编程的材料了吗?
【发布时间】:2015-12-26 08:44:43
【问题描述】:

我一直在扩展我的图书馆(这些奇怪的东西称为“书”的物理图书馆……我知道……我知道)我正在阅读 Wendy Jones 的《Beginning DirectX 9.0》。正如我过去浏览过的一些“过时”的书籍一样,它们背后的逻辑实际上是相同的,如果不是在我读过的 C++ 书籍等早期版本(根据我的经验)中更重要的话。我对这本 DirectX 9 书的问题是,10/10 练习代码永远都不起作用。甚至在这里找到的解决方案和 MSDN 对我不起作用。 (相同的问题)。

所以我希望你能不能在我去购买一本关于 DX11 的书之前告诉我,这可能与我的编译器/vs 或 vs 已于 2015 年更新的事实有关,而这 DX9 已过时/DX11标准已经出台。

//Include the Windows header file that's needed for all Windows applications 
#include <Windows.h>


HINSTANCE hInst; // global handle to hold the application instance
HWND wndHandle; // global variable to hold the window handle

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow);

//forward declerations
bool initWindow(HINSTANCE hInstance);
LRESULT CALLBACK WndProc(HWND, UINT WPARAM, LPARAM);

//This is winmain, the main etry point for Windows applications
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    //Initialize the window
    if (!initWindow(hInstance))
        return false;
    //main message loop: (See page 13, "Adding the Windows Code" - Chapter 2
    MSG msg;
    ZeroMemory(&msg, sizeof(msg));
    while (msg.message != WM_QUIT);
    {
        //Check the message queue
            while (GetMessage(&msg, wndHandle, 0, 0))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
    }
    return(int)msg.wParam;
}


/****************************************************************************** 
* bool initWindow( HINSTANCE hInstance ) 
* initWindow registers the window class for the application, creates the window 
******************************************************************************/

bool initWindow(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    //Fill in the WNDCLASSEX structure. THis describes how the window will look to the system
    wcex.cbSize = sizeof(WNDCLASSEX);                    // the size of the structure
    wcex.style = CS_HREDRAW | CS_VREDRAW;                // the class style
    wcex.lpfnWndProc = (WNDPROC)WndProc;                 // the window procedure callback
    wcex.cbClsExtra = 0;                                 // extra bytes to allocate for this calss
    wcex.cbWndExtra = 0;                                 // extra bytes to allocate for this instance
    wcex.hInstance = hInstance;                          // handle to the application
    wcex.hIcon = 0;                                      // icon to associate with the application
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);          // the default cursor
    wcex.lpszMenuName = NULL;                            // the resource name for the menu
    wcex.lpszClassName = NULL;                           // the class name being created
    wcex.hIconSm = 0;
    RegisterClassEx(&wcex);

    //Create the window
    wndHandle = CreateWindow(
        (LPCWSTR)"DirectXExample",              // the window class to use
        (LPCWSTR)"DirectXExample",              // the title bar text
        WS_OVERLAPPEDWINDOW,                    // the window style
        CW_USEDEFAULT,                          // the starting x coordinate
        CW_USEDEFAULT,                          // the starting y coordinate
        640,                                    //the pixel width of the window
        480,                                    //the pixel height of the window
        NULL,                                   // the parent window; NULL for desktop
        NULL,                                   // the menu for the application; NULL for none
        hInstance,                              // the handle to the apllication instance
        NULL);                                  // no values passed to the window

    //make sure that the window handle that is created is valid
    if (!wndHandle)
        return false;

    //Display the window on the screen
    ShowWindow(wndHandle, SW_SHOW);
    UpdateWindow(wndHandle);
    return true;
}

【问题讨论】:

  • 如果您决定继续使用 DirectX 11,请确保远离 Wendy Jones 编写(或合着)的标题。这位作者不应该写关于这个主题的书。查看Beginning DirectX 11 Game Programming的书评。

标签: winapi compiler-errors directx-9 obsolete


【解决方案1】:

继续使用 DirectX 9 非常好。但是您在屏幕上显示最小主机窗口的实现存在一些简单的错误。它还在 ANSI 和宽字符串之间进行了一些错误的转换。让我们帮你解决:

删除 WinMain 的前向声明。这一行,删掉就好了。

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow);

在WinMain的实际函数体中,将lpCmdLine的类型从LPTSTR参数改为LPSTR

//This is winmain, the main etry point for Windows applications
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    //Initialize the window
    if (!initWindow(hInstance))

您对 WndProc 的声明也不正确。 WndProc 应该声明如下:

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam);

一旦你修复了 WndProc 的上述声明,你就可以在 WNDCLASS 初始化中去掉那个错误的强制转换操作。改变这个:

wcex.lpfnWndProc = (WNDPROC)WndProc;  // the window procedure callback

到这里:

wcex.lpfnWndProc = WndProc;  // the window procedure callback

您缺少 WndProc 的定义。您需要自己实现该功能。这是一个最小的实现:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CLOSE:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;

}

上面的代码会让你的代码编译,但它仍然会有一些错误,并且不会真正像它应该的那样运行。让我们解决这些问题。

首先,您的消息泵有一个额外的;,它会阻止它实际运行并使您的代码处于无限循环中。这一行:

while (msg.message != WM_QUIT);

应该是(不带分号):

while (msg.message != WM_QUIT)

当我在这里时,您的消息泵实现有点奇怪。 GetMessage 仅在msg.message==WM_QUIT 时返回 FALSE,因此不需要外循环。改变这个:

while (msg.message != WM_QUIT)
{
    //Check the message queue
        while (GetMessage(&msg, wndHandle, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
}

变成这样:

//Check the message queue until WM_QUIT is received
while (GetMessage(&msg, wndHandle, 0, 0))
{
     TranslateMessage(&msg);
     DispatchMessage(&msg);
}

当您实际为您的 DX 应用程序实现图形循环时,您可以将 GetMessage 调用更改为 PeekMessage,然后显式检查 WM_QUIT。

您的 initWindow 失败的原因有很多。

您在 WNDCLASSEX 变量中留下了一些垃圾值。更改此行:

 WNDCLASSEX wcex;

变成这样:

WNDCLASSEX wcex = {};

您忘记设置 wcex.lpszClassName。把它变成这样:

 wcex.lpszClassName = L"DirectXExample";

然后您将 ANSI 字符串转换为 (LPCWSTR) 是不正确的。为方便起见,这里有一个固定版本的 initWindow 函数。

bool initWindow(HINSTANCE hInstance)
{
    WNDCLASSEX wcex = {};

    //Fill in the WNDCLASSEX structure. THis describes how the window will look to the system
    wcex.cbSize = sizeof(WNDCLASSEX);                    // the size of the structure
    wcex.style = CS_HREDRAW | CS_VREDRAW;                // the class style
    wcex.lpfnWndProc = (WNDPROC)WndProc;                 // the window procedure callback
    wcex.cbClsExtra = 0;                                 // extra bytes to allocate for this calss
    wcex.cbWndExtra = 0;                                 // extra bytes to allocate for this instance
    wcex.hInstance = hInstance;                          // handle to the application
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);                                      // icon to associate with the application
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);          // the default cursor
    wcex.lpszMenuName = NULL;                            // the resource name for the menu
    wcex.lpszClassName = L"DirectXExample";                           // the class name being created
    wcex.hIconSm = 0;
    RegisterClassEx(&wcex);

    //Create the window
    wndHandle = CreateWindow(
        L"DirectXExample",              // the window class to use
        L"DirectXExample",              // the title bar text
        WS_OVERLAPPEDWINDOW,                    // the window style
        CW_USEDEFAULT,                          // the starting x coordinate
        CW_USEDEFAULT,                          // the starting y coordinate
        640,                                    //the pixel width of the window
        480,                                    //the pixel height of the window
        NULL,                                   // the parent window; NULL for desktop
        NULL,                                   // the menu for the application; NULL for none
        hInstance,                              // the handle to the apllication instance
        NULL);                                  // no values passed to the window

                                                //make sure that the window handle that is created is valid
    if (!wndHandle)
        return false;

    //Display the window on the screen
    ShowWindow(wndHandle, SW_SHOW);
    UpdateWindow(wndHandle);
    return true;
}

应该这样做。

【讨论】:

  • 非常感谢详细而彻底的回复。这真的很奇怪,因为该代码是直接从书中提取的,然后我仔细检查了提供的在线资源。我可能需要投资另一本书。
  • 即使修正了可原谅的拼写错误,代码也无法正常工作。所以如果你把它从一本书里拿出来,是时候扔掉这本书了。我学习 DirectX 9 的一本好书是 this one。同一作者发布了 DX 10 和 DX11 的更新版本。
  • 不使用 DX9 的主要原因是它对现代版本的 Windows 的调试支持很差,因为 API 本身已有十多年的历史。请参阅 DirectX 工具包tutorials
  • 另外,如果您打算使用 Direct3D 9,请避免使用固定功能管道。请改用 HLSL 和可编程着色器,因为 DX 10 或更高版本中不存在固定功能管线。
猜你喜欢
  • 1970-01-01
  • 2013-01-24
  • 1970-01-01
  • 1970-01-01
  • 2010-11-25
  • 1970-01-01
  • 2023-04-09
  • 2020-07-24
  • 1970-01-01
相关资源
最近更新 更多