搜索
bottom↓
回复: 29

[上位机][笔记]Visual Studio 2008 C++ CLR 模式学习笔记10-15-09 Updated

[复制链接]

出0入296汤圆

发表于 2009-8-19 11:40:10 | 显示全部楼层 |阅读模式

说在前面的话
<font color=brown>
    不得不承认自己抱残守缺了,用了Visual Studio2008 才明白6.0的时代过去了。用了VB2008才知道,
VB还是一如既往的好用;用了VC2008(CLR模式)才知道VC++也可以和VB一样好用;用了C#才知道,原来
C#、VB、J++真的很类似;用了VC++ MFC才知道,从6.0到现在仍然让我望而却步……

    CLR模式,在很多人嘴里称为:自虐模式。有一个做软件的老前辈听说我从6.0转了Visual Studio2008
很欣慰的说你终于进步了,听说我用了VC++而不是VB,赞许说终于走上康庄大道了,听说我用了CLR而不是
MFC不由得直皱眉头说,要么用C#要么就用MFC,你用哪门子CLR啊……自虐啊……

    CLR的自虐之路……渐渐体会到了……但是这正是乐趣所在。毕竟CLR模式在界面设计和软件理念上是如
此的先进(我很看好CLR,对MFC不抱好感),所以决定一个一个攻克现在遇到的困难,特此记录下自己的脚
印,以资后(来)人……

    愿主保佑我,阿门……


<font color=blue>[一些建议]

    A、仔细弄懂delegate的使用方法
    B、有事没事看看System::Windows::Forms::Form里面都有哪些属性和方法,察看的方法很简单,选中
       以上文字,然后按F1——当然你必须在VS2008的工作环境下这么弄
    C、Windows编程的基本知识还是要有的……需要尽快补齐
    D、设计窗体时,学会使用Dock属性配合SplitContainer,会获得意想不到的效果
   
    to be continue...

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入296汤圆

 楼主| 发表于 2009-8-19 11:40:24 | 显示全部楼层

[问题A] CLR里面如何处理窗体消息的?

    CLR窗体里面,系统都有默认的消息处理函数,在当前的窗体类中,可以通过以下的方式找到该函数:
    System::Windows::Forms::Form::WndProc
    <font color=blue>如果你安装了MSDN,在VS2008中选中上面的文字,然后按F1,获得非常详细地说明。


    如果我们想处理窗体消息,怎么办呢?
    首先需要在窗体类里面增加从winUser.h里面找到的窗体消息,这个头文件需要安装SDK1.1后获得:
    private:
        static const Int32 WM_ACTIVATEAPP =     0x001C;
        static const Int32 WM_DEVICECHANGE =    0x0219;

    同时重载WndProc方法:
    [SecurityPermission(SecurityAction::Demand, Flags=SecurityPermissionFlag::UnmanagedCode )]
        virtual void WndProc( Message% m ) override
        {
            // Listen for operating system messages.
            switch ( m.Msg )
            {
                case WM_ACTIVATEAPP:
                    // The WParam value identifies what is occurring.
                    //appActive = (int)m.WParam != 0;
                    // Invalidate to get new text painted.
                    this->Invalidate();
                    break;
                case WM_DEVICECHANGE:
                    break;
            }
            Form::WndProc(m);
        }

    因为我们重载的时候牵涉到了安全设定,所以还需要增加一个安全相关的namespace:
    using namespace System::Security::Permissions;

    [注意] 不要尝试在CLR相关的头文件和cpp文件中增加#include<windows.h>。关于在CLR
          模式下编译MFC及其兼容代码的方法,将在后面的章节里面介绍。

出0入296汤圆

 楼主| 发表于 2009-8-19 11:51:58 | 显示全部楼层

[问题 B.1] 如何更改CLR窗体中控件的叠放次序(ZOrder)

    CLR的窗体中,控件没有ZOrder的概念,控件添加到窗体的顺序就决定了他们的显示次序,有意思的是,最后
添加控件最显示在后面(难道是FIFO?)。那么如何在程序中动态调整控件的前后顺序呢?
    答案很简单,修改控件的Index……
    举例说明……
    this->Controls->SetChildIndex(this->Label2,1);
    this->Controls->SetChildIndex(this->Label1,2);
    很简单吧……其中0表示最底层……


<font color=blue>[问题 B.2] 如何更改CLR窗体中MDI子窗体的先后顺序?


    其实CLR中,窗体也是一个控件……有一个函数叫做SendToBack();可以把控件或者窗体的ZOder设置为底层。需
要注意的是,如果这个控件或者窗体没有老爸老妈,就需要先调用BringToFront()来激活一下……然后再调用函数
SendToBack()。幸运的是对于MDI子窗体来说,肯定有老爸老妈……所以直接调用SendToBack()就可以liao……


[问题 B.3] 如何给CLR的MDI主窗体的工作区中增加背景控件?

    如果你只是想给MDI主窗体增加一个背景图片,直接在MDI主窗体的BackgroundImage中选择你要增加的图片,然后
通过BackgroundImageLayout选择图片的放置方法,我一般选择Center。

    但是如果你希望在MDI的应用程序工作区增加控件,可能就不是那么简单了,问题不是增加本身,而是这些控件都
会悬浮在MDI子窗体上……因此你有如下两个选择:
    1、直接在MDI应用程序工作区增加控件,当任何子窗体被激活时,通过MDI主窗体的MdiChildActivate()事件处
理函数来修改这些控件的可见性(Visible)。
    当子窗体最小化时,将这些控件设置为可见……这样并不算真正的窗体背景……因为当子窗体处于非最小化的
Normal状态时,背景控件时看不到的……

    2、建立一个MDI子窗体,将其BordStyle设置为None(0),并将其SendToBack(),现在唯一的问题就是,当其他子
窗体处于非激活状态时,他们会被隐藏到该背景子窗体的后面……这当然很好处理啦……比如单机或者双击这个背景子
窗体的时候,让他自动把自己SendToBack()就可以了……这种做法还有一种好处,就是多文档在被最小化的时候会被
隐藏……单击背景又能唤出所有最小化的子窗体……

    假设背景子窗体名叫m_frmBackGround是主窗体的一个成员变量,则可以在主窗体的构造函数里面增加如下的代码:
    m_frmBackGround.MdiParent = this;        //设置窗体为主MDI窗体的孩子
    m_frmBackGround.SendToBack();            //设置为背景……ZOrder = 0
    m_frmBackGround.Show();                  //显示出来

    那么如何让这个背景窗体随着主窗体应用区而自动伸缩呢?用Resize事件么?No,No!那太老土了……设计窗体时
看到Dock属性了么?选择Fill再看看?嘿嘿 Dock属性,配合窗体容器控件SpiltContainer设计应用程序界面,那可是怎
一个爽字了得!

出0入0汤圆

发表于 2009-8-19 12:02:06 | 显示全部楼层
我还在学mfc  
现在没办法  装个显卡驱动都要 .net

出0入296汤圆

 楼主| 发表于 2009-8-19 12:06:08 | 显示全部楼层

[问题C.1] 如何在CLR工程中使用MFC?

    嗯……这是个难题……我也是浪费了几个小时才找到一个不是很让人满意的答案的:
    1、必须明确,MFC环境和CLR水火不容;
    2、必须明白,不可在支持CLR的.cpp和.h中使用MFC;同样,在MFC系统中也不能使用CLR的相关
       内容;
    3、必须明白,只能在CLR环境中为MFC开辟一个专署区域(.cpp),然后通过标准C++编写的接口
       函数为MFC和CLR建立缓冲地带。简单的说:
       CLR <----> C++ __stdcall 函数 <----> MFC
    4、下面介绍如何在CLR中为MFC函数建立专属环境:

以下内容来自MSDN

<font color=blue>使用 /clr 编译 MFC 可执行文件或规则 DLL

打开“项目属性”对话框,方法是右键单击“解决方案资源管理器”中的项目并选择“属性”。

展开“配置属性”旁边的节点并选择“常规”。在右侧窗格中的“项目默认值”下,将“公共语言运行库支持”设置为“公共语言运行库支持 (/clr)”。

