MFC架构下的DirectX8

2023-05-16

MFC架构下的DirectX8
第一章 MFC框架
(DX8MFC)
这里的MFC框架指的是一个符合游戏开发应用的框架,当然你也可以写一个符合你要求的MFC框架。如果你对MFC比较熟悉的话可以直接从第二章开始阅读。本框架是以后几个例子的基础,如果你对MFC不是很了解的话,就要认真阅读本章,以求对这个MFC框架有一个深入的了解。
框架中包括两个类:
CDX8MFCApp类和CFrameWin类,CDX8MFCApp类是应用程序类,CFrameWin类是框架的主类,以后我们的大部分代码都是从这里扩展的。首先来看一看CDX8MFCApp类,它包括CDX8MFCApp()、ExitInstance()、InitInstance()、OnIdle(LONG lCount)等成员函数和一个Game对象。
InitInstance()成员函数在程序初始化时就被调用,在这里我建立了一个窗口:
BOOL CDX8MFCApp::InitInstance()
{
// The one and only window has been initialized, so show and update it.
m_pMainWnd = new CFrameWin();
    m_pMainWnd->ShowWindow(m_nCmdShow);
    m_pMainWnd->UpdateWindow();
Game = (CFrameWin*) m_pMainWnd;
Game->Init();

return TRUE;
}

ExitInstance()成员函数在程序终止时被调用,在这里我们释放一些对象和指针:
int CDX8MFCApp::ExitInstance()
{
// TODO: Add your specialized code here and/or call the base class
Game->End();
delete Game;

return CWinApp::ExitInstance();
}

OnIdle(LONG lCount)成员函数会在没有Windows消息要处理的时候被调用,也就是说OnIdle()成员函数会不断的被调用,这正好被我们用作游戏循环。
BOOL CDX8MFCApp::OnIdle(LONG lCount)
{
// TODO: Add your specialized code here and/or call the base class
if(Game->window_active==TRUE)
{
Game->Active();
Game->window_active=FALSE;
}

Game->Go();

return TRUE;
}

Game对象是一个CFrameWin类指针,我们在InitInstance()成员函数中创建了一个CFrameWin对象并把CFrameWin对象的指针值赋给Game。
下面我们来看一看CFrameWin类,它包括Active()、End()、Go()、Init()、Update()等成员函数。
Init()成员函数,你可以在这里做一些自己的初始化。回顾CDX8MFCApp类的InitInstance()成员函数可知,在完成窗口初始化后InitInstance()成员函数里就调用了Game->Init(),也就是说Init()在窗口初始化后被调用。
void CFrameWin::Init()
{
AfxMessageBox("Init");
}

Go()成员函数会不断的被循环调用,它又调用了Update()和DestroyWindow()。Update()用于更新窗口,调用DestroyWindow()则会结束应用程序。如果你把DestroyWindow()语句删除掉,程序会不断的循环。
void CFrameWin::Go() //Game循环
{
AfxMessageBox("Go");
Update();
DestroyWindow();
}

Active()成员函数会在应用程序被击活的时候被调用。
void CFrameWin::Active() //窗口被激活
{
TRACE("Active/n");
AfxMessageBox("Active");
}

这个程序并不做任何事,只是一个MFC框架。你可以从http://gamedev.363.net 下载例子的源程序,或通过E-mail: laical@21cn.com 向本文作者索取。

第二章 初始化DirectX8
(DX8MFC1)
本例将以第一章的MFC框架为基础对CFrameWin类进行扩展。主要加入了DrawScene()、InitDirect3D(HWND hwnd)和ShutdownDirect3D()三个函数。
InitDirect3D(HWND hwnd)函数对Direct3D进行初始化:
HRESULT CFrameWin::InitDirect3D(HWND hwnd)
{
    pID3D = Direct3DCreate8(D3D_SDK_VERSION);

    HRESULT hr;
    do
    {
        // we need the display mode so we can get
        // the properties of our back buffer
        D3DDISPLAYMODE d3ddm;
        hr = pID3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
        if(FAILED(hr))
            break;

        D3DPRESENT_PARAMETERS present;
        ZeroMemory(&present, sizeof(present));
        present.SwapEffect       = D3DSWAPEFFECT_COPY;
        present.Windowed         = TRUE;
        present.BackBufferFormat = d3ddm.Format;

        hr = pID3D->CreateDevice(D3DADAPTER_DEFAULT,
                                 D3DDEVTYPE_HAL,
                                 hwnd,
                                 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                 &present,
                                 &pID3DDevice);

        if(FAILED(hr))
            break;

        // we do our own coloring, so disable lighting
        hr = pID3DDevice->SetRenderState(D3DRS_LIGHTING,
                                         FALSE);

    } while(0);

    return hr;
}

