自动化Microsoft Access [英] automate Microsoft Access

查看:69
本文介绍了自动化Microsoft Access的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 


我想在Access Runtime中的不同主题中创建2个不同的.accde文件的2个实例, 


但收到错误消息: 


"调用线程无法访问此对象,因为不同的线程拥有它。"


Access.Application oAccessOne = null;

Access .Application oAccessTwo = null;

private void createInstances()

        {

            Parallel.Invoke(()=>

         {

            Console.WriteLine(" Begin first task ...");

            oAccessOne = ShellGetApp(@"""" + @" C:\Users\user\Downloads\One.accde" + @"""" + QUOT; /运行/嵌入和QUOT ;, ProcessWindowStyle.Minimized);

        },  //靠近第一操作



        ()=>

          {

           Console.WriteLine("开始第二个任务..." ;);

           oAccessTwo = She llGetApp(@"""" + @" C:\ Users \ user \Downloads \Two.accde" + @"""" +" / runtime / EMBEDDING",ProcessWindowStyle.Minimized);

                } //,  //关闭第二个动作



< /跨度>); // close parallel.invoke



  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //设置可见

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; if(!oAccessEPM.Visible)

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; oAccessEPM.Visible = true;



  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; if(!oAccessMPM.Visible)

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; oAccessMPM.Visible = true;

  &NBSP; &NBSP; &NBSP; }


私有Access.Application ShellGetApp(字符串sCmdLine,ProcessWindowStyle enuWindowStyle)

  &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; Access.Application oAccess = null;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; string sAccPath = null; // msaccess.exe的路径

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;处理p = null;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; int iMaxTries = 20; //最大GetActiveObject在失败之前尝试

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; int iTries = 0; // GetActiveObject尝试制作



  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //启用异常处理程序:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;试试
  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //获取msaccess.exe的路径:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; // tuka e patot

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; sAccPath = GetOfficeAppPath("Access.Application","msaccess.exe");
$


  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; if(sAccPath == null)

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; MessageBox.Show("无法确定msaccess.exe的路径");

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;返回null;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; }


  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //开始传递sCmdLine的新Access实例:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; ProcessStartInfo startInfo = new ProcessStartInfo();

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; startInfo.FileName = sAccPath;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; startInfo.Arguments = sCmdLine;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; startInfo.WindowStyle = enuWindowStyle;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; p = Process.Start(startInfo);

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; p.WaitForInputIdle(60000); //最多1分钟等待空闲输入状态



  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //将焦点移回此表单。这确保了访问权限
  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //在ROT中注册自己:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; this.Activate();



  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; tryGetActiveObject:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //启用异常处理程序:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;试试
  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //尝试使用GetActiveObject引用正在运行的$
  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //访问实例:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; oAccess =(Access.Application)Marshal.GetActiveObject(" Access.Application");

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; }¥b $ b  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;抓住
  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; // GetActiveObject可能已失败,因为有足够的时间没有b $ b  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //已过去查找正在运行的Office应用程序。等一下1/2

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //秒并重试GetActiveObject。如果您尝试iMaxTries

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //次和GetActiveObject仍然失败,假设其他一些为
  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; // GetActiveObject失败的原因并退出程序。

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; iTries ++;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; if(iTries< iMaxTries)

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; System.Threading.Thread.Sleep(500); //等待1/2秒

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; this.Activate();

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;转到tryGetActiveObject;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; }¥b $ b  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; MessageBox.Show(QUOT;无法GetActiveObject后" +

&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; iTries + QUOT;尝试。");

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;返回null;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; }


  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //返回Access Application对象:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;返回oAccess;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; }¥b $ b  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; catch(例外e)

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; MessageBox.Show(e.Message);

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //由于意外错误,请尝试退出访问权限:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;尝试//使用try..catch以防oAccess未设置

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; oAccess.Quit(Access.AcQuitOption.acQuitSaveNone);

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; }¥b $ b  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; catch {}

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; NAR(oAccess);

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; oAccess = null;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;返回null;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; }¥b $ b  &NBSP; &NBSP; &NBSP; }


私有字符串GetOfficeAppPath(字符串sProgId,字符串sEXE)

  &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //返回Office应用程序的路径。例如

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //GetOfficeAppPath("Access.Application"," msaccess.exe")返回

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; // Microsoft Access的完整路径。基于Q240794的方法。

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //如果在注册表中找不到路径,则返回null。



  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //启用异常处理程序:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;试试
  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; Microsoft.Win32.RegistryKey oReg =

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;   Microsoft.Win32.Registry.LocalMachine;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; Microsoft.Win32.RegistryKey oKey = null;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; string sCLSID = null;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; string sPath = null;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; int iPos = 0;



  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //首先,从注册表项中获取progid的clsid

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; // HKEY_LOCAL_MACHINE \Software \Classes \< PROGID> \ CLSID:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; oKey = oReg.OpenSubKey(@" Software \Classes \" + sProgId + @" \ CLSID");

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; sCLSID = oKey.GetValue("")。ToString();

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; oKey.Close();



  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //现在我们有了CLSID,找到服务器路径为

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; // HKEY_LOCAL_MACHINE \Software \Classes \CLSID \ 

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx} \ LocalServer32:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;奥基= oReg.OpenSubKey(@" Software\Classes\CLSID\" + sCLSID +

&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP ; @" \ LocalServer32");

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; sPath = oKey.GetValue("")。ToString();

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; oKey.Close();



  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //删除exe名称以外的任何字符:

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; iPos = sPath.ToUpper()。IndexOf(sEXE.ToUpper()); //基于0的位置

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; sPath = sPath.Substring(0,iPos + sEXE.Length);

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; return sPath.Trim();

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; }¥b $ b  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; catch(例外e)

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; string sta = e.ToString();

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;返回null;

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; }¥b $ b  &NBSP; &NBSP; &NBSP; }


  &NBSP; &NBSP; &NBSP;私人空虚NAR(对象o)

  &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; //释放Automation对象。

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP;尝试//使用try..catch,以防o未设置为
  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; {

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; Marshal.ReleaseComObject(o);

  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; }¥b $ b  &NBSP; &NBSP; &NBSP; &NBSP; &NBSP; catch {}

  &NBSP; &NBSP; &NBSP; }




解决方案

如果我理解你的代码, Marshal.GetActiveObject将返回当前正在运行的实例。如果你想在一个单独的线程上创建一个新实例,我想你可能想要Activator.CreateInstance。


另外,请记住Office应用程序不支持多个线程进入一次运行实例


Hi, 

I want to create 2 instances of 2 different .accde files in different threads in Access Runtime, 

but I get error message: 

"The calling thread cannot access this object because different thread owns it."