在相同的窗格中,确保将“MFC 的使用”设置为“在共享 DLL 中使用 MFC”。

在“配置属性”下,展开“C/C++”旁边的节点并选择“常规”。请确保将“调试信息格式”设置为“程序数据库 /Zi”(而不是“/ZI”)。

在“配置属性”下,选择“C/C++”,然后选择“代码生成”。请确保将“运行时库”设置为“多线程调试 DLL (/MDd)”或“多线程 DLL (/MD)”之一。

使用 /clr 编译 MFC 扩展 DLL
按照本节中上面的“使用 /clr 编译 MFC 可执行文件或规则 DLL”中的步骤进行操作。

执行下列操作之一:

在“配置属性”下,展开“C/C++”旁边的节点并选择“预编译头”。将“创建/使用预编译头”设置为“不使用预编译头”。

在“解决方案资源管理器”中,右键单击文件 stdafx.cpp 并选择“属性”。在“配置属性”下,展开“C/C++”旁边的节点并选择“常规”。将“具有公共语言运行库支持的编译”设置为“无公共语言运行库支持”。

对于包含 DllMain 和其调用的任何内容的文件,打开该文件的“属性页”,方法是右键单击“解决方案资源管理器”中的文件并选择“属性”。在“配置属性”下,展开“C/C++”旁边的节点并选择“常规”。在右侧窗格中的“项目默认值”下,将“具有公共语言运行库支持的编译”设置为“无公共语言运行库支持”。


    5、通过这种方法处理的cpp中,别忘了增加MFC的相关头文件:

#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN                // Exclude rarely-used stuff from Windows headers
#endif

// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER                                // Allow use of features specific to Windows XP or later.
#define WINVER 0x0501                // Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef _WIN32_WINNT                // Allow use of features specific to Windows XP or later.                  
#define _WIN32_WINNT 0x0501        // Change this to the appropriate value to target other versions of Windows.
#endif                                               

#ifndef _WIN32_WINDOWS                // Allow use of features specific to Windows 98 or later.
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
#endif

#ifndef _WIN32_IE                        // Allow use of features specific to IE 6.0 or later.
#define _WIN32_IE 0x0600        // Change this to the appropriate value to target other versions of IE.
#endif

#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS        // some CString constructors will be explicit

// turns off MFC's hiding of some common and often safely ignored warning messages
#define _AFX_ALL_WARNINGS

#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions
#include <afxdb.h>
#include <afxdisp.h>        // MFC Automation classes



[问题C.2] IntPtr类型的Handle和HWND类型的hWnd如何转换?
<font color=brown>
    在MSDN上,赫然写着控件/窗体的Handle属性包含的内容就是hWnd,那么可以直接使用么?答案是否定的……
    如果你要把CLR窗体的Handle传递一个MFC函数,那么至少先要这么转换:

    增加一个中间函数,该函数以void *为传入参数类型。例如
    void __stdcall ExampleCLRtoMFC(void *hWnd)

    对于IntPtr类型的Handle,在调用ExampleCLRtoMFC前,要使用ToPointer()方法:
    ExampleCLRtoMFC(this->Handle.ToPointer());

    在ExampleCLRtoMFC内部,调用MFC函数前,必须进行强制类型转换:
    例如,某MFC函数类型如下 void __stdcall MFC_Example(HWND hWnd);
    void __stdcall ExampleCLRtoMFC(void *hWnd)
    {
        ...
        MFC_Example(*(HWND *)&hWnd);         //华丽的指针强制类型转换
        ...
    }   

    打完收工……
    另外,虽然MSDN告诉我们HWND的本质就是void *,但是你直接使用还是会报错,搞不懂了……
    附上内部定义如下:
    typedef void *                        PVOID;
    typedef PVOID                        HANDLE;
    typedef HANDLE                        HWND;

出0入296汤圆

 楼主| 发表于 2009-8-19 13:41:59 | 显示全部楼层

[问题D.1] 如何在自定义的CLR窗体控件中增加属性(Property)

    简单易用的自定义控件是CLR的亮点之一,对C++来说,增加Property还是比较简单的,直接在控件的类声明中增加:

public:
    //定义一个bool类型的控件属性
    property bool ExamplePropery
    {
        bool get()
        {
            //该属性的读取方法
            return true;
        }
        void set(bool val)
        {
            //该属性的设置方法
        }
    }

    其它依此类推了哦……


<font color=blue>[问题D.2] 如何在自定义的CLR窗体控件中增加自定义事件(Event)


    首先,需要借助Delegate关键字声明一个委托类型(所谓的委托类型很类似于一个函数指针的数组,通过这个类型定义的
变量称为委托变量类型,代表了一系列的同类型函数,通过这个委托变量类型,可以按照函数添加的顺序——通过"+"来添加——来依次
调用该数组里面的所有函数,是不是很BT啊……),例如

    public delegate void ExampleHandler(unsigned short hwValue); //定义了一个delegate委托变量类型,该变量代表了一系列
                                                                 // void (*)(unsigned short hwValue)类型的函数指针

    接下来,在控件的类声明中增加对事件的声明:
    event ExampleHandler^ ExampleEvent;

    最后,如果你系统该控件向外界发送这个自定义的事件,则只需要直呼其名就可以了,例如:
    ExampleEvent(0x1234);
    或者
    ExampleEvent.Invoke(0x1234);

    至于外界如何处理这个自定义的事件呢?自己看看控件的事件窗口,是不是在杂项里面多了一个事件类型ExampleEvent啊?
双击看看?呵呵。



[问题D.3] 如何在自定义的CLR窗体控件中对外界发起系统事件,例如Click、MouseMove……

    必须要明确一点,如果一个用户控件里面有其他系统控件,虽然这些控件的事件能在用户控件被使用时,可以在设计窗口的事件栏中看到,
但是这些事件有时候并不会直接被触发。你可以手工为用户控件添加这些事件……

    首先,你要搞清楚你要发起的事件,究竟是什么类型……例如Click事件,就是一个系统默认的事件类型EventHandler(也就是
说系统使用了EventHandler委托变量类型来处理Click事件),因此,我们需要增加如下的一个声明:
    event EventHandler^ Click;

    然后你就可以在某个合适的位置来RaiseEvent了,方法仍然是直接调用……或者Invoke……

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e)
                 {
                     //如果控件里面的button1被按下,就触发click事件。                 
                     Click(sender,e);
                 }

    对于像MouseMove这样的事件,需要传递一些参数,这些参数往往是需要初始化的,老老实实初始化咯……不明白得看MSDN

    当然,还有一个更简单的方法,直接调用控件的Onxxx方法,例如
    this->OnClick(e);  

     这种方法的好处是,什么额外的东西都不需要,而之前介绍的方式相当于Override……

出0入0汤圆

发表于 2009-8-19 15:05:31 | 显示全部楼层
搬小板凳。。

出0入0汤圆

发表于 2009-8-19 16:33:49 | 显示全部楼层
垫长报纸,坐着看

出0入0汤圆

发表于 2009-8-19 16:55:15 | 显示全部楼层
围观~

出0入0汤圆

发表于 2009-8-19 18:59:56 | 显示全部楼层
站在楼顶看

出0入0汤圆

发表于 2009-8-19 20:53:38 | 显示全部楼层
还是c#好呀!!

出0入0汤圆

发表于 2009-8-19 21:29:21 | 显示全部楼层
建议,还是c#吧...多得不想说
不然你继续vb.net也好...
============
c#中一样可以override来覆盖系统消息处理...
你现在这样太麻烦了...

出0入296汤圆

 楼主| 发表于 2009-8-19 21:35:51 | 显示全部楼层
谢谢楼上建议,不过身不由己……

出0入0汤圆

发表于 2009-8-19 21:39:19 | 显示全部楼层
身不由己…… 最悲剧的事莫过于此-_-

出0入0汤圆

发表于 2009-8-19 21:43:07 | 显示全部楼层
傻孩子的帖子总是很有技术含量滴...

看来我也该远离VC,跨上.net平台了

出0入0汤圆

