zoukankan      html  css  js  c++  java
  • C#+OpenGL编程之再见小桃子(The Tao Framework)

    本文基础:

      C#+OpenGL编程之OpenGL 纹理载入

      C#+OpenGL编程之OpenGL 多重纹理

      

    小桃子The Tao FrameworkTao提供的所有库都是完全开源的。其中的多数库都可以免费用在商业项目中,该框架较其它框架实现更简单、容易,代码也简洁易读。

      很遗憾的是这个框架已经不再开发了,作为程序猿不得不想点其他的框架了。

      下面的课程,我们将使用另外一个框架,OpenGL DotNet 官方网站:http://www.taylaninan.com/opengl-dotnet

      作为我们的开发框架,比起 小桃子的后继者OpenTK更接近C代码风格,要知道,做什么事都要跟随大流。现在市面上的游戏引擎都是C或者C++,而很多OpenGL教程也是基于C或者C++,标新立异等于在装酷。

      首先我们实现最早的基础实例吧:

    using System;  
    using System.Collections.Generic;  
    using System.Text;  
    using OpenGLDotNet;  
      
    namespace OpenGLTK  
    {  
        ///OpenGLDotNet需要修改  
        ///glut32.dll ->freeglut.dll  
        ///GLUT最初是《OpenGL红皮书(第二版)》[注2]中的示例程序。自那以后,GLUT简单、跨平台的特点,使其在各种实际应用中广泛应用。  
        ///目前最后版本GLUT v3.7的历史可追溯至1998年8月,且该项目似乎已经被废弃。它的许可证禁止任何人发布修改后的库代码。  
        ///毋庸置疑GLUT已经很老了,真的需要改善。此外,GLUT的许可证与一些软件发行不兼容(如XFree86的)。  
        ///一个轻量级的,开源的,跨平台的library。支持OpenGL及OpenGL ES,用来管理窗口,读取输入,处理事件等。因为OpenGL没有窗口管理的功能,所以很多热心的人写了工具来支持这些功能,比如早期的glut,现在的freeglut等。  
        ///修改代码位置 GLU.Functions.cs  
      
      
        ///找不到glu32.dll解决方法:  
        ///glu32.dll 改为->GLU32.dll,具体文件名大小写可以去 系统目录搜索这个文件我的是server2012   
        ///修改代码位置 GLUT.Functions.cs  
      
        ///tao->OpenGLDotNet 需要修改的地方  
        ///函数去掉glu和gl部分,例如  
        ///GL.glPopMatrix();->GL.PopMatrix();  
        ///Gl.gl->GL.  
        ///Gl.GL_->GL.GL_  
        /// Glu.glu->GLU.  
        ///当然你可以修改源代码private ->public  
        ///修改代码位置 GL.CoreDelegates.cs  
      
        /// <summary>  
        /// 第二章 Opengl程序框架 C# by 大师♂罗莊  
        ///   
        /// </summary>  
        class Examplefirst : IDisposable  
        {  
             String title = "第二章 Opengl程序框架";  
            ///窗口大小  
            internal int windowWidth, windowHeight;  
        
            //当前帧  
            internal float currentTime, startTime;  
      
            //鼠标位置  
            internal int mouseX, mouseY, button,  state;  
            //键盘按下  
      
            internal byte key;  
            public Examplefirst()  
            {  
                GLConfig.Init(0, 0, title, 25, 25, 1024, 768);  
                GL.Init(true);  
                GLUT.KeyboardFunc(Keyboard);  
                GLUT.MouseFunc(Mouse);  
                GLUT.IdleFunc(Idle);  
                GLUT.ReshapeFunc(Reshape);  
                GLUT.MotionFunc(Motion);  
                GLUT.DisplayFunc(Display);  
             }  
      
            /// <summary>  
            /// glut键盘回调函数    
            /// </summary>  
            /// <param name="key"></param>  
            /// <param name="x"></param>  
            /// <param name="y"></param>  
            public virtual void Keyboard(byte key, int x, int y)  
            {  
                this.key = key;  
            }  
      
            /// <summary>  
            ///  glut鼠标按下与释放回调函数    
            /// </summary>  
            /// <param name="button"></param>  
            /// <param name="state"></param>  
            /// <param name="x"></param>  
            /// <param name="y"></param>  
            public virtual void Mouse(int button, int state, int x, int y)  
            {  
      
                this.button = button;  
                this.state = state;  
                this.mouseX = x;  
                this.mouseY = y;  
                return;  
            }  
      
            /// <summary>  
            /// glut空闲处理回调函数  
            /// </summary>  
            public void Idle()  
            {  
                currentTime = System.Environment.TickCount;  
                Update(currentTime - startTime);  
                startTime = currentTime;  
                return;  
            }  
      
            /// <summary>  
            ///  glut窗口重置回调函数    
            /// </summary>  
            /// <param name="width"></param>  
            /// <param name="height"></param>  
            public void Reshape(int width, int height)  
            {  
                windowWidth = width;  
                windowHeight = height;  
                //防止除零问题  
                windowHeight = windowWidth > 0 ? windowHeight : 1;  
               InitGL(windowWidth, windowHeight);  
      
            }  
      
            /// <summary>  
            /// glut鼠标移动回调函数    
            /// </summary>  
            /// <param name="x"></param>  
            /// <param name="y"></param>  
            public void Motion(int x, int y)  
            {  
                return;  
            }  
      
            /// <summary>  
            /// glut描绘回调函数    
            /// </summary>  
            public void Display()  
            {  
                //我感觉用这个得重新设置下lookUP才行  
                iniView(windowWidth, windowHeight);  
                DrawGLScene();  
                  
            }  
      
            /// <summary>  
            /// 入口点  
            /// </summary>  
            public void Run()  
            {  
                GLUT.MainLoop();  
            }  
      
      
            /// <summary>  
            /// 更新用  
            /// </summary>  
            public virtual void Update(float milliseconds)  
            {  
                if (key == 27)                              // Escape 按下,退出  
                {  
                    this.Dispose();  
                }  
                return;  
            }  
      
            /// <summary>  
            /// 原书的初始化方法,C# by 大师♂罗莊  
            /// </summary>  
            /// <param name="windowWidth">窗口宽</param>  
            /// <param name="windowHeight">窗口高</param>  
            /// <returns></returns>  
            Boolean InitGL(int windowWidth, int windowHeight)  
            {  
                // 设置视口 viewport  
                GL.Viewport(0, 0, windowWidth, windowHeight);  
      
                //启用阴影平滑  
                GL.ShadeModel(GL.GL_SMOOTH);  
      
                //启用反走样  
                GL.Hint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);  
               
                // 设置投影模式 projection matrix  
                GL.MatrixMode(GL.GL_PROJECTION);  
                GL.LoadIdentity();  
                GL.Disable(GL.GL_DITHER);  
                return true;  
            }  
            /// <summary>  
            /// 初始化视口投影,本例子没有采用原书例子,自定义的视口  
            /// </summary>  
            public virtual void iniView(int windowWidth, int windowHeight)  
            {  
                GLU.Perspective(65, windowWidth / (double)windowHeight, 1, 100);  
                // 选择模型观察矩阵 modelview matrix  
                GL.MatrixMode(GL.GL_MODELVIEW);  
                //重置模型观察矩阵  
                GL.LoadIdentity();  
                GLU.LookAt(0, 1, 0,  // 眼睛位置  
                    0, 20, 0,           // 观察点  
                    0, 0, 1);           // 怎么看  
            }  
      
            /// <summary>  
            /// 原书的绘制方法 C# by 大师♂罗莊  
            /// <param name="currentTime">当前帧</param>  
            /// </summary>  
            public virtual void DrawGLScene()  
            {  
                // 重置黑色背景  
                GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);  
                GL.Clear(GL.GL_COLOR_BUFFER_BIT);  
                 // 画三角形  
                GL.Translatef(0, 14, 0);  
                GL.Begin(GL.GL_TRIANGLES);  
                GL.Color3f(1, 0, 0);  
                GL.Vertex3f(-5, 0, -4);  
                GL.Color3f(0, 1, 0);  
                GL.Vertex3f(5, 0, -4);  
                GL.Color3f(0, 0, 1);  
                GL.Vertex3f(0, 0, 6);  
                GL.End();  
                GLUT.SwapBuffers();  
            }  
      
      
            public void Dispose()  
            {  
                GLUT.KeyboardFunc(null);  
                GLUT.MouseFunc(null);  
                GLUT.IdleFunc(null);  
                GLUT.ReshapeFunc(null);  
                GLUT.MotionFunc(null);  
                GLUT.DestroyWindow(GLUT.GetWindow());  
            }  
        }  
    }  

    OpenGL DotNet也非十全十美,需要我们修改源代码:

      1、首先一个问题就是使用glut32.dll,这个库已经是上个世纪的库了,我们需要修改GLU.Functions.cs 里面把glut32.dll改为freeglut.dll

      2、找不到glu32.dll,这个要大家自己去windows目录看文件名大小写,在我的2012上面文件名为GLU32.dll

      然后就可以把桃子框架代码移植过来了。

      上面的代码就和C很相似了,使用GLUT函数实现窗口管理,代码量从160行升至220行。

      下面我们移植下多重纹理吧。

    using System;  
    using System.Collections.Generic;  
    using System.Drawing;  
    using System.IO;  
    using System.Text;  
    using System.Windows.Forms;  
    using OpenGLDotNet;  
      
    namespace OpenGLTK  
    {  
        /// <summary>  
        /// 自制的纹理载入类 C# by 大师♂罗莊  
        /// </summary>  
        class TextureLoad : IDisposable  
        {  
            public uint[] ID = new uint[3];  
            Bitmap image;  
            public bool Load(String fileName)  
            {  
                ///原则上材质只应该在初始化时候载入一次,否则会影响性能  
                if (image != null)  
                {  
                    return true;  
                }  
                FileInfo file = new FileInfo(fileName);  
                if (file.Exists == false)  
                {  
                    MessageBox.Show("无法载入" + fileName);  
                    return false;  
                }  
                try  
                {  
                    if (file.Extension.ToUpper() == ".TGA")  
                    {  
                        ///http://blog.csdn.net/zgke/article/details/4667499  
                        ///C# 载入TGA 类,自行参考,这里不再列出  
                        ImageTGA tga = new ImageTGA(fileName);  
                        image = tga.Image;  
                    }  
                    else  
                    {  
                        image = new Bitmap(fileName);  
                    }  
      
                }  
                catch (System.ArgumentException)  
                {  
                    MessageBox.Show("无法载入" + fileName);  
                    return false;  
                }  
      
                if (image != null)  
                {  
                    image.RotateFlip(RotateFlipType.RotateNoneFlipY);  
                    System.Drawing.Imaging.BitmapData bitmapdata;  
                    Rectangle rect = new Rectangle(0, 0, image.Width, image.Height);  
      
                    ///Nearest Linear MipMapped三个纹理实现,本文暂时不考虑  
                    //bitmapdata = image.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);  
                    //GL.GenTextures(3, this.texture);  
      
                    //// Create Nearest Filtered Texture  
                    //GL.BindTexture(GL.GL_TEXTURE_2D, this.texture[0]);  
                    //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);  
                    //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);  
                    //GL.TexImage2D(GL.GL_TEXTURE_2D, 0, (int)GL.GL_RGB, image.Width, image.Height, 0, GL.GL_BGR_EXT, GL.GL_UNSIGNED_BYTE, bitmapdata.Scan0);  
                    //// Create Linear Filtered Texture  
                    //GL.BindTexture(GL.GL_TEXTURE_2D, this.texture[1]);  
                    //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);  
                    //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);  
                    //GL.TexImage2D(GL.GL_TEXTURE_2D, 0, (int)GL.GL_RGB, image.Width, image.Height, 0, GL.GL_BGR_EXT, GL.GL_UNSIGNED_BYTE, bitmapdata.Scan0);  
                    //// Create MipMapped Texture  
                    //GL.BindTexture(GL.GL_TEXTURE_2D, this.texture[2]);  
                    //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);  
                    //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_NEAREST);  
                    //GL.uBuild2DMipmaps(GL.GL_TEXTURE_2D, (int)GL.GL_RGB, image.Width, image.Height, GL.GL_BGR_EXT, GL.GL_UNSIGNED_BYTE, bitmapdata.Scan0);  
                    //image.UnlockBits(bitmapdata);  
      
                    /** 生成纹理对象名称 */  
                    GL.GenTextures(3, ID);  
      
                    /** 创建纹理对象 */  
                    GL.BindTexture(GL.GL_TEXTURE_2D, ID[0]);  
      
                    /** 控制滤波 */  
                    GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, (int)GL.GL_LINEAR);  
                    GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, (int)GL.GL_LINEAR);  
                    GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, (int)GL.GL_REPEAT);  
                    GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, (int)GL.GL_REPEAT);  
      
                    bitmapdata = image.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);  
                    /** 创建纹理 */  
                    GLU.Build2DMipmaps(GL.GL_TEXTURE_2D, (int)GL.GL_RGB, image.Width,  
                                      image.Height, GL.GL_BGR_EXT, GL.GL_UNSIGNED_BYTE,  
                                      bitmapdata.Scan0);  
                    image.UnlockBits(bitmapdata);  
                }  
                return true;  
            }  
      
            public void FreeImage()  
            {  
                /** 释放内存 */  
                if (image != null)  
                {  
                    image.Dispose();  
                }  
            }  
            public void Dispose()  
            {  
                FreeImage();  
            }  
        }  
    }  
    using System;  
    using System.Collections.Generic;  
    using System.IO;  
    using System.Text;  
    using System.Windows.Forms;  
    using OpenGLDotNet;  
      
    namespace OpenGLTK  
    {  
        /// <summary>  
        /// 第四章 OpenGl 多重纹理载入 C# by 大师♂罗莊  
        /// </summary>  
        class OpenGLMultiTexture : Examplefirst  
        {  
            TextureLoad[] m_texture = new TextureLoad[4];  
            bool multitexturing=false;  
            /** 检查是否支持扩展 */  
            string title = "第四章 OpenGl 多重纹理载入";  
      
            public OpenGLMultiTexture()  
                : base()  
            {  
                for (int i = 0; i < 4; i++)  
                {  
                    m_texture[i] = new TextureLoad();//对象数组必须初始化  
                }  
                LoadTexture();  
                GLUT.SetWindowTitle(title);  
                /** 初始化 */  
                if (!initMultiTexture())//和原来不一样,GL.GetString这个函数不能放入动画事件  
                {  
                    MessageBox.Show("您的硬件和驱动不支持多重纹理");  
                    return;  
                }  
      
            }  
      
            /// <summary>  
            /// 检查多重纹理支持  
            /// </summary>  
            /// <param name="input"></param>  
            /// <returns></returns>  
            bool isExtensionSupported(string input)  
            {  
                string extension = GL.GetString(GL.GL_EXTENSIONS);  
      
                return extension.IndexOf(input)>=0;  
            }  
      
              
            bool initMultiTexture()  
            {  
                /** 检查是否支持扩展 */  
                if (isExtensionSupported("GL_ARB_multitexture"))  
                {  
                    return true;  
                }  
                else  
                    return false;  
            }  
      
            /** 载入纹理数据  */  
            bool LoadTexture()  
            {  
                /// 文件名   
                String[] fileName = new String[4] { "wall.bmp", "lightmap.bmp", "bitmap.bmp", "fog.bmp" };  
      
                /// 载入四幅位图   
                for (int i = 0; i < 4; i++)  
                {  
                        if (m_texture[i].Load(Path.Combine(Application.StartupPath, @"Image" + fileName[i]).ToString()) == false)                         /**< 载入位图文件 */  
                        {  
                            MessageBox.Show("无法载入" + fileName[i]);  
                            return false;  
                        }  
                     
      
                }  
                return true;  
      
            }  
      
            /// <summary>  
            /// 初始化视口投影,恢复原书的视口  
            /// </summary>  
            public override void iniView(int windowWidth, int windowHeight)  
            {  
                GLU.Perspective(45.0f, windowWidth / windowHeight, 1.0f, 100.0f);  
                GL.MatrixMode(GL.GL_MODELVIEW);  
                GL.LoadIdentity();  
                GLU.LookAt(0, 1, 0,  // 眼睛位置  
                 0, 20, 0,           // 观察点  
                 0, 0, 1);           // 怎么看  
                
                 
                            
            }  
      
            /** 用户自定义的卸载函数 */  
            public new void Dispose()  
            {  
                base.Dispose();  
                for (int i = 0; i < 4; i++)  
                {  
                    m_texture[i].FreeImage();  
                    GL.DeleteTextures(1, m_texture[i].ID);  
                }  
            }  
            float wrap = 0;      /**< 用于雾的流动 */  
      
            public override void Keyboard(byte key, int x, int y)  
            {  
                if (key == 27)                              // Escape 按下,退出  
                {  
                    this.Dispose();  
                }  
      
                /////** 当按下空格时,开启多重纹理 */  
                if (key == 0x20)  
                {  
                    multitexturing = true;//开启  
                }  
                else  
                {  
                    multitexturing = false;//按下其他键关闭  
                }  
            }  
            /// <summary>  
            /// 重载  
            /// </summary>  
            /// <param name="currentTime"></param>  
            public override void Update(float milliseconds)  
            {  
                wrap += milliseconds /1000;                 //动画 速度请自己调节  
                Display();  
                  
            }  
            /// <summary>  
            /// 重载,使用Draw方法绘图  
            /// </summary>  
            /// <param name="mouseX"></param>  
            /// <param name="currentTime"></param>  
            public override void DrawGLScene()  
            {  
                Draw();  
                GLUT.SwapBuffers();  
            }  
          
            /** 绘制函数 */  
            void Draw()  
            {  
                /** 用户自定义的绘制过程 */  
                GL.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);  
                GL.LoadIdentity();  
      
                GL.Translatef(0.0f, 0.0f, -10.0f);  
      
                /** 激活纹理0,并绑定纹理 */  
                GL.ActiveTextureARB(GL.GL_TEXTURE0_ARB);  
                GL.Enable(GL.GL_TEXTURE_2D);  
                GL.BindTexture(GL.GL_TEXTURE_2D, m_texture[0].ID[0]);  
      
                /** 激活纹理1,并绑定纹理 */  
                GL.ActiveTextureARB(GL.GL_TEXTURE1_ARB);  
      
                /** 如果多重纹理启用,则启用该纹理 */  
                if (multitexturing)  
                    GL.Enable(GL.GL_TEXTURE_2D);  
                else  
                    GL.Disable(GL.GL_TEXTURE_2D);  
      
                GL.BindTexture(GL.GL_TEXTURE_2D, m_texture[1].ID[0]);  
      
                /** 绘制一个四方形墙面 */  
                GL.PushMatrix();  
                GL.Translatef(-2.5f, 0f, 0f);  
                GL.Scalef(2.0f, 2.0f, 2.0f);  
                GL.Begin(GL.GL_QUADS);  
      
                /** 左上点 */  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 0.0f, 1.0f);  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 0.0f, 1.0f);  
                GL.Vertex3f(-1, 1, 0);  
      
                /** 左下点 */  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 0.0f, 0.0f);  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 0.0f, 0.0f);  
                GL.Vertex3f(-1, -1, 0);  
      
                /** 右下点 */  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 1.0f, 0.0f);  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 1.0f, 0.0f);  
                GL.Vertex3f(1, -1, 0);  
      
                /** 右上点 */  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 1.0f, 1.0f);  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 1.0f, 1.0f);  
                GL.Vertex3f(1, 1, 0);  
      
                GL.End();    /**< 绘制结束 */  
                GL.PopMatrix();  
      
      
                /** 激活纹理0,并绑定纹理 */  
                GL.ActiveTextureARB(GL.GL_TEXTURE0_ARB);  
                GL.Enable(GL.GL_TEXTURE_2D);  
                GL.BindTexture(GL.GL_TEXTURE_2D, m_texture[2].ID[0]);  
      
                /** 激活纹理1,并绑定纹理 */  
                GL.ActiveTextureARB(GL.GL_TEXTURE1_ARB);  
      
                /** 如果多重纹理启用,则启用该纹理 */  
                if (multitexturing)  
                    GL.Enable(GL.GL_TEXTURE_2D);  
                else  
                    GL.Disable(GL.GL_TEXTURE_2D);  
                GL.BindTexture(GL.GL_TEXTURE_2D, m_texture[3].ID[0]);  
      
                 
      
                GL.Translatef(2.5f, 0, 0);  
                GL.Scalef(2.0f, 2.0f, 2.0f);  
                GL.Begin(GL.GL_QUADS);  
      
                /** 左上点 */  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 0.0f, 1.0f);  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 0.0f - wrap, 1.0f);  
                GL.Vertex3f(-1, 1, 0);  
      
                /** 左下点 */  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 0.0f, 0.0f);  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 0.0f - wrap, 0.0f);  
                GL.Vertex3f(-1, -1, 0);  
      
                /** 右下点 */  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 1.0f, 0.0f);  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 1.0f - wrap, 0.0f);  
                GL.Vertex3f(1, -1, 0);  
      
                /** 右上点 */  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 1.0f, 1.0f);  
                GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 1.0f - wrap, 1.0f);  
                GL.Vertex3f(1, 1, 0);  
                GL.End();  
            }  
        }  
    }  

      移植只要改改几个地方就很方便了。

      这里我再次提醒大家,因为我们用到非托管库,freeglut.dll。需要把这个DLL拷贝到应用程序目录,由于系统分32位和64位,而默认VS生成项目模板是Any CPU,也就是32、64位自适应的EXE,而OpenGLDotNet和tao 自带freeglut.dll都是32位。

      需要自己设置为X86 32位EXE,或者自行下载freeglut 编译一个64位DLL,然后做两个版本EXE。

  • 相关阅读:
    Redis使用
    Linux下安装Tomcat
    Linux安装MySQL
    jquery的clone方法bug的修复select,textarea的值丢失
    sql 跨服务器查询数据
    无法执行该操作,因为链接服务器 "xxxxx" 的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务
    web服务器决定支持多少人同时在线的因素
    2016最新的中国省市区三级数据库表.sql mssql
    sqlserver2008R2数据库自动备份脚本
    sql server 2008 windows验证改混合登陆中SqlServer身份验证用户名密码
  • 原文地址:https://www.cnblogs.com/rainbow70626/p/5728875.html
Copyright © 2011-2022 走看看