IDirect3D是我们首先要用到的接口,你可以这样写:
IDirect3D8 * pID3D = Direct3Dcreate8(D3D_SDK_VERSION);
在你使用pID3D以前,请检查pID3D是否为非空。
你下一步通常是创建D3D设备,但在创建D3D设备之前你要调用GetAdapterDisplayMode方法取得必须的信息:
D3DDISPLAYMODE d3ddm;
pID3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
接下来是取得当前显示模式参数。下面的参数是Surface格式。你可以用这些参数来创建一个D3DPRESENT_PARAMETERS结构:
D3DPRESENT_PARAMETERS present;
ZeroMemory(&present, sizeof(present));
present.SwapEffect              = D3DSWAPEFFECT_COPY;
present.Windowed                = TRUE;
present.BackBufferFormat        = d3ddm.Format;
D3DPRESENT_PARAMETERS描述了显示器Surface的信息,交换机制的类型,应用程序是窗口的还是全屏模式等信息。
在本例中,Surface是以拷贝方法代替页面翻转的,因为它是一个窗口模式的应用程序。把后台表面设置成与当前显示模式相匹配的格式,一个准备显示的Surface可以Draw在后台表面上。

现在你可以创建一个IDirect3DDevice8接口了:
pID3D->CreateDevice(D3DADAPTER_DEFAULT,
                    D3DDEVTYPE_HAL,
                    hwnd,
                    D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                    &present,
                    &pID3DDevice);
这个函数有六个参数,幸运的是没有一个是很复杂的。D3DADAPTER_DEFAULT告诉Direct3D使用主显示器,只有当你使用多显示器时才是必须的。你可以使用一个数值来指定另外一个显示器。调用IDirect3D的GetAdapterCount将返回系统的适配器数目。
第二个参数,D3DDEVTYPE_HAL,告诉Direct3D使用硬件加速。其它选项包括D3DDEVTYPE_REF 和 D3DDEVTYPE_SW,通常你都会希望使用硬件加速的,但有时侯你可能会使用软件加速进行测试。
指定窗口取得焦点。如果是全屏应用程序,你需要一个最顶层窗口。
D3DCREATE_SOFTWARE_VERTEXPROCESSING指定顶点处理类型。你也可以使用硬件加速或是联合类型,我不使用硬件加速为的是广泛的兼容性。如果你想支持T&L,则你必须使用硬件加速。
最后两个参数很简单,一个是你以前建立的,而pID3Ddevice是你现在要创建的IDirect3DDevice8接口。如果方法返回D3DERR_NOTAVAILABLE,则你写的参数是正确的,但你的设备不支持你指定的参数。
最完美的是这个方法自动为你创建后台缓冲(back buffers)和深度缓冲(depth buffers)。剪裁(Clipping)作为后台表面(backface culling)被自动激活。灯光也被自动激活了,直到你定义顶点颜色之前,你可以禁止使用灯光:
pID3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

DrawScene()函数:
HRESULT CFrameWin::DrawScene()
{
    HRESULT hr;
    do
    {
        // clear back buffer
        hr = pID3DDevice->Clear(0,
                                NULL,
                                D3DCLEAR_TARGET,
                                D3DCOLOR_RGBA(0,63,0,0),
                                0,
                                0);
        if(FAILED(hr))
            break;

        // start drawing
        hr = pID3DDevice->BeginScene();
        if(FAILED(hr))
            break;

        // Put all drawing code here

        hr = pID3DDevice->EndScene();
        if(FAILED(hr))
            break;

        // flip back buffer to front
        hr = pID3DDevice->Present(NULL, NULL, NULL, NULL);
    } while(0);

    return hr;
}

Clear会填充你指定的缓冲区。你可以填充Z缓冲区、后台缓冲区或摸板缓冲区(stencil buffer)。在这个例子中你将用绿色填充后台缓冲区。所以,我们设定D3DCLEAR_TARGET标志和绿色。
在本例中BeginScene和EndScene并没有做什么,但在以后的例子中我们会用到它的。这两个函数是画图元时的例行公事代码,
这个函数不断的翻转后台表面。我们可以不断的在后台表面画一些东西,然后把后台表面翻转到前台表面。

ShutdownDirect3D()函数
void CFrameWin::ShutdownDirect3D()
{
    HELPER_RELEASE(pTexture);
    HELPER_RELEASE(pIndexBuffer);
    HELPER_RELEASE(pStreamData);
    HELPER_RELEASE(pID3DDevice);
    HELPER_RELEASE(pID3D);
}
ShutdownDirect3D释放所有的接口。将来你可能要加入额外的代码来关闭Direct3D接口,但现在已经够了。如果你运行程序,你将得到一个绿色背景的窗口。你可以按“ESC”键来退出应用程序。

第三章 画三角形
(DX8MFC2)
定义你的顶点格式,Direct3D引入了一种可变形顶点格式(flexible vertex format)(FVF)的概念。在FVF中,你定义一个结构其中包括所需要的顶点组成部分。这个结构会随着你的程序而改变,但在这里你将初步把它定义成这个样子:
struct MYVERTEX
{
  FLOAT x, y, z; // The transformed position
  FLOAT rhw;     // 1.0 (reciprocal of homogeneous w)
  DWORD color;   // The vertex color
};
示例的开始定义了一个顶点结构,顶点的名称,和每一个三角形的顶点。在你的InitDirect3D函数中,你必须创建一个顶点缓冲区:
int num_elems = sizeof(vertices) / sizeof(vertices[0]);
pID3DDevice->CreateVertexBuffer(sizeof(MYVERTEX) *
                                num_elems,
                                D3DUSAGE_WRITEONLY,
                                D3DFVF_XYZRHW|D3DFVF_DIFFUSE,
                                D3DPOOL_DEFAULT,
                                &pStreamData);
函数的第一个参数是顶点结构的字节大小。在应用程序还不能读取顶点之前,传一个D3DUSAGE_WRITEONLY标记给它。这里可以有不同的标记来指定如何处理你的顶点,但现在你可以确信Direct3D已经能正确的工作了。
下一步,指定我们用的是什么FVF格式。当你还没有使用坐标系预转换之前,指定为D3DFVF_XYZRHW标记。以后你使用自己的矩阵坐标系转换时,把它改成D3DFVF_XYZ。D3DFVF_DIFFUSE告诉Direct3D,我们将为每一个顶点指定颜色。D3DPOOL_DEFAULT指定内存的管理模式。
最后一个参数是顶点缓冲区的指针,在例子1中你已经定义了它,但并没有用上。
如果你不向顶点缓冲区填入有用数据的话,顶点缓冲区是没有用的:
MYVERTEX *v;
pStreamData->Lock(0, 0, (BYTE**)&v, 0);
for(int ii = 0; ii < num_elems; ii++)
{
  v[ii].x     = vertices[ii].x;
  v[ii].y     = vertices[ii].y;
  v[ii].z     = vertices[ii].z;
  v[ii].rhw   = vertices[ii].rhw;
  v[ii].color = vertices[ii].color;
}
pStreamData->Unlock();
这是不难理解的,Lock返回一个你想写入顶点数据的指针。下一步你从你的顶点阵列中拷贝数据。然后,反还这个指针。
这一对的调用可以告诉Direct3D你的FVF格式,并设定顶点阵列为当前的活动顶点阵列。(你可以有多个顶点阵列)。
pID3DDevice->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);

pID3DDevice->SetStreamSource(0, pStreamData, sizeof(MYVERTEX));
SetVertexShader告诉Direct3D使用与CreateVertexBuffer同样的格式。
SetStreamSource告诉Direct3D使用pStreamData作为当前顶点阵列,并取得所有元素的大小。
你现在可以加入画三角形的代码了。在DrawScene()的BeginScene和EndScene之间加入如下代码:
int num_elems = sizeof(vertices) / sizeof(vertices[0]);
pID3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
                           0,
                           num_elems / 3);
D3DPT_TRIANGLELIST标记将命令Direct3D画不连续的三角形。你指定从索引的第0个顶点开始,指定所要画的三角形数目。
如果正确的话,你会看到一个三角形画在先前的绿色背景窗口上。