发表于 2009-8-19 21:51:30 | 显示全部楼层
好东西
Mark

出0入296汤圆

 楼主| 发表于 2009-9-14 23:32:59 | 显示全部楼层

问题E 如何制作中文的Framework3.5离线安装包

<font color=blue>以下内容摘抄自网络,原始网址:http://hi.baidu.com/sd_chunhui/blog/item/12f724d3b30453093af3cfe4.html


1.  离线安装包的bug. .NET Framework 3.5 SP1发布了,兴冲冲…下载,当然是完全离线安装包
    .net Framework 3.5 Service pack 1(Full Package) 231MB,网络慢呀!终于下载完了,安
    装….遇到新情况,还要连接网络下载,不是完全离线安装包吗?(急…等待中…大概需要30多
    分钟) 上火…啪啪的… 说明:呵呵,查了资料后才知道是微软制作安装程序时的一个无奈bug.
    在这里微软没有提醒大家,确实忽悠了我们。原来,.NET Framework 3.5 SP1(Full Package)
    是默认英文的安装包,如果要同时包含所有语言,那体积会太大了,可能考虑到这一点,发布
    时并没有包含其它的语言包,而是通过安装时在线下载,因而Full Package的称呼有点言不符实。

2.  自己动手,制作离线安装包. 自己能办到的,一般不求别人…
    第一 下载.net Framework 3.5 Service pack 1 (Full Package) 231MB 安装包后
    dotnetfx35.exe,用WinRAR将其解压缩。
    http://www.microsoft.com/downloads/details.aspx?familyid=D0E5DEA7-AC26-4AD7-B68C-FE5076BBA986&displaylang=zh-cn
    第二 下载中文简体语言包。
    http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn&FamilyID=8489ed13-b831-4855-96f7-dd35e4c02a20
    文件名                            文件大小
    dotnetfx35langpack_ia64zh-CHS.exe 16.9 MB
    dotnetfx35langpack_x64zh-CHS.exe  33.3 MB
    dotnetfx35langpack_x86zh-CHS.exe  27.4 MB
    一般用户下载dotnetfx35langpack_x86zh-CHS.exe 即可
    说明:也可从vs2008 sp1 提取,里面dotnetfx35langpack_x64zh-CHS.exe和
    dotnetfx35langpack_x86zh-CHS.exe都有,前提是你已经下载了VS2008 sp1。

3.  将语言包dotnetfx35langpack_x86zh-CHS.exe复制到第一步解压缩的
     \wcu\dotNetFramework\dotNetFX35\x86文件夹里。 (如果是x64位的,可将
    dotnetfx35langpack_x64zh-CHS.exe 复制到\wcu\dotNetFramework\dotNetFX35\x64文件夹里。)
    第四 点击运行dotNetFx35setup.exe,可彻底的离线安装了。安装之后需要重启计算机。

出0入296汤圆

 楼主| 发表于 2009-10-14 11:29:08 | 显示全部楼层

问题F 为什么修改了窗体类的名称以后,总是提示资源错误?

使用Visual Studio 2008 的C++ 建立CLR窗体工程时,系统会使用默认的模板,此时,
窗体的名称是Form1,窗体文件为Form1.h。是不是很不爽?于是开始依次修改:
1、首先通过属性窗口修改类名称——注意,尽可能不要手动修改代码,而使用属性窗口
   来修改,方法是打开窗体的代码视图,选中窗体类。此时,属性窗口中出现了该类的
   各种属性,直接修改名称即可。
2、接下来,我们要修改文件名称,总之form1.h看起来很不爽。仍然不要手动修改文件
   名称,选中窗体文件Form1.h,然后在属性窗口中修改名称。
3、编译,肯定会出现错误,不过都是一些#include文件名称的小错误,很容易解决。
4、再次编译,通过,但是运行时刻,总能看到如下的错误提示:
   
   观察控制台,提示资源加载错误,找不到所需的资源文件:
   <font color=blue>Additional information: Could not find any resources appropriate for the specified culture or the neutral culture.  Make sure "DeviceSpaceTest.frmDeviceSpaceTest.resources" was correctly embedded or linked into assembly "DeviceSpaceTest" at compile time, or that all the satellite assemblies required are loadable and fully signed.

   这是为什么呢?
   大惑不解:于是仔细查看代码,发现在窗体类的定义之前,有一段小注释:
         /// <summary>
        /// Summary for frmDeviceSpaceTest
        ///
        /// WARNING: If you change the name of this class, you will need to change the
        ///          'Resource File Name' property for the managed resource compiler tool
        ///          associated with all .resx files this class depends on.  Otherwise,
        ///          the designers will not be able to interact properly with localized
        ///          resources associated with this form.
        /// </summary>

   看来和资源文件有关系,于是按照上面的提示,尝试解决问题:
   1、选中工程->属性(Propertis)->配置属性(Configuration Properties)
              ->托管资源(Managed Resource)->资源文件名称(Resource File Name)
   2、强制将$(InputName)修改为窗体文件名称(假如你的窗体文件名成为frmDeviceSpaceTest),则
      一个典型的修改结果为:
      $(IntDir)\$(RootNamespace).frmDeviceSpaceTest.resources
      单机应用。
   3、清除工程(Clean)、重新编译(Rebuild),然后运行,故障解除。
   4、重新通过步骤2,将刚才修改的名字改回$(InputName),因为二者是等价的。上面的强制修改迫使
      VS2008重新进行了某些更新——鬼知道,也许是一个BUG。

   问题解决,大功告成……(累 - -b)

出0入296汤圆

 楼主| 发表于 2009-10-15 15:55:18 | 显示全部楼层

备忘01 关于垃圾收集和析沟函数
<font color=brown>
1、CLR模式下(C++ CLR、C#和VB),没有任何方式立即释放gcnew(C#里面的new)分配的对象;
   所有的垃圾收集工作由垃圾收集器完成。
2、value类型不能具有析构函数,因为value类型是在stack中分配的,不牵涉到垃圾收集器;
   ref类型的析构函数由垃圾收集器在垃圾收集的时候调用。
3、在可能的情况下,尽可能不要编写析构函数,这会降低系统效率。
4、不要在析构函数里面访问其他ref对象,因为这个ref对象很有可能已经被垃圾收集器释放
   了。因为垃圾收集器并不保证ref对象的释放顺序。

出0入0汤圆

发表于 2010-12-18 17:39:18 | 显示全部楼层
学习

出0入0汤圆

发表于 2010-12-18 19:37:39 | 显示全部楼层
学习

出0入0汤圆

发表于 2010-12-18 20:26:45 | 显示全部楼层
楼主啊,你的工作性质只开发在Windows上跑的软件吗??????
我个人觉得喜欢这个论坛的人肯定不是那些整天开发桌面软件的人,肯定是工作中主要是使用单片机啊、ARM啊、DSP啊、FPGA啊还有电子电路啊之类的人,他们开发GUI界面软件主要是一个辅助性的工作,而且这些软件并不一定是在PC上运行的。所以,对于我们来说学习C#、CLR之类的东东是不是不合适啊,可能QT啊JAVA之类的更合适吧——虽然这个也是虚拟机,但他的运行范围运用大于微软的CLR吧。

呵呵,新人的管窥之见,切勿介意!!!
我也是很困惑该选那一个,只是在这里和楼主探讨探讨,

出0入0汤圆

发表于 2010-12-18 22:52:45 | 显示全部楼层
mark~

出0入0汤圆

发表于 2010-12-18 23:44:40 | 显示全部楼层
先占个座

出0入0汤圆

发表于 2011-4-1 20:22:13 | 显示全部楼层
mark!!!

出0入0汤圆

发表于 2011-11-28 23:43:28 | 显示全部楼层
占座刘明

出0入0汤圆

发表于 2011-11-29 00:20:26 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-8-4 11:48:08 | 显示全部楼层
mark      

出0入0汤圆

发表于 2014-2-13 18:49:18 | 显示全部楼层
mark                             

出0入10汤圆

发表于 2016-11-25 10:16:46 | 显示全部楼层
好帖子,很有用
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 01:45

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表