张晓华的博客

        2005年,最后一场雪,还是下了,虽然凄凉了一些!
posts - 185, comments - 100, trackbacks - 8, articles - 1

Monday, June 23, 2008


使用IPicture::Render 绘制图片的方法说明:

  HRESULT Render(
                  HDC hdc, //Handle of device context on which to render the image  
                           //绘图设备
                  long x,  //Horizontal position of image in hdc
                           //绘图设备上的X起始坐标
                  long y,  //Vertical position of image in hdc
                           //绘图设备上的Y起始坐标
                  long cx, //Horizontal dimension of destination rectangle
                           //绘图设备上的水平像素单位数(宽)
                  long cy, //Vertical dimension of destination rectangle
                           //绘图设备上的垂直像素单位数(高)
                  OLE_XPOS_HIMETRIC xSrc,
                           //Horizontal offset in source picture
                           //原图的X起始坐标
                  OLE_YPOS_HIMETRIC ySrc,
                           //Vertical offset in source picture
                           //原图的Y起始坐标
                  OLE_XSIZE_HIMETRIC cxSrc,
                           //Amount to copy horizontally in source picture
                           //总计拷贝的水平像素单位数(宽)
                  OLE_YSIZE_HIMETRIC cySrc,
                           //Amount to copy vertically in source picture
                           //总计拷贝的垂直像素单位数(高)
                  LPCRECT prcWBounds
                           //Pointer to position of destination for a metafile hdc
                           //图源文件指针
                );
        范例:
          HRESULT  hr=m_lppi->Render(pDC->m_hDC,0,0,100,100,0,0,11774,20320,&rc);