第四章 画索引三角形
(DX8MFC3)
上一章的画三角形方式运行效率是较低的,而实际上我们都会使用DrawIndexedPrimitive()而不是DrawPrimitive()。想一想,如果要画两个相连的三角形,共有四个顶点。用DrawIndexedPrimitive()画要画四个顶点,而用DrawPrimitive()画则要画六个顶点。
如果你可以顶点建立索引,你就可以用DrawIndexedPrimitive()画三角形了。我们可以为一个三角形建立这样的索引:
WORD indices[] = { 0, 1, 2 };
它表示三角形中,第一个顶点对应于顶点阵列的第0个顶点;三角形中,第二个顶点对应于顶点阵列的第1个顶点;三角形中,第三个顶点对应于顶点阵列的第2个顶点;
要画索引三角形,首先要建立索引缓冲:
num_elems = sizeof(indices) / sizeof(indices[0]);
pID3DDevice->CreateIndexBuffer(sizeof(WORD) * num_elems,
                               D3DUSAGE_WRITEONLY,
                               D3DFMT_INDEX16,
                               D3DPOOL_DEFAULT,
                               &pIndexBuffer);
第二步是用顶点填充这个索引缓冲:
WORD *pIndex;
pIndexBuffer->Lock(0, 0, (BYTE **)&pIndex, 0);
for(ii = 0; ii < num_elems; ii++)
{
  pIndex[ii] = indices[ii];
}
pIndexBuffer->Unlock();
设定索引缓冲:
pID3DDevice->SetIndices(pIndexBuffer, 0);
把DrawScene()的相应的pID3DDevice->DrawPrimitive(...)换成:
pID3DDevice->DrawIndexedPrimitive(
                 D3DPT_TRIANGLELIST,
                 0,
                 sizeof(indices) / sizeof(indices[0]),
                 0,
                 sizeof(indices) / sizeof(indices[0]) / 3);
运行程序的到的还是一个三角形。

第五章 加入帖图
(DX8MFC4)
首先,在MYVERTEX结构中加入帖图坐标系tu和tv,并给顶点阵列赋以适当的值。
下一步,设置你的帖图:
D3DXCreateTextureFromFile(pID3DDevice,
                          "dx5_logo.bmp",
                          &pTexture);
pID3DDevice->SetTexture(0, pTexture);
其中的"dx5_logo.bmp"指的是帖图文件,你可以用其他的文件代替它,运行程序你会看到一个带帖图的三角形。

第六章 帖图立方体
(DX8MFC5)
现在样我们来进入三维的世界吧!这里你要启用Z缓冲(z-buffer),设置立方体的材质,世界坐标系和投影坐标系。
启用Z缓冲(z-buffer),你要在D3DPRESENT_PARAMETERS结构中加入:
present.EnableAutoDepthStencil  = TRUE;
present.AutoDepthStencilFormat  = D3DFMT_D16;
这里告诉DirectX8使用16位的Z缓冲,下一步:
pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
到这里Z缓冲已经设置完成。最后你还要在DrawScene()中调用清除Z缓冲内容的代码:
pID3DDevice->Clear(0,
                   NULL,
                   D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
                   D3DCOLOR_RGBA(0,63,0,0),
                   1.0,
                   0);
MYVERTEX结构改成:
struct MYVERTEX
{
    FLOAT x, y, z; // The transformed position
    DWORD color;   // The vertex color
    FLOAT tu, tv;  // Texture coordinates
};
在InitDirect3D()也作了相应改动,具体可见源代码。
Direct3D中有多种矩阵,在这里只使用其中的三个:世界、视图和投影矩阵。世界矩阵变换会把正方体放在世界坐标系中,视图矩阵变换把正方体放在可视空间内,投影矩阵使正方体看起来有深度感。
BuildMatrices()函数将建立这三个矩阵:
void CFrameWin::BuildMatrices()
{
    D3DXMATRIX matrix;
    D3DXMatrixRotationY(&matrix, timeGetTime() / 1000.0f);
    pID3DDevice->SetTransform(D3DTS_WORLD, &matrix);

    D3DXMatrixLookAtLH(&matrix, &D3DXVECTOR3(0.0f, 3.0f, -5.0f), // 摄像机的空间位置
                                &D3DXVECTOR3(0.0f, 0.0f, 0.0f),  // 摄象机观察点
                                &D3DXVECTOR3(0.0f, 1.0f, 0.0f)); // 摄象机向上方向矢量
    pID3DDevice->SetTransform(D3DTS_VIEW, &matrix);

    // 设置我们的平截面为45度角
    D3DXMatrixPerspectiveFovLH(&matrix, D3DX_PI / 4, 4.0f / 3.0f, 1.0f, 100.0f);
    pID3DDevice->SetTransform(D3DTS_PROJECTION, &matrix);
}
运行本章的例子你将看到一个旋转的正方体。