Access.Application oAccessOne = null;
Access.Application oAccessTwo = null;
private void createInstances()
        {
            Parallel.Invoke(() =>
                {
                    Console.WriteLine("Begin first task...");
                    oAccessOne = ShellGetApp(@"""" + @"C:\Users\user\Downloads\One.accde" + @"""" + " /runtime /EMBEDDING", ProcessWindowStyle.Minimized);
                },  // close first Action

                () =>
                {
                    Console.WriteLine("Begin second task...");
                    oAccessTwo = ShellGetApp(@"""" + @"C:\Users\user\Downloads\Two.accde" + @"""" + " /runtime /EMBEDDING", ProcessWindowStyle.Minimized);
                } //,  //close second Action

); //close parallel.invoke

            // set visible
            if (!oAccessEPM.Visible)
                oAccessEPM.Visible = true;

            if (!oAccessMPM.Visible)
                oAccessMPM.Visible = true;
        }

private Access.Application ShellGetApp(string sCmdLine, ProcessWindowStyle enuWindowStyle)
        {
            Access.Application oAccess = null;
            string sAccPath = null; //path to msaccess.exe
            Process p = null;
            int iMaxTries = 20; //max GetActiveObject attempts before failing
            int iTries = 0; //GetActiveObject attempts made

            // Enable exception handler:
            try
            {
                // Obtain the path to msaccess.exe:
                // tuka e patot
                sAccPath = GetOfficeAppPath("Access.Application", "msaccess.exe");

                if (sAccPath == null)
                {
                    MessageBox.Show("Can't determine path to msaccess.exe");
                    return null;
                }

                // Start a new instance of Access passing sCmdLine:
                ProcessStartInfo startInfo = new ProcessStartInfo();
                startInfo.FileName = sAccPath;
                startInfo.Arguments = sCmdLine;
                startInfo.WindowStyle = enuWindowStyle;
                p = Process.Start(startInfo);
                p.WaitForInputIdle(60000); //max 1 minute wait for idle input state

                // Move focus back to this form. This ensures that Access
                // registers itself in the ROT:
                this.Activate();

                tryGetActiveObject:
                // Enable exception handler:
                try
                {
                    // Attempt to use GetActiveObject to reference a running
                    // instance of Access:
                    oAccess = (Access.Application)Marshal.GetActiveObject("Access.Application");
                }
                catch
                {
                    //GetActiveObject may have failed because enough time has not
                    //elapsed to find the running Office application. Wait 1/2
                    //second and retry the GetActiveObject. If you try iMaxTries
                    //times and GetActiveObject still fails, assume some other
                    //reason for GetActiveObject failing and exit the procedure.
                    iTries++;
                    if (iTries < iMaxTries)
                    {
                        System.Threading.Thread.Sleep(500); //wait 1/2 second
                        this.Activate();
                        goto tryGetActiveObject;
                    }
                    MessageBox.Show("Unable to GetActiveObject after " +
                       iTries + " tries.");
                    return null;
                }

                // Return the Access Application object:
                return oAccess;
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
                // Try to quit Access due to an unexpected error:
                try // use try..catch in case oAccess is not set
                {
                    oAccess.Quit(Access.AcQuitOption.acQuitSaveNone);
                }
                catch { }
                NAR(oAccess);
                oAccess = null;
                return null;
            }
        }

private string GetOfficeAppPath(string sProgId, string sEXE)
        {
            //Returns path of the Office application. e.g.
            //GetOfficeAppPath("Access.Application", "msaccess.exe") returns
            //full path to Microsoft Access. Approach based on Q240794.
            //Returns null if path not found in registry.

            // Enable exception handler:
            try
            {
                Microsoft.Win32.RegistryKey oReg =
                   Microsoft.Win32.Registry.LocalMachine;
                Microsoft.Win32.RegistryKey oKey = null;
                string sCLSID = null;
                string sPath = null;
                int iPos = 0;

                // First, get the clsid from the progid from the registry key
                // HKEY_LOCAL_MACHINE\Software\Classes\<PROGID>\CLSID:
                oKey = oReg.OpenSubKey(@"Software\Classes\" + sProgId + @"\CLSID");
                sCLSID = oKey.GetValue("").ToString();
                oKey.Close();

                // Now that we have the CLSID, locate the server path at
                // HKEY_LOCAL_MACHINE\Software\Classes\CLSID\ 
                // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx}\LocalServer32:
                oKey = oReg.OpenSubKey(@"Software\Classes\CLSID\" + sCLSID +
                   @"\LocalServer32");
                sPath = oKey.GetValue("").ToString();
                oKey.Close();

                // Remove any characters beyond the exe name:
                iPos = sPath.ToUpper().IndexOf(sEXE.ToUpper()); // 0-based position
                sPath = sPath.Substring(0, iPos + sEXE.Length);
                return sPath.Trim();
            }
            catch (Exception e)
            {
                string sta = e.ToString();
                return null;
            }
        }

        private void NAR(object o)
        {
            // Releases the Automation object.
            try // use try..catch in case o is not set
            {
                Marshal.ReleaseComObject(o);
            }
            catch { }
        }


解决方案

If I understand your code, Marshal.GetActiveObject will simply return a currently running instance. I think you probably want Activator.CreateInstance if you want to create a new instance on a separate thread.

Also, keep in mind the the Office apps do not support multiple threads into a single running instance.


这篇关于自动化Microsoft Access的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