使用CreateFile取得文件句柄的方法说明
    HANDLE WINAPI CreateFile(
                  LPCTSTR lpFileName,  
                             //The name of the object to be created or opened.
                             //打开或者新建的文件名
                  DWORD dwDesiredAccess,  
                             // The access to the object, which can be read, write, or both.
                             //  文件访问权限  常用的是 GENERIC_EXECUTE  / GENERIC_READ  /GENERIC_WRITE
                  DWORD dwShareMode,  
                             //  The sharing mode of an object, which can be read, write, both, or none
                             //   文件的共享模式,常用的是  FILE_SHARE_DELETE  / FILE_SHARE_READ  /FILE_SHARE_WRITE ,0表示不共享
                  LPSECURITY_ATTRIBUTES lpSecurityAttributes,  
                             //  A pointer to a SECURITY_ATTRIBUTES structure that determines whether or not the returned handle can be inherited by child processes.
                             //  详细内容,参见 msdn 的相关描述,我就不翻译了
                  DWORD dwCreationDisposition,  
                             //  An action to take on files that exist and do not exist.
                             //  详细内容,参见 msdn 的相关描述,我就不翻译了
                  DWORD dwFlagsAndAttributes,  
                             //  The file attributes and flags.
                             // 详细内容,参见 msdn 的相关描述,我就不翻译了
                  HANDLE hTemplateFile  
                             //  A handle to a template file with the GENERIC_READ access right. The template file supplies file attributes and extended attributes for the file that is being created. This parameter can be NULL.
                             //  详细内容,参见 msdn 的相关描述,我就不翻译了
                );
                
    范例:
          HANDLE hFile=CreateFile(_T("\\aaa.jpg"),GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
            

    
使用IPersistStream::Load获取LPPICTURE对象的方法:
    STDAPI OleLoadPicture(
                  IStream * pStream,
                               //Pointer to the stream that contains picture's data
                  LONG lSize,  //Number of bytes read from the stream
                  BOOL fRunmode,
                               //The opposite of the initial value of the picture's
                               // property
                  REFIID riid, //Reference to the identifier of the interface
                               // describing the type of interface pointer to return
                  VOID ppvObj  //Address of output variable that receives interface
                               // pointer requested in riid
                );

其他方法:

//按文件大小分配内存
                 LPVOID pvData;
                 HGLOBAL hGlobal=GlobalAlloc(GMEM_MOVEABLE,dwFileSize);
//锁定内存
                pvData=GlobalLock(hGlobal);            
//读取文件到内存    
                DWORD dwFileRead=0;
                BOOL bRead=ReadFile(hFile,pvData,dwFileSize,&dwFileRead,NULL);
//从已分配内存生成IStream流
                HRESULT hr=CreateStreamOnHGlobal(hGlobal,TRUE,&pstm);
                hr=OleLoadPicture(pstm,dwFileSize,FALSE,IID_IPicture,(LPVOID*)&(*lppi));
                pstm->Release();


一个相对完整的步骤

//加载图片
BOOL CPicTestDlg::LoadMyJpegFile(CString fname,LPPICTURE *lppi)
    {
        HANDLE hFile=CreateFile(fname,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
            if(hFile==INVALID_HANDLE_VALUE)
            {
                CString str;
                str.Format(_T("%s无法被打开"),fname);
                MessageBox(str);
                return FALSE;
            }
            
        //取得文件大小
        DWORD dwFileSize=GetFileSize(hFile,NULL);
            if((DWORD)-1==dwFileSize)
            {
                CloseHandle(hFile);
                MessageBox(_T("图像文件是空的"));
                return FALSE;
            }

        //读取图像文件
        
        LPVOID pvData;
        
        //按文件大小分配内存
        HGLOBAL hGlobal=GlobalAlloc(GMEM_MOVEABLE,dwFileSize);
            if(NULL==hGlobal)
            {
                CloseHandle(hFile);
                MessageBox(_T("内存不足,无法分配足够内存"));
                return FALSE;
            }

        pvData=GlobalLock(hGlobal);
            if(NULL==pvData)
            {
                GlobalUnlock(hGlobal);
                CloseHandle(hFile);
                MessageBox(_T("无法锁定内存"));
                return FALSE;
            }

        DWORD dwFileRead=0;
        
        BOOL bRead=ReadFile(hFile,pvData,dwFileSize,&dwFileRead,NULL);
        
        GlobalUnlock(hGlobal);
        
        CloseHandle(hFile);
        
            if(FALSE==bRead)
            {
                MessageBox(_T("读文件出错"));
                return FALSE;
            }
        LPSTREAM pstm=NULL;
        
        //从已分配内存生成IStream流
        
        HRESULT hr=CreateStreamOnHGlobal(hGlobal,TRUE,&pstm);
            if(!SUCCEEDED(hr))
            {
                MessageBox(_T("生成流操作失败"));
                if(pstm!=NULL)
                    pstm->Release();
                return FALSE;
            }else if(pstm==NULL){
                MessageBox(_T("生成流操作失败"));
                return FALSE;
            }
            
            if(!*lppi)
                (*lppi)->Release();
                
        hr=OleLoadPicture(pstm,dwFileSize,FALSE,IID_IPicture,(LPVOID*)&(*lppi));
        
        pstm->Release();
            if(!SUCCEEDED(hr))
            {
                MessageBox(_T("加载操作失败"));
                return FALSE;
            }else if(*lppi==NULL){
                MessageBox(_T("加载操作失败"));
                return FALSE;
            }
        return TRUE;
    }

//绘制图片



        TCHAR strPath[MAX_PATH];
        memset(strPath,0,MAX_PATH);
        //得到当前路径
        GetCurrentDirectory(MAX_PATH,strPath);
        //定义图片路径
        wcscat_s(strPath,MAX_PATH,_T("\\145.bmp"));
        //加载图片到 m_lppi
        m_bHadLoad=LoadMyJpegFile(strPath,&m_lppi);
        //取得绘图设备
        CDC *pDC=GetDC();
        //定义绘图矩形区域
        CRect rc;
        //得到图片长宽
        long hmWidth=0;
        long hmHeight=0;
        m_lppi->get_Height(&hmHeight);
        m_lppi->get_Width(&hmWidth);
        //定义区域与设备关联
        GetClientRect(&rc);
        int nWidth,nHeight;
        //得到设备的长宽
        nWidth=rc.Width();
        nHeight=rc.Height();
        //绘制图片到设备区域
        HRESULT  hr=m_lppi->Render(pDC->m_hDC,nWidth,0,-nWidth,nHeight,hmWidth,hmHeight,-hmWidth,-hmHeight,&rc);
        
使用以上内容可以在mfc的窗体中的任何地方绘制图片,重绘的时候,需要在方法OnPaint()中加以定义,另外可以在OnInitDialog()中提前加载图片到内存中.










 
 

 

posted @ 11:44 PM | Feedback (0)

I.内存分配问题
          1.变量未初始化。下面的程序在debug中运行的很好。
              thing * search(thing * something)
                BOOL found;
                for(int i = 0; i < whatever.GetSize(); i++)
                  {
                  if(whatever[i]->field == something->field)
                     { /* found it */
                      found = TRUE;
                      break;
                     } /* found it */
                   }
            if(found)
                     return whatever[i];
            else
                     return NULL;
          而在release中却不行,因为debug中会自动给变量初始化found=FALSE,而在release版中则不会。所以尽可能的给变量、类或结构初始化。
          2.数据溢出的问题
                如:char buffer[10];
                     int counter;
               lstrcpy(buffer, "abcdefghik");
          在debug版中buffer的NULL覆盖了counter的高位,但是除非counter>16M,什么问题也没有。但是在release版中,counter可能被放在寄存器中,这样NULL就覆盖了buffer下面的空间,可能就是函数的返回地址,这将导致ACCESS ERROR。
          3.DEBUG版和RELEASE版的内存分配方式是不同的。如果你在DEBUG版中申请   ele 为 6*sizeof(DWORD)=24bytes,实际上分配给你的是32bytes(debug版以32bytes为单位分配),而在release 版,分配给你的就是24bytes(release版以8bytes为单位),所以在debug版中如果你写ele[6],可能不会有什么问题,而在 release版中,就有ACCESS VIOLATE。
II.ASSERT和VERIFY
               ASSERT在Release版本中是不会被编译的。
          ASSERT宏是这样定义的
                #ifdef _DEBUG
                   #define ASSERT(x) if( (x) == 0) report_assert_failure()
                #else
                   #define ASSERT(x)
                #endif
                实际上复杂一些,但无关紧要。假如你在这些语句中加了程序中必须要有的代码
          比如
          ASSERT(pNewObj = new CMyClass);
          pNewObj->MyFunction();
          这种时候Release版本中的pNewObj不会分配到空间
          所以执行到下一个语句的时候程序会报该程序执行了非法操作的错误。这时可以用VERIFY :
                #ifdef _DEBUG
                   #define VERIFY(x) if( (x) == 0) report_assert_failure()
                #else
                   #define VERIFY(x) (x)
                #endif
          这样的话,代码在release版中就可以执行了。

III.参数问题:
          自定义消息的处理函数,必须定义如下:
          afx_msg LRESULT OnMyMessage(WPARAM, LPARAM);
          返回值必须是HRESULT型,否则Debug会过,而Release出错
IV.  内存分配
        保证数据创建和清除的统一性:如果一个DLL提供一个能够创建数据的函数,那么这个DLL同时应该提供一个函数销毁这些数据。数据的创建和清除应该在同一个层次上。
V.DLL的灾难
                人们将不同版本DLL混合造成的不一致性形象的称为 “动态连接库的地狱“(DLL Hell) ,甚至微软自己也这么说(http://msdn.microsoft.com/library/techart/dlldanger1.htm)。
         如果你的程序使用你自己的DLL时请注意:
          1.不能将debug和release版的DLL混合在一起使用。debug都是debug版,release版都是release版。
          解决办法是将debug和release的程序分别放在主程序的debug和release目录下
          2.千万不要以为静态连接库会解决问题,那只会使情况更糟糕。
VI.RELEASE板中的调试:
          1.将ASSERT() 改为 VERIFY() 。找出定义在"#ifdef _DEBUG"中的代码,如果在RELEASE版本中需要这些代码请将他们移到定义外。查找TRACE(...)中代码,因为这些代码在RELEASE中也不被编译。请认真检查那些在RELEASE中需要的代码是否并没有被便宜。
          2.变量的初始化所带来的不同,在不同的系统,或是在DEBUG/RELEASE版本间都存在这样的差异,所以请对变量进行初始化。
          3.是否在编译时已经有了警告?请将警告级别设置为3或4,然后保证在编译时没有警告出现.
VII.将Project Settings" 中 "C++/C " 项目下优化选项改为Disbale(Debug)。编译器的优化可能导致许多意想不到的错误.
          此外对RELEASE版本的软件也可以进行调试,请做如下改动:
          在"Project Settings" 中 "C++/C " 项目下设置 "category" 为 "General" 并且将"Debug Info"设置为 "Program Database"。
          在 "Link"项目下选中"Generate Debug Info"检查框。
          "Rebuild All"
          如此做法会产生的一些限制:
          无法获得在MFC DLL中的变量的值。
          必须对该软件所使用的所有DLL工程都进行改动。
          另:
          MS BUG:MS的一份技术文档中表明,在VC5中对于DLL的"Maximize Speed"优化选项并未被完全支持,因此这将会引起内存错误并导致程序崩溃。

posted @ 4:41 AM | Feedback (0)

调试MFC程序的时候,有时候会出现这个错误"没有找到MFC80D.DLL,重新安装.................", 使用网上搜索到的好几种方法,都无效,自己瞎改,遂,好了,操作如下:
修改项目-属性-配置属性--debug-General--output  directory  和  intermediate directory
   他们的缺省值为.\debug ,给他们改成了 $(SolutionDir)$(ConfigurationName)  和 $(ConfigurationName)
重新编译,问题解决.

可能网上其他解决办法是针对其它原因导致这个报错的方式,需要找专家答疑了,呵呵,简单列一下其他方法(在我这个问题上测试无效,可能对别的环境有效  :)  )

1  安装的是后没有把debug的一些unicode的库装进去,从安装盘里面拷贝一份.

2  需要更改默认项目的工程属性。工程属性->配置属性->清单工具->输入和输出->嵌入清单==>改为否

    方法2的另一描述:
         Visual Studio 2005用向导生成的项目,在运行时可能会遇到找不到MFC80UD.dll的问题。这个问题可能是Manifest 引起的,因此我们可以通过修改项目属性(properties)->清单工具(property pages)->链接(linker)-->manifest file -->Allow Isolation,把“嵌入清单”选“否”,.然后编译、链接、运行即可
  方法2的再一描述:

在头文件中加入如下声明即可
#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.VC80.CRT' version='8.0.50608.0' processorArchitecture='X86' publicKeyToken='1fc8b3b9a1e18e3b' language='*'\"")

3    查找下MFC80UD.DLL,   拷贝到你项目的生成目标文件夹下试试.  

4   工程属性->配置属性->常规->字符集"选"使用多字节字符集"

5   project   properties-manifest   tools-general   -   use   FAT32   work-around->true    然后clean-rebuild
     方法5,我压根没找到怎么改,我太笨了!

以上方法我均试用无效,估计别的环境有效吧,留此供大家参考!


posted @ 4:34 AM | Feedback (1)

1 编写 DLL
    a)   使用vs2005向导生成DLL项目
    b)   在 xxx.h文件中添加导出的方法
  extern   "C" void __stdcall/__fastcall/__cdecl   MethodName(void);   
  或者
  extern   "C"   void  fastcallproc(void);  
  区别在于后者
  c)    在xxx.cpp中添加实现方法
  extern CMyTestApp theApp;  //可以声明一个对象实例,在后面使用
  extern   "C" void cdeclx(int i)  
  {
      theApp.cdeclx(i);  // 使用前面的对象实例,调用类中的方法
  } 
  extern   "C"   void     _cdecl   cdeclproc(void)    // 和前面.h中的写法是完全一样的
  {
      ::MessageBox(0,_T("cdecl   function   "),_T("dll   call"),0); 
  } 
  extern   "C"   void     _fastcall   fastcallproc(void) 
  { ::MessageBox(0,_T("fastcall   function   "),_T("dll   call"),0); 
  }  
    extern   "C"   int   add (int i,int j)
  { 
      CString s=CString("%d",theApp.add(i,j));
      ::MessageBox(0,s,_T("dll   call"),0); 
      return theApp.add(i,j);
  }  
 
    d) 完成以上步骤后,进行编译,形成LIB,EXP,DLL等文件
   
