none
請教一個VB使用word功能的程式問題 RRS feed

  • 問題

  • 各位好,想請教一個VB程式中使用Word的replace功能的問題。情況如下:

    使用word建立之後將一直被用到的報表樣版(存在伺服器端),並使用VB寫成的ActiveX元件將資料填入樣版文件,再產生一份新的word文件,將樣版文件中的資料複製並關閉,然後使用replace功能寫入新的word文件中,讓使用者列印報表。

    有時卻會碰到使用者發生無法將資料填入新word文件的狀況(未產生新的文件,只出現無法填入資料、處於唯讀狀態下的樣版文件),造成程式執行失敗;而且不同版本的word都會發生,甚至有的使用者本來能使用,但升級Office版本後卻發生不能用的情況,不過大部份的使用者都能正常使用。因此想請教版上的諸位先進,這種狀況該如何解決?

    目前懷疑是word裡的replace功能叫用失敗,不過,為何有的使用者的系統可以正常使用,有的卻否?又或許是系統裡相關的DLL檔出錯了?那麼,該如何找出具有相依性的檔案呢?謝謝。

    2006年6月8日 上午 07:23

解答

  • 「無法填入資料、處於唯讀狀態下的樣版文件」

    通常是兩個人同時使用存取這個 Word 樣板,造成樣版文件被鎖定。

    你可以先把樣版文件複製成新的檔案,再開啟新的檔案,這樣就不會有同時兩個人開啟樣版文件,也不需要另存新檔。

    不過基本上建議你用 WordML (XML 格式) ,這樣剛好接 Office 2007 的預設格式,不過只能在 Office XP/2003/2007 中用。可參考:

    http://tlcheng.no-ip.com/Paper/RunPC/132/Office.htm

    這個方法並不限制用在 Web 上,也可以用在 Windows Form 上。

    2006年6月8日 下午 12:45
  • 請描述你如何存取你的 word ,是透過中介程式還是只有透過網路芳鄰等。

    透過中介程式請確認 dcomcnfg 的設定及代理使用者的暫存空間。

    透過網路芳鄰請檢查出問題的使用者所使用的 OS 、帳號、密碼及做為檔案伺服器的權限設定。

    跨電腦使用 Office Automation 並不如單機使用單純,有很多問題在身份跟權限、暫存空間上。

    2006年6月9日 上午 10:26
  • ... 我起先還以為你是 Windows 應用程式,透過網芳處理勒...

    那你的 VB 用在哪?

    如果你的 VB 是指 VBScript 或是由 VB5/6 所開發出來的 ActiveX DLL ,請確認 dcomcnfg 正確設定 winword.exe 的代理使用者

    http://tlcheng.no-ip.com/TLCheng/Basic/vbs/dcom/automation.htm

    如果你的 VB5/6 是開發 ActiveX EXE ,請把上面的代理使用者設給你的 VB5/6 ,當然也可以設定給 winword.exe ,這是權限管理的範疇。

    在選擇代理使用者時,請確定該帳號有實體的暫存目錄,你可以透過 Windows 環境變數設定,將所有使用者全部指向單一目錄,或是以代理使用者帳號密碼登入,確認建立代理使用者帳號目錄,並用該使用者開啟樣版檔另存新檔,確認有足夠權限開啟、存取。

    若是網頁非使用匿名驗證,而使用 Windows 驗證,則一種方式是仍用上面的代理帳號處理,一種方式是確認所有的 Windows 驗證帳號都有 winword.exe 的存取權,通常 guests 群組是沒有寫入權,則若是碰上 windows 驗證無法識別的帳號時,可能會用 guests 登入,就會發生權限問題。

    當然,仍然用複製檔案來開啟,避免發生多人同時開啟被鎖定。

    其它情形請做更清楚的描述與舉例。

    2006年6月12日 上午 03:04
  • 這句錯了:

    Set wdRange = ActiveDocument.Content


    應該用

    Set wdRange = wdDoc.Content

    若能確定該文件為作用中文件,也可以用:

    Set wdRange = wdApp.ActiveDocument.Content

    原先的物件並不存在根目錄下的命名空間。

    2006年6月21日 上午 03:09
  • ...

    Private xxx

    是放在共用變數宣告區吧?

    程式碼不能放在宣告區,請搬移到適當位置執行。

     

    2006年6月23日 下午 12:45

所有回覆

  • 「無法填入資料、處於唯讀狀態下的樣版文件」

    通常是兩個人同時使用存取這個 Word 樣板,造成樣版文件被鎖定。

    你可以先把樣版文件複製成新的檔案,再開啟新的檔案,這樣就不會有同時兩個人開啟樣版文件,也不需要另存新檔。

    不過基本上建議你用 WordML (XML 格式) ,這樣剛好接 Office 2007 的預設格式,不過只能在 Office XP/2003/2007 中用。可參考:

    http://tlcheng.no-ip.com/Paper/RunPC/132/Office.htm

    這個方法並不限制用在 Web 上,也可以用在 Windows Form 上。

    2006年6月8日 下午 12:45
  • 感謝您的回覆。

    謝謝您的建議,不過,“只能在 Office XP/2003/2007 中用”,這就有點問題了耶,一定得讓使用舊版Office軟體的使用者可用才行,所以可能無法直接“晉級”了,哈

    “先把樣版文件複製成新的檔案,再開啟新的檔案,這樣就不會有同時兩個人開啟樣版文件,也不需要另存新檔”,這部份我會再確認的,謝謝。不過,比較想不通的是,每天都有許多人在用這個系統,但,都沒碰到問題,甚至,同一組使用者內,二位都能正常使用,而另一位卻怎樣都不行,所以或許不會是樣版使用權造成衝突所產生的吧。

    另外,有一個相關狀況是:在使用內部的測試系統進行測試時,也曾碰過無法寫入的情況,但在重灌office軟體後,就能正常運作了(當時有跳出訊息窗表示有幾個DLL檔版本不同,看是否保留或覆蓋,但卻忘了記下來>.<);所以,當使用者提出發生這個問題時,請他們重新安裝一次office軟體,就能排除這個情況了(當然也有無法排除的時候,不過多是因為還有其他造成失敗的原因需另外排除),所以,想請教您,或版上其他先進,是否知道有哪些相關的DLL檔會被用到,可能可以用來排除這個問題?謝謝。

    2006年6月9日 上午 08:32
  • 請描述你如何存取你的 word ,是透過中介程式還是只有透過網路芳鄰等。

    透過中介程式請確認 dcomcnfg 的設定及代理使用者的暫存空間。

    透過網路芳鄰請檢查出問題的使用者所使用的 OS 、帳號、密碼及做為檔案伺服器的權限設定。

    跨電腦使用 Office Automation 並不如單機使用單純,有很多問題在身份跟權限、暫存空間上。

    2006年6月9日 上午 10:26
  • 您好,感謝您持續回應及幫助,也很抱歉問題似乎描述得不夠詳盡,底下會描述整個運作的方式。謝謝。

    這是一個ASP網站服務,word樣版存放在伺服器上,使用者可以在輸入資料後將結果列印,而word樣版即是做為制式的列印表格,樣版上設有一些bookmark讓套表列印時能正確填入資料。有時,似乎是輸入的資料無法正確取代bookmark(如先前描述,會產生一個唯讀的、上面保有原始bookmark參數的樣版),導致執行錯誤。

     

    2006年6月12日 上午 02:20
  • ... 我起先還以為你是 Windows 應用程式,透過網芳處理勒...

    那你的 VB 用在哪?

    如果你的 VB 是指 VBScript 或是由 VB5/6 所開發出來的 ActiveX DLL ,請確認 dcomcnfg 正確設定 winword.exe 的代理使用者

    http://tlcheng.no-ip.com/TLCheng/Basic/vbs/dcom/automation.htm

    如果你的 VB5/6 是開發 ActiveX EXE ,請把上面的代理使用者設給你的 VB5/6 ,當然也可以設定給 winword.exe ,這是權限管理的範疇。

    在選擇代理使用者時,請確定該帳號有實體的暫存目錄,你可以透過 Windows 環境變數設定,將所有使用者全部指向單一目錄,或是以代理使用者帳號密碼登入,確認建立代理使用者帳號目錄,並用該使用者開啟樣版檔另存新檔,確認有足夠權限開啟、存取。

    若是網頁非使用匿名驗證,而使用 Windows 驗證,則一種方式是仍用上面的代理帳號處理,一種方式是確認所有的 Windows 驗證帳號都有 winword.exe 的存取權,通常 guests 群組是沒有寫入權,則若是碰上 windows 驗證無法識別的帳號時,可能會用 guests 登入,就會發生權限問題。

    當然,仍然用複製檔案來開啟,避免發生多人同時開啟被鎖定。

    其它情形請做更清楚的描述與舉例。

    2006年6月12日 上午 03:04
  • 感謝您的回覆。也很抱歉沒能即時回應您。

    參照您提供的連結,設定似乎並未弄錯,所以,看來不是這個問題吧。

    接著重新敘述一次問題,俾供您瞭解:

    這是一個ASP網站服務,word樣版預先建立好並存放在伺服器上(為了能與不同版本的word軟體相容,樣版文件是由word 97建立),使用者需安裝網站提供的ActiveX 元件(使用VB6撰寫)進行報表列印的功能;使用者執行資料輸入的功能是在網站上進行的,系統將使用者輸入的資料存入伺服端的資料庫,而報表列印功能則是一個非必要執行的選項,使用者只有在需要保留hard copy的備份時才會使用。這個報表列印功能是由前述的ActiveX元件將資料庫中的資料讀出並填入樣版文件,再產生一份新的word文件,將樣版文件中的資料複製並關閉樣版文件,然後寫入新的word文件中。

    現在遇到比較想不通的狀況就是:

    使用者在系統上線後都能正常使用,但之後卻會突然發生不能執行列印的問題,於是請使用者利用“較乾淨”的系統(有的使用者利用剛重灌的機器)安裝ActiveX元件再重新執行,大部份都能正常使用,卻仍有少數機器無法順利執行,這時再請使用者重新安裝office軟體(重新安裝使用者原本使用的版本,不需安裝特定版本),便能正常使用了。

    加上,先前在測試時亦碰上相同的狀況,也是在重新安裝office軟體後回復正常,而且當時有碰到安裝程式詢問是否覆蓋或保留某幾個DLL檔案的情形,所以才直覺認為或許是有某些被使用到的DLL檔,在一般的使用情況下被較新版本所覆蓋,而無法叫用,才造成這個狀況。

    因此,不知您或版上其他先進是否知道相關的解決方案?謝謝。

    2006年6月16日 上午 02:37
  • ? Client 端幹嘛要安裝 ActiveX ?

    情況 1. 全部在 Server 端執行:

    a. Server 端安裝 Office 版本不限、樣版版本對應 Office 版本後,在 Server 端將樣版文件複製到暫存目錄,暫存目錄需授權 IUSR_servername / 代理使用者 有寫入權。

    b. Server 端操控暫存檔輸入指定內容,另存為舊版格式(Word 2003 可能會有需要修復的問題)。

    c. 重新導向將暫存檔輸出。

    所以 Client 端不用安裝 ActiveX 。

    情況 2. Word 檔在 Client 端產生。

    a. Server 端無須安裝 Office 軟體,但是樣版文件需要舊版相容格式。

    b. 使用者端以 ActiveX 將樣版文件下載到暫存目錄,可用 wininet.dll 內的 InternetReadFile ,在 ActiveX 再將內容輸入到樣版文件。

    c. 以 ActiveX 開啟暫存檔,進行預覽列印。

    所以 Server 端不需要做 dcomcnfg 設定。

    你是用 ActiveX ,則應該屬於情況 2 才對,就跟上一篇我回的不一樣,上一篇說的是情況 1 ,如果是情況 2 ,應該是 client 端的問題,這要看你 ActiveX 是用延後連結還是提前連結,情況 2 ,在 ActiveX 就不應參照 Word Library x.0 ,要用延後連結的方式做 CreateObject ,宣告也不應包含 Dim xxx As Word.xxx 之類的。

    2006年6月16日 上午 03:21
  • 感謝您的回應。

    確實是使用您在情況二中所提到的方法,而且也是用 Dim xxx As Word.xxx 的方式,可能就因此而造成問題,感謝您的解惑。

    想再請教您,能否更仔細說明“用延後連結的方式做 CreateObject ”的方法如何使用?

    以及,是否有辦法以最少更動原始碼的方式,改為您建議的 CreateObject 方法?謝謝您。

    2006年6月21日 上午 02:40
  • 1. 把所有 Dim xxx As Word.xxx 改宣告成 Dim xxx As Object

    2. 把參照 Word x.0 Library 拿掉 ' 有這參照會認 Word 版本

    3.

    原先 Dim xxx As Word.Application 改用如下,變數名自行宣告為 Object:

    Set wdApp = CreateObject("Word.Application")

    ' 上面這句是必要,大部分情況來說,你原先程式碼改到這,應該就能跑了

    ' 以下若有需要可是情況引用

    Set wdDoc = wdApp.Documents.Open xxx

    Set wdRange = ActiveDocument.Content

    wdReplaceAll = 2

    With wdRange

       ...

       .Find.Execute strFind, strReplace, , , , , , , , , wdReplaceAll

    End With

    注意:

    1. 未參照 Word Library 時,所有的 Word 常數將不能使用,建議另行宣告一個常數用的 bas 檔。

    2. 原先 VB6 設計上並不支援指名引數,我不知道 SP6 後改過沒,建議依照原先參數定義來做,不要用指名引數,或是直接設屬性也可以。

    2006年6月21日 上午 03:04
  • 這句錯了:

    Set wdRange = ActiveDocument.Content


    應該用

    Set wdRange = wdDoc.Content

    若能確定該文件為作用中文件,也可以用:

    Set wdRange = wdApp.ActiveDocument.Content

    原先的物件並不存在根目錄下的命名空間。

    2006年6月21日 上午 03:09
  • 感謝您的回覆。

    我嚐試依照您的說明將部份程式修改如下:

    ' Private wd As Word.Application  (註解部份是指原始寫法,其下接依您說明而修改的寫法)
    Dim wd As Object
    Set wd = CreateObject("Word.application")  <==執行到這行的 Set 時就出現錯誤訊息
    ' Private srcDoc As Word.Document
    Dim srcDoc As Object
    ' Private desDoc As Word.Document
    Dim desDoc As Object
    ' Private mySel As Word.Selection
    Dim mySel As Object
    ' Private element As Word.Bookmark
    Dim element As Object

    但卻得到“Compile error: Invalid outside procedure”的錯誤訊息,不知您是否瞭解該如何解決?謝謝您。

    2006年6月23日 上午 06:05
  • ...

    Private xxx

    是放在共用變數宣告區吧?

    程式碼不能放在宣告區,請搬移到適當位置執行。

     

    2006年6月23日 下午 12:45