声明:
本文的SourceCode可以从http://gamedev.363.net得到
欢迎您光临我的主页:http://gamedev.363.net
作者:陈伟凡
E-mail: laical@21cn.com
2001/1/12

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MFC架构下的DirectX8 的相关文章

  • 如何在单独的线程中创建带有进度条的MFC对话框?

    我的应用程序可能需要一段时间才能连接到数据库 此连接是通过单个库函数调用建立的 即我无法将进度更新放在那里并进行回调或类似的操作 我的想法是在连接到数据库之前在单独的线程中创建一个带有进度条的对话框 该对话框将不断更改进度状态CProgre
  • MFC/WinAPI 的大问题

    我需要创建一个带有两个选项卡的表单视图的 SDI 表单 其中封装了多个对话框作为选项卡内容 但表格必须有彩色背景 诸如此类的事情让我讨厌编程 首先 我通过资源编辑器尝试了 CTabControl 尝试了不同的事情 但未记录的行为和没有答案的
  • 在 Visual Studio 2013 中显示带有偏移量的控件

    最近 我将源代码从 Visual Studio 2010 迁移到 Visual Studio 2013 在 Visual Studio 2013 中构建后 控件将显示有偏移 单击下面的链接查看图像 链接到图像 https i stack i
  • 调试 MFC:“mfc100.dll”找不到或打开 pdb

    我正在尝试在调试时进入 MFC 源代码 但是 Visual Studio 显然在加载适当的符号时遇到问题 C WINDOWS symbols dll mfc100 i386 pdb PDB 与图像不匹配 我检查了其他问题 通常建议启用 符号
  • Mfc CComboBoxEx - 如何更改背景颜色

    我有一个派生自 CComboBoxEx 的类 我正在尝试更改背景颜色 我认为它会像 ComboBox 一样工作 使用 SetBkColor 函数 但它不会改变背景颜色 这是我尝试过的 BEGIN MESSAGE MAP CMyComboBo
  • Visual Studio 无法识别我的网络摄像头激光测距仪代码的 MFC 库

    我尝试直接从互联网复制源代码 但由于下面发现的错误 我无法构建 调试整个文件 请帮忙 Error occurred while restoring NuGet packages System ArgumentException The pa
  • 同时显示同一文档的多个视图

    如何说服 MFC 文档 视图体系结构让我同时显示同一文档的两个不同视图 例如 说我的CDocument子类代表某种描述的档案 我想要一个用户界面 其中该存档中的所有条目的名称都显示在CListView子类显示在左侧窗格中 而当前所选条目的详
  • VC++中如何判断链接是否存在?

    我有一个链接 我已通过正则表达式检查该链接是否是有效的 URL 现在 我想检查该链接是否是有效的 http 链接 即它不应该是不存在的链接 VC 6 0 MFC 有办法检查吗 一种选择是尝试使用以下方法从该 URL 获取数据URLOpenB
  • 如何向现有 Win32 C++ 项目添加 MFC 支持?

    我正在创建一个 C 应用程序 它使用 Qt 创建 GUI 但是 我需要使用依赖于 MFC 的第三方库 用于 CString 等 无论如何 是否可以将 MFC 添加到我的应用程序中以允许我使用这个库 或者我需要自己重写它 I saw 这个问题
  • 升级后的 MFC 应用程序看起来仍然很旧

    我有一个用 VC6 编写的 MFC 应用程序 我已将其升级到 VS2015 并且它可以构建并运行 该应用程序是一个主可执行文件 其中包含许多包含对话框的 DLL 然而应用仍然looks就像用 VC6 构建的一样 所有 GUI 组件都没有 W
  • 如何最好地避免 C++/CLI 本机类型中的双重转换

    传统上 我一直使用 MFC 扩展 dll 并使用 dllimport dllexport 导入 导出 但是 当 dll 更改为使用 clr 时 此方法的成本会变得很高 因为调用可能会导致双重转换 我现在的性能受到了巨大的打击 需要停止双重重
  • 使用 CSplitterWnd 在 CChildFrame 中创建多个视图

    我正在使用 MFC MDI 我需要创建如下视图 我的 ChildWnd 分为两部分 它们是LeftView CView 和RightView CScrollView LeftView 分为两部分 TreeView 和 FormView 我怎
  • 创建非托管常规 MFC DLL 并从托管 C++ .NET 应用程序调用它时出现问题

    我有几个关于 DLL 的问题 我尝试了很多 但无法获得完整的图片 大多数示例都是用 C 等编写的 使用 VS2005 中的向导 我创建了一个非托管 MFC 常规 DLL 由于剩余代码 必须是 MFC 然后我尝试将其导入 VS2005 管理的
  • MFC中如何将BYTE数组转换为CString?

    如何在 MFC 中将 BYTE 数组转换为 CString 试试这个 例如 如果 x 是你的字节数组 那么 BYTE x 5 x 0 A x 1 0 x 2 B x 3 C x 4 0 CString str LPCSTR x sizeof
  • 如何找到激活时打开给定 HMENU 的菜单项(如果有)?

    我想用原型实现一个功能 Locates the menu item of the application which caused the given menu mnu to show up return true if the given
  • 如何停止对辅助隐式加载 DLL 的 DLL 劫持

    例如 COMDLG32 DLL 隐式链接到以下系统 DLL 以及其他 xmllite dll dll srvcli dll wkscli dll 链接信息库 netutils dll 微星 dll 由于这些是由操作系统隐式加载的 而不是使用
  • MinGW支持MFC吗?

    我已经使用 MinGW 开发了 WinAPI 应用程序 没有出现任何问题 现在 我可以用 MFC 做同样的事情吗 我只是在这里猜测 但我认为您需要购买 Visual Studio 的副本才能获得使用 MFC 的许可证 MFC 也不因其对 C
  • 捕获由纯 C++ dll 中的 MFC 应用程序生成的 Windows 消息

    首先 这可能吗 我有一个与某些硬件接口的第三方 dll 它是用MFC编写的 我 从 dll 供应商处 收到了一个示例 Visual Studio 2010 解决方案 该解决方案只有一个项目 调用相关第三方 dll 的 MFC 应用程序 ex
  • C++ 检查 unicode 字符是否为全角

    如何检查unicode字符是否是全角 我使用Win32 MFC 例如 中是全宽 A不是全角 是全宽 F不是全宽 你需要的是检索东亚宽度 http www unicode org reports tr11 的角色 您可以通过解析来做到这一点东
  • 如何通过MFC将应用程序设置保存到注册表中?

    我有一个由 MFC 项目向导创建的 MFC 应用程序 我想在注册表中保存 读取应用程序设置 所以问了这个question https stackoverflow com questions 1880275 good c registry w

