• duilib学习 --- 360demo 学习


    我想通过360demo的学习,大概就能把握duilib的一般用法,同时引申出一些普遍问题,和普遍解决方法。并在此分享一些链接和更多内容的深入学习。。。。。

    原谅我是一个菜鸟,什么都想知道得清清楚楚。。。。god,还有一堆书要看,看完是否就会有豁然开朗的感觉呢?

    stdafx.h:

     1 #if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
     2 #define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_
     3 
     4 #pragma once
     5 
     6 #define WIN32_LEAN_AND_MEAN    
     7 #define _CRT_SECURE_NO_DEPRECATE
     8 
     9 #include <windows.h>
    10 #include <objbase.h>
    11 #include <zmouse.h>
    12 
    13 #include "..DuiLibUIlib.h"
    14 
    15 using namespace DuiLib;
    16 
    17 #ifdef _DEBUG
    18 #   ifdef _UNICODE
    19 #       pragma comment(lib, "..\bin\DuiLib_ud.lib")
    20 #   else
    21 #       pragma comment(lib, "..\bin\DuiLib_d.lib")
    22 #   endif
    23 #else
    24 #   ifdef _UNICODE
    25 #       pragma comment(lib, "..\bin\DuiLib_u.lib")
    26 #   else
    27 #       pragma comment(lib, "..\bin\DuiLib.lib")
    28 #   endif
    29 #endif
    30 
    31 //{{AFX_INSERT_LOCATION}}
    32 // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
    33 
    34 #endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)

    第1,2,34行:

    1 #if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)

    2 #define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_

    自动生成的吧,大概就是为了避免stdafx.h被重复包含吧。

    第4行:#pragma once

    这个不多说了,我另一篇随笔有说

    第6行:#define WIN32_LEAN_AND_MEAN

    参考:更快的生成和更小的头文件

    非mfc应用程序可定义这个宏

    第7行:#define _CRT_SECURE_NO_DEPRECATE

     参考:CRT Security Enhancements (Windows Embedded CE 6.0)

    这里说得非常详细,主要是涉及一些旧crt api的安全问题,例如strcpy没有溢出检查等。。。

    推荐方法是使用取而代之的strcpy_s等带安全检查的函数,定义上述的宏是为了消除编译警告。。。

    第17-29:duilib不同版本的调用方法

    参考:这里

    stdafx.cpp:

     1 #include "stdafx.h"
     2 
     3 #if defined _M_IX86
     4 #pragma comment(linker, "/manifestdependency:"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'"")
     5 #elif defined _M_IA64
     6 #pragma comment(linker, "/manifestdependency:"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'"")
     7 #elif defined _M_X64
     8 #pragma comment(linker, "/manifestdependency:"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'"")
     9 #else
    10 #pragma comment(linker, "/manifestdependency:"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"")
    11 #endif

    参考:Win32 创建控件风格不是Win XP解决方案

    主要处理的是产生窗口的样式问题

    ControlEx.h:

     1 #pragma once
     2 
     3 class ComputerExamineUI : public CContainerUI
     4 {
     5 public:
     6     ComputerExamineUI()
     7     {
     8         CDialogBuilder builder;
     9         CContainerUI* pComputerExamine = static_cast<CContainerUI*>(builder.Create(_T("ComputerExamine.xml"), (UINT)0));
    10         if( pComputerExamine ) {
    11             this->Add(pComputerExamine);
    12         }
    13         else {
    14             this->RemoveAll();
    15             return;
    16         }
    17     }
    18 };
    19 
    20 class CDialogBuilderCallbackEx : public IDialogBuilderCallback
    21 {
    22 public:
    23     CControlUI* CreateControl(LPCTSTR pstrClass) 
    24     {
    25         if( _tcscmp(pstrClass, _T("ComputerExamine")) == 0 ) return new ComputerExamineUI;
    26         return NULL;
    27     }
    28 };

    这里主要演示了自定义控件的使用方法,这部分可以等到分析控件生成过程的时候再详细说一下

    360safe.cpp:

      1 #include "stdafx.h"
      2 #include <exdisp.h>
      3 #include <comdef.h>
      4 #include "ControlEx.h"
      5 
      6 class C360SafeFrameWnd : public CWindowWnd, public INotifyUI
      7 {
      8 public:
      9     C360SafeFrameWnd() { };
     10     LPCTSTR GetWindowClassName() const { return _T("UIMainFrame"); };/*overrride from CWindowWnd,内部RegisterSuperclass,RegisterWindowClass,::CreateWindowEx会用到的窗口类名*/
     11     UINT GetClassStyle() const { return CS_DBLCLKS; };//override from CWindowWnd,内部调用RegisterWindowClass会用到
     12     void OnFinalMessage(HWND /*hWnd*/) { delete this; };//见解释1
     13    //
     14     void Init() {
     15         m_pCloseBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("closebtn")));/通过xml中定义的控件名,调用CPaintManager的findControl去查询hash表得到控件对象。通过静态类型转化绑定到程序控件上,见解释2*/
     16         m_pMaxBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("maxbtn")));
     17         m_pRestoreBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("restorebtn")));
     18         m_pMinBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("minbtn")));
     19     }
     20 
     21     void OnPrepare() {
     22     }
     23 
     24     void Notify(TNotifyUI& msg)//override form INotifyUI,详见解释3
     25     {
     26         if( msg.sType == _T("windowinit") ) OnPrepare();
     27         else if( msg.sType == _T("click") ) {
     28             if( msg.pSender == m_pCloseBtn ) {
     29                 PostQuitMessage(0);
     30                 return; 
     31             }
     32             else if( msg.pSender == m_pMinBtn ) { 
     33                 SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); return; }
     34             else if( msg.pSender == m_pMaxBtn ) { 
     35                 SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0); return; }
     36             else if( msg.pSender == m_pRestoreBtn ) { 
     37                 SendMessage(WM_SYSCOMMAND, SC_RESTORE, 0); return; }
     38         }
     39         else if(msg.sType==_T("selectchanged"))
     40         {
     41             CStdString name = msg.pSender->GetName();
     42             CTabLayoutUI* pControl = static_cast<CTabLayoutUI*>(m_pm.FindControl(_T("switch")));
     43             if(name==_T("examine"))
     44                  pControl->SelectItem(0);
     45             else if(name==_T("trojan"))
     46                  pControl->SelectItem(1);
     47             else if(name==_T("plugins"))
     48                 pControl->SelectItem(2);
     49             else if(name==_T("vulnerability"))
     50                 pControl->SelectItem(3);
     51             else if(name==_T("rubbish"))
     52                 pControl->SelectItem(4);
     53             else if(name==_T("cleanup"))
     54                 pControl->SelectItem(5);
     55             else if(name==_T("fix"))
     56                 pControl->SelectItem(6);
     57             else if(name==_T("tool"))
     58                 pControl->SelectItem(7);
     59         }
     60     }
     61 
     62     LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     63     {
     64         LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
     65         styleValue &= ~WS_CAPTION;// 去掉标题栏
     66         ::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);//设置窗口重叠时的绘制方式
     67 
     68         m_pm.Init(m_hWnd);//设置父窗口句柄,详见解释4
     69         CDialogBuilder builder;
     70         CDialogBuilderCallbackEx cb;
     71         CControlUI* pRoot = builder.Create(_T("skin.xml"), (UINT)0,  &cb, &m_pm);/*加载xml,创建界面,详见解释5,路径是从main函数那里调用CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + _T("skin"));设置的*/
     72         ASSERT(pRoot && "Failed to parse XML");
     73         m_pm.AttachDialog(pRoot);/*添加根节点指针到hash表,绘制过程应该回遍历这个hash表,绘制过程待续*/
     74         m_pm.AddNotifier(this);/添加界面消息通知,联合上面的Notify,和下面的HandleMessge不难看出这是一个观察者模式,详见解释3*/
     75 
     76         Init();//控件绑定,见上面的解释
     77         return 0;
     78     }
     79 
     80     LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     81     {
     82         bHandled = FALSE;
     83         return 0;
     84     }
     85 
     86     LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     87     {
     88         ::PostQuitMessage(0L);
     89 
     90         bHandled = FALSE;
     91         return 0;
     92     }
     93 
     94     LRESULT OnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     95     {
     96         if( ::IsIconic(*this) ) bHandled = FALSE;
     97         return (wParam == 0) ? TRUE : FALSE;
     98     }
     99 
    100     LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    101     {
    102         return 0;
    103     }
    104 
    105     LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    106     {
    107         return 0;
    108     }
    109 
    110     LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)//由于隐藏了windows的标题栏,所以自己处理点击事件
    111     {
    112         POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);
    113         ::ScreenToClient(*this, &pt);
    114 
    115         RECT rcClient;
    116         ::GetClientRect(*this, &rcClient);
    117          // 这段屏蔽了鼠标拖动区域响应
    118 //         if( !::IsZoomed(*this) ) {
    119 //             RECT rcSizeBox = m_pm.GetSizeBox();
    120 //             if( pt.y < rcClient.top + rcSizeBox.top ) {
    121 //                 if( pt.x < rcClient.left + rcSizeBox.left ) return HTTOPLEFT;
    122 //                 if( pt.x > rcClient.right - rcSizeBox.right ) return HTTOPRIGHT;
    123 //                 return HTTOP;
    124 //             }
    125 //             else if( pt.y > rcClient.bottom - rcSizeBox.bottom ) {
    126 //                 if( pt.x < rcClient.left + rcSizeBox.left ) return HTBOTTOMLEFT;
    127 //                 if( pt.x > rcClient.right - rcSizeBox.right ) return HTBOTTOMRIGHT;
    128 //                 return HTBOTTOM;
    129 //             }
    130 //             if( pt.x < rcClient.left + rcSizeBox.left ) return HTLEFT;
    131 //             if( pt.x > rcClient.right - rcSizeBox.right ) return HTRIGHT;
    132 //         }
    133 
    134         RECT rcCaption = m_pm.GetCaptionRect();
    135         if( pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right 
    136             && pt.y >= rcCaption.top && pt.y < rcCaption.bottom ) {
    137                 CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(pt));
    138                 if( pControl && _tcscmp(pControl->GetClass(), _T("ButtonUI")) != 0 && 
    139                     _tcscmp(pControl->GetClass(), _T("OptionUI")) != 0 &&
    140                     _tcscmp(pControl->GetClass(), _T("TextUI")) != 0 )
    141                     return HTCAPTION;
    142         }
    143 
    144         return HTCLIENT;
    145     }
    146 
    147     LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)//这里应该是为了边框圆角化
    148     {
    149         SIZE szRoundCorner = m_pm.GetRoundCorner();
    150         if( !::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0) ) {
    151             CRect rcWnd;
    152             ::GetWindowRect(*this, &rcWnd);
    153             rcWnd.Offset(-rcWnd.left, -rcWnd.top);
    154             rcWnd.right++; rcWnd.bottom++;
    155             HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy);
    156             ::SetWindowRgn(*this, hRgn, TRUE);
    157             ::DeleteObject(hRgn);
    158         }
    159 
    160         bHandled = FALSE;
    161         return 0;
    162     }
    163 
    164     LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)//控制窗体的显示区域,放大缩小等的范围
    165     {
    166         MONITORINFO oMonitor = {};
    167         oMonitor.cbSize = sizeof(oMonitor);
    168         ::GetMonitorInfo(::MonitorFromWindow(*this, MONITOR_DEFAULTTOPRIMARY), &oMonitor);
    169         CRect rcWork = oMonitor.rcWork;
    170         rcWork.Offset(-rcWork.left, -rcWork.top);
    171 
    172         LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam;
    173         lpMMI->ptMaxPosition.x    = rcWork.left;
    174         lpMMI->ptMaxPosition.y    = rcWork.top;
    175         lpMMI->ptMaxSize.x        = rcWork.right;
    176         lpMMI->ptMaxSize.y        = rcWork.bottom;
    177 
    178         bHandled = FALSE;
    179         return 0;
    180     }
    181 
    182     LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    183     {
    184         // 有时会在收到WM_NCDESTROY后收到wParam为SC_CLOSE的WM_SYSCOMMAND
    185         if( wParam == SC_CLOSE ) {
    186             ::PostQuitMessage(0L);
    187             bHandled = TRUE;
    188             return 0;
    189         }
    190         BOOL bZoomed = ::IsZoomed(*this);
    191         LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam);
    192         if( ::IsZoomed(*this) != bZoomed ) {
    193             if( !bZoomed ) {
    194                 CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("maxbtn")));
    195                 if( pControl ) pControl->SetVisible(false);
    196                 pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("restorebtn")));
    197                 if( pControl ) pControl->SetVisible(true);
    198             }
    199             else {
    200                 CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("maxbtn")));
    201                 if( pControl ) pControl->SetVisible(true);
    202                 pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("restorebtn")));
    203                 if( pControl ) pControl->SetVisible(false);
    204             }
    205         }
    206         return lRes;
    207     }
    208 
    209     // override from CWindowWnd
    210     LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)//详见解释3
    211     {
    212         LRESULT lRes = 0;
    213         BOOL bHandled = TRUE;
    214         switch( uMsg ) {
    215         case WM_CREATE:        lRes = OnCreate(uMsg, wParam, lParam, bHandled); break;
    216         case WM_CLOSE:         lRes = OnClose(uMsg, wParam, lParam, bHandled); break;
    217         case WM_DESTROY:       lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break;
    218         case WM_NCACTIVATE:    lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break;
    219         case WM_NCCALCSIZE:    lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;
    220         case WM_NCPAINT:       lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break;
    221         case WM_NCHITTEST:     lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;
    222         case WM_SIZE:          lRes = OnSize(uMsg, wParam, lParam, bHandled); break;
    223         case WM_GETMINMAXINFO: lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break;
    224         case WM_SYSCOMMAND:    lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break;
    225         default:
    226         bHandled = FALSE;
    227         }
    228         if( bHandled ) return lRes;
    229         if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes;
    230         return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
    231     }
    232 
    233 public:
    234     CPaintManagerUI m_pm;//为什么要是public。。。。
    235 
    236 private:
    237     CButtonUI* m_pCloseBtn;
    238     CButtonUI* m_pMaxBtn;
    239     CButtonUI* m_pRestoreBtn;
    240     CButtonUI* m_pMinBtn;
    241     //...
    242 };
    243 
    244 
    245 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow)
    246 {
    247     CPaintManagerUI::SetInstance(hInstance);//绑定实例句柄
    248     CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + _T("skin"));//设置资源路径,里面应该是个zip包
    249     CPaintManagerUI::SetResourceZip(_T("360SafeRes.zip"));//设置zip包名称,资源都用zip打包好的
    250 
    251     HRESULT Hr = ::CoInitialize(NULL);//com初始化
    252     if( FAILED(Hr) ) return 0;
    253 
    254     C360SafeFrameWnd* pFrame = new C360SafeFrameWnd();
    255     if( pFrame == NULL ) return 0;
    256     pFrame->Create(NULL, _T("360安全卫士"), UI_WNDSTYLE_FRAME, 0L, 0, 0, 800, 572);//详见解释6
    257     pFrame->CenterWindow();
    258     ::ShowWindow(*pFrame, SW_SHOW);
    259 
    260     CPaintManagerUI::MessageLoop();//开始消息循环,详见解释3
    261 
    262     ::CoUninitialize();//注销com
    263     return 0;
    264 }

     解释1:void OnFinalMessage(HWND /*hWnd*/) { delete this; };

    override from CWindowWnd
    调用来自注册窗体的回调函数:
     1 LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     2 {
     3     CWindowWnd* pThis = NULL;
     4     if( uMsg == WM_NCCREATE ) {
     5         LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
     6         pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);
     7         pThis->m_hWnd = hWnd;
     8         ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
     9     } 
    10     else {
    11         pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
    12         if( uMsg == WM_NCDESTROY && pThis != NULL ) {
    13             LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
    14             ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);
    15             if( pThis->m_bSubclassed ) pThis->Unsubclass();
    16             pThis->m_hWnd = NULL;
    17             pThis->OnFinalMessage(hWnd);//这里用到了onFinanlMessage
    18             return lRes;
    19         }
    20     }
    21     if( pThis != NULL ) {
    22         return pThis->HandleMessage(uMsg, wParam, lParam);
    23     } 
    24     else {
    25         return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    26     }
    27 }
    
    

    主要是在接收到WM_NCDESTROY消息的时候,执行最后的一些处理,这里是调用delete this,销毁对象,禁止进一步对对象成员的访问,参考:这里

    附:

    WM_NCCLIENT 消息在 WM_CREATE 之前,

    WM_NCDESTROY 在 WM_DESTROY 之后,

    包括标题栏、窗口边框、最大、最小按钮、滚动条等都属于 non-client 区域。

    引用自:http://bbs.csdn.net/topics/350112762

    解释2:控件这块,会有后续章节,更深入地去了解

    解释3:消息循环,也会有后续章节深入了解

    解释4:m_pm.Init(m_hWnd);

    1 void CPaintManagerUI::Init(HWND hWnd)
    2 {
    3     ASSERT(::IsWindow(hWnd));
    4     // Remember the window context we came from
    5     m_hWndPaint = hWnd;
    6     m_hDcPaint = ::GetDC(hWnd);
    7     // We'll want to filter messages globally too
    8     m_aPreMessages.Add(this);/*添加当前paintmanager对象指针到类静态成员中,用于一些消息的处理,这部分如果有机会说paintManager应该会说说,各位也可以自己看吧*/
    9 }

    当前窗口句柄保存到paintManager

    解释5:ControlUI* pRoot = builder.Create(_T("skin.xml"), (UINT)0, &cb, &m_pm);

    如果有时间说builder的xml解析,会深入了解

    解释6:pFrame->Create(NULL, _T("360安全卫士"), UI_WNDSTYLE_FRAME, 0L, 0, 0, 800, 572);

    内部还是调用windows窗体注册过程

     1 HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, const RECT rc, HMENU hMenu)
     2 {
     3     return Create(hwndParent, pstrName, dwStyle, dwExStyle, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hMenu);
     4 }
     5 
     6 HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, int x, int y, int cx, int cy, HMENU hMenu)
     7 {
     8     if( GetSuperClassName() != NULL && !RegisterSuperclass() ) return NULL;
     9     if( GetSuperClassName() == NULL && !RegisterWindowClass() ) return NULL;
    10     m_hWnd = ::CreateWindowEx(dwExStyle, GetWindowClassName(), pstrName, dwStyle, x, y, cx, cy, hwndParent, hMenu, CPaintManagerUI::GetInstance(), this);
    11     ASSERT(m_hWnd!=NULL);
    12     return m_hWnd;
    13 }
  • 相关阅读:
    Making Pimpl Easy
    OpenCV学习资源
    openCV基础学习(1)
    fl2440原始linux代码的启动日志
    《s3c2440+lan91c111 vxworks驱动调试》疑惑
    使用并行的方法计算斐波那契数列 (Fibonacci)
    [译] SolidWorks的发展历史(1994~2007)
    翻译介绍一点CAD发展的历史
    使用fopen的两点注意事项
    四元数(Quaternions)简介
  • 原文地址:https://www.cnblogs.com/riversHahaha/p/4580977.html
Copyright © 2020-2023  润新知