2 隐式调用 DLL
   a)  使用vs2005向导添加MFC App程序
   b)  在程序代码 .h或者 .cpp前面添加 DLL的.h文件和LIB地址    
              #include "..\MyTest\MyTest.h"
              //链接输入库文件 
              #pragma   comment(lib,"..\\debug\\MyTest.lib")  
    c) 在程序代码中可以直接使用导出的方法
        void CDllCallerDlg::OnBnClickedButtona()
                {
                         ::cdeclx(1);
                }

2 显式调用 DLL  
    a)  使用vs2005向导添加MFC App程序
    b)  在程序代码中可以仿照下例使用导出的方法
        void CDllCallerDlg::OnBnClickedButtona()
                {
                     //声明DLL函数
                   typedef int (_cdecl *cdeclx)(int i);   
                    //声明函数句柄
                      HMODULE hTestDLL = NULL;
                       cdeclx cdeclX = NULL;
                      // 加载动态链接库
                      hTestDLL = LoadLibrary("TestDLL.dll");
                      if(hTestDLL == NULL){
                        MessageBox(NULL,_T("cannot load LCDDLL.dll"),_T("错误"),0);
                      return;
                      }
                       /*** 找到每个函数的入口 ****/
                    cdeclX = (cdeclx)GetProcAddress(hTestDLL,"cdeclx");
                  if(cdeclX==NULL)
                  {
                    MessageBox(NULL,_T("cannot load process cdeclX"),_T("错误"),0);
                  FreeLibrary(hTestDLL);
                  return;
                  }
                       //执行方法
                    int x=(*cdeclX)(100);
                       //结束
                }  
 

posted @ 1:45 AM | Feedback (0)