随机推荐

  • android studio引入本地外部项目的Module

    方法一 1 File gt New gt Import Module 2 Source directory 这里选择其它工程的module 点击Finish完成 方法二 1 File gt New gt New Module 或在工程上右键
  • git merge冲突解决

    1 git merge冲突了 xff0c 根据提示找到冲突的文件 xff0c 解决冲突 如果文件有冲突 xff0c 那么会有类似的标记 2 修改完之后 xff0c 执行git add 冲突文件名 3 git commit 注意 没有 m选项
  • Java并发之CAS原理分析

    CAS 底层原理 CAS 的思想很简单 xff1a 三个参数 xff0c 一个当前内存值 V 旧的预期值 A 即将更新的值 B xff0c 当且仅当预期值 A 和内存值 V 相同时 xff0c 将内存值修改为 B 并返回 true xff0
  • git 删除分支

    删除一个已被终止的分支 如果需要删除的分支不是当前正在打开的分支 xff0c 使用branch d直接删除 git branch d lt branch name gt 异常 error Cannot delete branch 39 xx
  • 异常 Caused by: java.lang.ClassNotFoundException: Didn‘t find class “...“on path: DexPathList

    解决方法 xff1a Android的项目目录里是有两个build文件夹的 xff0c 一个是 xff1a 项目目录 app build xff0c 另一个是 xff1a 项目目录 build Build gt Clean Project
  • java消息队列,业务应用场景概述

    1 异步处理 场景说明 xff1a 用户注册后 xff0c 需要发注册邮件和注册短信 传统的做法有两种 1 串行的方式 xff1b 2 并行方式 a 串行方式 xff1a 将注册信息写入数据库成功后 xff0c 发送注册邮件 xff0c 再
  • TCP三次握手,四次挥手

    三次握手 xff1a 第一次握手 SYN 61 1 seq 61 x xff0c 发送完毕后 xff0c 客户端进入 SYN SEND 状态 第二次握手 SYN 61 1 ACK 61 1 seq 61 y ACKnum 61 x 43 1
  • 206. 反转链表

    方法一 xff1a 迭代 假设链表为 1 2 3 xff0c 我们想要把它改成 1 2 3 在遍历链表时 xff0c 将当前节点的 next 指针改为指向前一个节点 由于节点没有引用其前一个节点 xff0c 因此必须事先存储其前一个节点 在
  • 启动不了docker怎么办?关于docker报错

    常常有时候电脑重启之后或者前一天正常关机第二天就启动不了的问题 xff1f 问题描述 从terminal启动ubuntu1804报错 参考的对象类型不支持尝试的操作 直接启动ubuntu1804也不行 解决方法 以左下角鼠标右键管理员身份打
  • Java 并发编程(一)

    多线程带来的风险 public class Unsafe private int chenmo public int add return chenmo 43 43 上面这段代码在单线程的环境中可以正确执行 xff0c 但在多线程的环境中则
  • Java并发编程(二):保证共享变量的原子性

    怎么让一个类在多线程的环境下是安全的 xff0c 有 3 条法则 xff0c 让我来告诉你 xff1a 1 不在线程之间共享状态变量 2 将状态变量改为不可变 3 访问状态变量时使用同步 那你可能要问 xff0c 状态变量是什么 xff1f
  • Java 并发编程(三):保证共享变量的可见性

    Java 内存模型 xff08 Java Memory Model xff0c 简称 JMM xff09 描述了 Java 程序中各种变量 xff08 线程之间的共享变量 xff09 的访问规则 xff0c 以及在 JVM 中将变量存储到内
  • Java 并发编程(四):保证对象的线程安全性

    02 线程安全类 设计一个线程安全类需要三个步骤 xff1a 1 xff09 找出表示对象状态的所有变量 2 xff09 对变量进行有效性约束 3 xff09 增加类的并发访问策略 我在作者说的基础上做了微调 xff0c 读起来更加容易理解
  • gradle依赖变量

    settings gradle对象生成早于app build gradle甚至早于根目录的build gradle 所以在build gradle里声明ext someVar 61 xxx 变量无效 settings无法访问 因此在grad
  • AudioTrack分析

    第一部分 AudioTrack分析 一 目的 本文的目的是通过从Audio系统来分析Android的代码 xff0c 包括Android自定义的那套机制和一些常见类的使用 xff0c 比如Thread xff0c MemoryBase等 分
  • git 报错信息:SSL certificate problem: certificate has expired 解决方案

    执行命令 git config global http sslVerify false 再次执行 git pull 成功拉取
  • 获取本机号码及sim卡信息

    一 SIM卡存储的数据可分为四类 xff0c 它们分别是 xff1a 第一类是固定存放的数据 这类数据在移动电话机被出售之前由SIM卡中心写入 xff0c 包括国际移动用户识别号 xff08 IMSI xff09 鉴权密钥 xff08 KI
  • Socket粘包问题的3种解决方案

    在 Java 语言中 xff0c 传统的 Socket 编程分为两种实现方式 xff0c 这两种实现方式也对应着两种不同的传输层协议 xff1a TCP 协议和 UDP 协议 xff0c 但作为互联网中最常用的传输层协议 TCP xff0c
  • Android aar包的使用 打包aar后报错ClassNotFoundException,aar中有dependencies依赖的情况;

    示例 xff1a 现有A xff0c B两个library module都是本地的 xff0c A引用B xff0c 我把A打成了aar库 xff0c 打出来之后却没有B的内容 xff0c 导致我的主工程引用A之后 xff0c 执行某个应用
  • MFC架构下的DirectX8

    MFC架构下的DirectX8 第一章 MFC框架 DX8MFC 这里的MFC框架指的是一个符合游戏开发应用的框架 xff0c 当然你也可以写一个符合你要求的MFC框架 如果你对MFC比较熟悉的话可以直接从第二章开始阅读 本框架是以后几个例