อาการ
เมื่อคุณพยายามใช้ GetObject (Microsoft visual Basic) หรือ GetActiveObject (microsoft visual c ++) เพื่อทำให้แอปพลิเคชัน microsoft office เป็นแบบอัตโนมัติคุณจะได้รับข้อความแสดงข้อผิดพลาดอย่างใดอย่างหนึ่งต่อไปนี้แม้ว่าแอปพลิเคชัน Office กำลังทำงานอยู่ให้ทำดังนี้
ข้อความแสดงข้อผิดพลาด 1:
ข้อผิดพลาดขณะเรียกใช้ ' ๔๒๙ ': คอมโพเนนต์ ActiveX ไม่สามารถสร้างวัตถุได้
ข้อความแสดงข้อผิดพลาด 2
ข้อผิดพลาด: 0x800401e3 "การดำเนินการไม่พร้อมใช้งาน"
สาเหตุ
แม้ว่าแอปพลิเคชัน Office กำลังทำงานอยู่อาจไม่มีการลงทะเบียนในตารางวัตถุที่ใช้งานอยู่ (เน่า) อินสแตนซ์ที่กำลังทำงานของแอปพลิเคชัน Office ต้องได้รับการลงทะเบียนในเน่าก่อนที่จะสามารถแนบกับการใช้ GetObject (visual Basic) หรือ GetActiveObject (visual c ++) เมื่อแอปพลิเคชัน Office เริ่มทำงานจะไม่สามารถลงทะเบียนวัตถุที่กำลังทำงานได้ทันที การดำเนินการนี้จะปรับปรุงกระบวนการเริ่มต้นของแอปพลิเคชัน แทนที่จะลงทะเบียนเมื่อเริ่มต้นแอปพลิเคชัน Office จะลงทะเบียนวัตถุที่กำลังทำงานอยู่ในเน่าเมื่อสูญเสียโฟกัส ถ้าคุณพยายามใช้ GetObject หรือ GetActiveObject เพื่อแนบไปกับอินสแตนซ์ที่กำลังทำงานของแอปพลิเคชัน Office ก่อนที่แอปพลิเคชันจะสูญเสียโฟกัสคุณอาจได้รับข้อผิดพลาดอย่างใดอย่างหนึ่งต่อไปนี้
การแก้ไข
การใช้โค้ดคุณสามารถเปลี่ยนโฟกัสจากแอปพลิเคชัน Office ไปยังแอปพลิเคชันของคุณเอง (หรือไปยังแอปพลิเคชันอื่นๆ) เพื่อให้สามารถลงทะเบียนตัวเองในเน่าได้ นอกจากนี้ถ้าโค้ดของคุณเปิดใช้งานไฟล์ exe ของแอปพลิเคชัน Office คุณอาจจำเป็นต้องรอให้แอปพลิเคชัน Office เสร็จสิ้นการโหลดก่อนที่จะพยายามแนบไปกับอินสแตนซ์ที่กำลังทำงานอยู่ ตัวอย่างโค้ดจะมีให้เป็นวิธีแก้ไขปัญหาชั่วคราวในส่วน "ข้อมูลเพิ่มเติม"
สถานะ
ลักษณะการทำงานนี้จะเป็นตามการออกแบบ
ข้อมูลเพิ่มเติม
ในสถานการณ์ส่วนใหญ่นักพัฒนาที่ต้องการทำให้แอปพลิเคชัน Office จำเป็นต้องใช้ CreateObject (visual Basic) หรือ CoCreateInstance (visual c ++) เพื่อเปิดใช้งานอินสแตนซ์ใหม่ของแอปพลิเคชัน Office อย่างไรก็ตามมีบางกรณีที่คุณอาจต้องการทำให้แอปพลิเคชัน Office ที่กำลังใช้งานอยู่: ตัวอย่างเช่นถ้าผู้ใช้เริ่มต้นแอปพลิเคชัน Office ไว้ก่อนหน้านี้ หรือถ้าคุณเปิดใช้งานแอปพลิเคชัน Office ของแอปพลิเคชันโดยใช้โค้ดเพื่อให้คุณสามารถระบุสวิตช์บรรทัดคำสั่งสำหรับแอปพลิเคชันได้ เมื่อต้องการทำให้แอปพลิเคชัน Office ของคุณทำงานโดยอัตโนมัติคุณต้องใช้GetObjectหรือGetActiveObject
ขั้นตอนในการทบทวนเกิดลักษณะการทำงาน
-
เริ่ม Microsoft Visual Basic และสร้างโครงการ EXE มาตรฐานใหม่ Form1 จะถูกสร้างขึ้นตามค่าเริ่มต้น
-
เพิ่มตัวควบคุม CommandButton ไปยัง Form1
-
เพิ่มโค้ดต่อไปนี้ลงในโมดูโค้ดของฟอร์ม
Private Sub Command1_Click() Dim oExcel As Object ' Launch a new instance of Microsoft Excel: Shell "C:\Program Files\Microsoft Office\Office\Excel.EXE", _ vbMinimizedNoFocus ' An error 429 occurs on the following line: Set oExcel = GetObject(, "Excel.Application") MsgBox oExcel.Name Set oExcel = NothingEnd Sub
-
ตรวจสอบให้แน่ใจว่าตำแหน่งที่ตั้งของ outlook.exe ถูกต้องในตัวอย่างโค้ด
-
ออกจาก Microsoft Excel ถ้ามีการใช้งานอยู่แล้ว
-
กด F5 เพื่อเรียกใช้โครงการแล้วคลิกCommand1
วิธีแก้ไขปัญหาชั่วคราว
เมื่อต้องการแก้ไขปัญหานี้คุณสามารถทำได้ดังนี้
-
ให้โฟกัสไปยังแอปพลิเคชัน Office โดยการเปลี่ยนอาร์กิวเมนต์ที่สองของฟังก์ชัน Shell เป็นvbMinimizedFocus, vbMaximizedFocusหรือvbNormalFocus
-
ทำให้ฟอร์ม Visual Basic ของคุณโฟกัส
-
พยายาม GetObject ขณะที่บัญชีสำหรับเวลาการโหลดของแอปพลิเคชัน Office
โค้ดที่ได้จากการแก้ไขต่อไปนี้แสดงวิธีแก้ไขปัญหานี้
Private Declare Sub Sleep Lib "kernel32" _ (ByVal dwMilliseconds As Long)Private Sub Command1_Click() Dim intSection As Integer Dim intTries As Integer Dim oExcel As Object ' Enable error handler for this procedure: On Error GoTo ErrorHandler ' Launch Microsoft Excel, giving it focus: Shell "C:\Program Files\Microsoft Office\Office\Excel.EXE", _ vbMinimizedFocus 'other options for starting with 'focus: vbMaximizedFocus and vbNormalFocus ' Move focus back to this form. (This ensures the Office ' application registers itself in the ROT, allowing ' GetObject to find it.) Me.SetFocus ' Attempt to use GetObject to reference the running ' Office application: intSection = 1 'attempting GetObject... Set oExcel = GetObject(, "Excel.Application") intSection = 0 'resume normal error handling ' Now you can automate Microsoft Excel: MsgBox oExcel.Name & ": able to GetObject after " & _ intTries + 1 & " tries.", vbMsgBoxSetForeground ' Finished with automation so release your reference: Set oExcel = Nothing ' Exit procedure: Exit Sub ErrorHandler: If intSection = 1 Then 'GetObject may have failed because the 'Shell function is asynchronous; enough time has not elapsed 'for GetObject to find the running Office application. Wait 'wait 1/2 seconds and retry the GetObject. If you try 20 times 'and GetObject still fails, assume some other reason 'for GetObject failing and exit the procedure. intTries = intTries + 1 If intTries < 20 Then Sleep 500 ' wait 1/2 seconds Resume 'resume code at the GetObject line Else MsgBox "GetObject still failing. Process ended.", _ vbMsgBoxSetForeground End If Else 'intSection = 0 so use normal error handling: MsgBox Error$ End IfEnd Sub
วิธีแก้ไขปัญหาชั่วคราวสำหรับ c ++
ถ้าคุณกำลังเขียนโปรแกรมใน c ++ ตัวอย่างโค้ดต่อไปนี้จะอธิบายวิธีแก้ไขปัญหาที่คล้ายคลึงกันกับที่แสดงในตัวอย่างด้านบนของ Visual Basic โปรดสังเกตว่า SetForegroundWindow จะถูกใช้เพื่อย้ายโฟกัสออกจาก Excel ซึ่งจะช่วยให้คุณสามารถลงทะเบียนวัตถุที่กำลังทำงานอยู่ได้
//Store the handle of the currently active window...HWND hwndCurrent = ::GetForegroundWindow();//Launch Excel and wait until it is waiting for//user input...STARTUPINFO Start;PROCESS_INFORMATION ProcInfo;ZeroMemory(&Start,sizeof(STARTUPINFO));Start.cb=sizeof(Start);Start.dwFlags = STARTF_USESHOWWINDOW;Start.wShowWindow = SW_SHOWMINIMIZED;//Change the path to Excel as needed...LPSTR pszExcelPath = "c:\\program files\\microsoft office\\office\\excel.exe";::CreateProcess(NULL, pszExcelPath, 0, 0, 1, NORMAL_PRIORITY_CLASS, 0, NULL, &Start, &ProcInfo);if((::WaitForInputIdle(ProcInfo.hProcess, 10000))==WAIT_TIMEOUT){ ::MessageBox(NULL, "Timed out waiting for Excel.", NULL, MB_OK);}//Restore the active window to the foreground...// NOTE: If you comment out this line, the code will fail!::SetForegroundWindow(hwndCurrent);//Initialize COM library...::CoInitialize(NULL);//Attach to the running instance...CLSID clsid;CLSIDFromProgID(L"Excel.Application", &clsid); IUnknown *pUnk = NULL;IDispatch *pDisp = NULL;for(int i=1;i<=5;i++) //try attaching for up to 5 attempts{ HRESULT hr = GetActiveObject(clsid, NULL, (IUnknown**)&pUnk); if(SUCCEEDED(hr)) { hr = pUnk->QueryInterface(IID_IDispatch, (void **)&pDisp); break; } ::Sleep(1000);} if (!pDisp) { ::MessageBox(NULL, "Failed to find instance!!", "Error", MB_ICONHAND);}else { ::MessageBox(NULL, "Got instance of Excel!", "Success", MB_OK);}//Release the no-longer-needed IUnknown...if (pUnk) pUnk->Release();//... Add your automation code for Excel here ...//Release pDisp when no longer needed...if (pDisp) pDisp->Release();//Cleanup COM...CoUninitialize();
อ้างอิง
สำหรับข้อมูลเพิ่มเติมให้คลิกหมายเลขบทความต่อไปนี้เพื่อดูบทความในฐานความรู้ของ Microsoft:
๑๙๒๙๑๙ วิธีการทำให้ฐานข้อมูล Access ที่มีความปลอดภัยโดยอัตโนมัติโดยใช้ Visual Basic
๒๓๗๓๓๘ ข้อความแสดงข้อผิดพลาดโดยใช้ WordMail: "วิธีการนี้หรือคุณสมบัตินี้ไม่พร้อมใช้งาน"
๒๔๐๗๙๔ วิธีกำหนดเส้นทางสำหรับแอปพลิเคชัน Office