VS2010對Excel操作---DLL向


最近公司有個項目要用到Excel的操作,於是自己就對VC中關於Excel的操作進行整理了下。而這里我是直接做成DLL方便他人調用的。

  1. 創建一個MFC Dll項目。

  2. 選擇MFC擴展DLL。
  3. 在“類視圖”---“添加類”---在MFC中選擇“TypeLib中的MFC類”,按如圖所示選擇,並添加對應的類PS:由於我電腦上安裝的是office2010,所以對應的Excel版本號是14.0,各位可以根據自己的情況選擇。
  4. 刪除這六個類的頭文件中的第一句,如圖,並將頭文件添加到“stdafx.h"中
  5. 修改字符集,vs2010默認生成的是使用unicode字符集,這里我們把它修改為”使用多字節字符集“,這樣能避免很多不必要的麻煩。
  6. 接下來進行編譯,正常情況下會出現如下錯誤:這時候定位到警告處,在函數名之前加上下划線就OK了。如圖:這樣編譯就沒什么問題了。
  7. 接下就是直接添加導出函數來,這里我偷個懶直接到dllmain.cpp這個文件里面加了,大家可以根據自己的習慣來。

      1 extern "C" _declspec(dllexport) void ReadExcel(const CString& strPath,const CString& strFlag, const vector<CString>& vTarget,vector<CString>& vOutTarget)
      2 {
      3     CApplication _app;
      4     CWorkbook _book;
      5     CWorkbooks _books;
      6 
      7     CWorksheet _sheet;
      8     CWorksheets _sheets;
      9     CRange _rang;
     10 
     11     if (!_app.CreateDispatch(_T("Excel.Application")))
     12     {
     13         MessageBox(NULL,_T("Error!Creat Excel Application Server Faile!"),_T("Creat Excel Application Server"),MB_ICONERROR);
     14         exit(1);
     15     }
     16     _books = _app.get_Workbooks();
     17     _book = _books.Add(_variant_t(strPath));
     18 
     19     _sheets = _book.get_Worksheets();
     20     _sheet = _sheets.get_Item(_variant_t("電力電纜井"));
     21 
     22     //獲取行列數
     23     CRange _usedRang;
     24     _usedRang.AttachDispatch(_sheet.get_UsedRange(),TRUE);
     25     _rang.AttachDispatch(_usedRang.get_Columns(),TRUE);
     26     long nColumn = _rang.get_Count();//
     27     _rang.ReleaseDispatch();
     28     _rang.AttachDispatch(_usedRang.get_Rows(),TRUE);
     29     long nRow = _rang.get_Count();//
     30     _rang.ReleaseDispatch();
     31     _usedRang.ReleaseDispatch();
     32     //遍歷
     33     _rang.AttachDispatch(_sheet.get_Cells(),TRUE);//獲取所有單元格
     34     CString str;
     35     long nCurRow = 0;
     36     long nCurColumn = 0;
     37     //獲取關鍵字所在的行列號
     38     for (long i = 1; i <= nRow; ++i)
     39     {
     40         for (long j = 1; j <= nColumn; ++j)
     41         {
     42             CRange _currentRang;
     43             _currentRang.AttachDispatch(_rang.get_Item(COleVariant((long)i),COleVariant((long)j)).pdispVal,TRUE);
     44             COleVariant vResult = _currentRang.get_Value2();
     45 
     46             if (VT_BSTR == vResult.vt)//字符串
     47             {
     48                 str = vResult.bstrVal;
     49             }
     50             else if (VT_INT==vResult.vt)
     51             {
     52                 str.Format(_T("%d"),vResult.pintVal);
     53             }
     54             else if (VT_R8==vResult.vt)//8字節數字
     55             {
     56                 str.Format(_T("%f"),vResult.dblVal);
     57             }
     58             else if (VT_DATE==vResult.vt)//時間格式
     59             {
     60                 SYSTEMTIME st;
     61                 VariantTimeToSystemTime(vResult.date,&st);
     62             }
     63             else if (VT_EMPTY==vResult.vt)//空單元格
     64             {
     65                 str = "(NULL)";
     66             }
     67             _currentRang.ReleaseDispatch();
     68             if (strFlag==str)//直接使用goto語句跳出雙重循環
     69             {
     70                 nCurRow = i;
     71                 nCurColumn = j;
     72                 goto LOOPOUT;
     73             }
     74         }
     75     }
     76 
     77 LOOPOUT:
     78     vector<long> vNTarget;//目標列所在的列號
     79     for (long i = 1;i <= nColumn;++i)
     80     {
     81         CRange _currentRang;
     82         _currentRang.AttachDispatch(_rang.get_Item(COleVariant((long)1),COleVariant((long)i)).pdispVal,TRUE);
     83         COleVariant vResult = _currentRang.get_Value2();
     84 
     85         if (VT_BSTR == vResult.vt)//字符串
     86         {
     87             str = vResult.bstrVal;
     88         }
     89         else if (VT_INT==vResult.vt)
     90         {
     91             str.Format(_T("%d"),vResult.pintVal);
     92         }
     93         else if (VT_R8==vResult.vt)//8字節數字
     94         {
     95             str.Format(_T("%f"),vResult.dblVal);
     96         }
     97         else if (VT_DATE==vResult.vt)//時間格式
     98         {
     99             SYSTEMTIME st;
    100             VariantTimeToSystemTime(vResult.date,&st);
    101         }
    102         else if (VT_EMPTY==vResult.vt)//空單元格
    103         {
    104             str = "(NULL)";
    105         }
    106         _currentRang.ReleaseDispatch();
    107         //對取出來的str和目標str進行配對
    108         for (vector<CString>::size_type j = 0;j != vTarget.size(); ++j)
    109         {
    110             if (vTarget.at(j)==str)
    111             {
    112                 vNTarget.push_back(i);
    113                 break;
    114             }
    115         }
    116     }
    117     //接下來根據獲取的行號nCurRow和列號vNTarget來讀取指定內容
    118     for (vector<CString>::size_type i = 0; i != vTarget.size(); ++i)
    119     {
    120         CRange _currentRang;
    121         _currentRang.AttachDispatch(_rang.get_Item(COleVariant((long)nCurRow),COleVariant((long)vNTarget.at(i))).pdispVal,TRUE);
    122         COleVariant vResult = _currentRang.get_Value2();
    123 
    124         if (VT_BSTR == vResult.vt)//字符串
    125         {
    126             str = vResult.bstrVal;
    127         }
    128         else if (VT_INT==vResult.vt)
    129         {
    130             str.Format(_T("%d"),vResult.pintVal);
    131         }
    132         else if (VT_R8==vResult.vt)//8字節數字
    133         {
    134             str.Format(_T("%f"),vResult.dblVal);
    135         }
    136         else if (VT_DATE==vResult.vt)//時間格式
    137         {
    138             SYSTEMTIME st;
    139             VariantTimeToSystemTime(vResult.date,&st);
    140         }
    141         else if (VT_EMPTY==vResult.vt)//空單元格
    142         {
    143             str = "(NULL)";
    144         }
    145         _currentRang.ReleaseDispatch();
    146         vOutTarget.push_back(str);
    147     }
    148 
    149     _book.ReleaseDispatch();
    150     _books.ReleaseDispatch();
    151     _app.Quit();
    152 _app.ReleaseDispatch();
    153 }
    上述函數就是打開路徑strPath的Excel文件,並通過標志符strFlag找到要讀取的行,通過vTarget找到要讀取的列,將讀取的內容輸出到vOutTarget中。這里我是默認表格的第一行就是存放的表頭,大家可以根據自己的實際情況進行調整。

     

  8. 接下來再添加一個關於更新(即寫某個單元格的函數)
      1 extern "C" _declspec(dllexport) void UpdateExcel(const CString& strPath,const CString& strFlag,const vector<CString>& vTarget,const vector<CString>& vInTarget)
      2 {
      3     CApplication _app;
      4     CWorkbook _book;
      5     CWorkbooks _books;
      6 
      7     CWorksheet _sheet;
      8     CWorksheets _sheets;
      9     CRange _rang;
     10 
     11     if (!_app.CreateDispatch(_T("Excel.Application")))
     12     {
     13         MessageBox(NULL,_T("Error!Creat Excel Application Server Faile!"),_T("Creat Excel Application Server"),MB_ICONERROR);
     14         exit(1);
     15     }
     16     _books = _app.get_Workbooks();
     17     _book = _books.Add(_variant_t(strPath));
     18 
     19     _sheets = _book.get_Worksheets();
     20     _sheet = _sheets.get_Item(_variant_t("電力電纜井"));
     21 
     22     //獲取行列數
     23     CRange _usedRang;
     24     _usedRang.AttachDispatch(_sheet.get_UsedRange(),TRUE);
     25     _rang.AttachDispatch(_usedRang.get_Columns(),TRUE);
     26     long nColumn = _rang.get_Count();//
     27     _rang.ReleaseDispatch();
     28     _rang.AttachDispatch(_usedRang.get_Rows(),TRUE);
     29     long nRow = _rang.get_Count();//
     30     _rang.ReleaseDispatch();
     31     _usedRang.ReleaseDispatch();
     32     //遍歷
     33     _rang.AttachDispatch(_sheet.get_Cells(),TRUE);//獲取所有單元格
     34     CString str;
     35     long nCurRow = 0;
     36     long nCurColumn = 0;
     37     //獲取關鍵字所在的行列號
     38     for (long i = 1; i <= nRow; ++i)
     39     {
     40         for (long j = 1; j <= nColumn; ++j)
     41         {
     42             CRange _currentRang;
     43             _currentRang.AttachDispatch(_rang.get_Item(COleVariant((long)i),COleVariant((long)j)).pdispVal,TRUE);
     44             COleVariant vResult = _currentRang.get_Value2();
     45 
     46             if (VT_BSTR == vResult.vt)//字符串
     47             {
     48                 str = vResult.bstrVal;
     49             }
     50             else if (VT_INT==vResult.vt)
     51             {
     52                 str.Format(_T("%d"),vResult.pintVal);
     53             }
     54             else if (VT_R8==vResult.vt)//8字節數字
     55             {
     56                 str.Format(_T("%f"),vResult.dblVal);
     57             }
     58             else if (VT_DATE==vResult.vt)//時間格式
     59             {
     60                 SYSTEMTIME st;
     61                 VariantTimeToSystemTime(vResult.date,&st);
     62             }
     63             else if (VT_EMPTY==vResult.vt)//空單元格
     64             {
     65                 str = "(NULL)";
     66             }
     67             _currentRang.ReleaseDispatch();
     68             if (strFlag==str)//直接使用goto語句跳出雙重循環
     69             {
     70                 nCurRow = i;
     71                 nCurColumn = j;
     72                 goto LOOPOUT;
     73             }
     74         }
     75     }
     76 
     77 LOOPOUT:
     78     vector<long> vNTarget;//目標列所在的列號
     79     for (long i = 1;i <= nColumn;++i)
     80     {
     81         CRange _currentRang;
     82         _currentRang.AttachDispatch(_rang.get_Item(COleVariant((long)1),COleVariant((long)i)).pdispVal,TRUE);
     83         COleVariant vResult = _currentRang.get_Value2();
     84 
     85         if (VT_BSTR == vResult.vt)//字符串
     86         {
     87             str = vResult.bstrVal;
     88         }
     89         else if (VT_INT==vResult.vt)
     90         {
     91             str.Format(_T("%d"),vResult.pintVal);
     92         }
     93         else if (VT_R8==vResult.vt)//8字節數字
     94         {
     95             str.Format(_T("%f"),vResult.dblVal);
     96         }
     97         else if (VT_DATE==vResult.vt)//時間格式
     98         {
     99             SYSTEMTIME st;
    100             VariantTimeToSystemTime(vResult.date,&st);
    101         }
    102         else if (VT_EMPTY==vResult.vt)//空單元格
    103         {
    104             str = "(NULL)";
    105         }
    106         _currentRang.ReleaseDispatch();
    107         //對取出來的str和目標str進行配對
    108         for (vector<CString>::size_type j = 0;j != vTarget.size(); ++j)
    109         {
    110             if (vTarget.at(j)==str)
    111             {
    112                 vNTarget.push_back(i);
    113                 break;
    114             }
    115         }
    116     }
    117     //更新指定的單元格
    118     for (vector<CString>::size_type i = 0; i != vInTarget.size(); ++i)
    119     {
    120         _rang.put_Item(COleVariant(nCurRow),COleVariant(vNTarget.at(i)),COleVariant(vInTarget.at(i)));
    121     }
    
    1 _book.SaveCopyAs(COleVariant(strPath));
    2 _book.put_Saved(TRUE);
    3 _app.put_Visible(FALSE);
    4 _book.ReleaseDispatch();
    5 _books.ReleaseDispatch();
    6 
    7 _app.Quit()
    8 _app.ReleaseDispatch();

     

    126 }
    參數的設置和上一個函數差不多。

     

  9. 接下來編譯的時候,正常情況下會有一點小問題。這個問題如果你是基於對話框的MFC程序貌似是不會出現的,只有創建DLL或者ActiveX控件才會出現。這個問題也是煩惱了我好久,解決方法是先在文件頭導入一個lib在編譯,運氣好的話就沒什么問題了。運氣不好還會出下如下問題。這個時候我們修改下項目屬性把我標出來的選項改為否應該就沒什么問題了。
  10. 最后編譯完成通過。這樣dll和lib就都生成好了,大家可以盡情的使用了。
  11. 差不多就這樣了,至於其他的問題,比如如果直接創建的是基於對話框的MFc程序的話就更簡單了。跟着步驟走就完事了。最后我是一個菜鳥,如果有什么問題也歡迎大家指教。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM