Использование plclient_kompas.dll C#

Автор bbb, 02.11.17, 17:16:55

« предыдущая - следующая »

0 Пользователей и 1 гость просматривают эту тему.

bbb

Задача вставить стандартное изделие из справочника СИ.
Проблема в подключении unmannaged dll (plclient_kompas.dll) и вызове функции PLInsert3D

Пробую так подключить:
[DllImport ("plclient_kompas.dll", CallingConvention = CallingConvention.StdCall)]
public static extern object PLInsert3D(IPARTLibProvader boPartlib,BOResponse boRes,ksPlacement place);

Потом вызываю
PLInsert3D(boPartlib,res,null); //boPartlib и res есть нормальные значения, placement пока null

получаю MarshalDirectiveExeption.

По идее надо как то записать что PLInsert3D возвращает MarshalAs(Unmanaged.IDispatch), но не знаю как...

Делал раньше на Delphi, работало, а вот как на C# перевести?

Frothener

bbb, скиньте пожалуйста файл SDK по справочнику СИ. Не могу найти его  внутри папок с программой. Заранее благодарю.

bbb

В новой версии справки уже есть пример на C#
/*

* Необходимо у подключаемых библиотек BOSimple и PARTLibClient выставить значение параметра

* Embed Interop Types = False

*

* */

using System;

using Microsoft.Win32;

using System.Reflection;

using System.Runtime.InteropServices;

using System.Windows.Forms;



using KAPITypes;

using Kompas6Constants;

using Kompas6API5;

using Kompas6API7;

using PARTLibClient;

using BOSimple;

using Kompas6Constants3D;

using stdole;

using System.Runtime.Versioning;



namespace PartLibAPI

{

    [ClassInterface(ClassInterfaceType.AutoDual)]

    public class InsertKompas

    {

        const string _LIBRARYNAME = "Вставка изделия в Компас из СИ";

        const string _KEYNAME = @"SOFTWARE\Classes\CLSID\{";

        const string _KOMPASLIBRARY = "Kompas_Library";

        const string _DLLPATH = "plclient_kompas.dll";

        const string _KERNEL32 = "kernel32.dll";



        #region Методы для работы библиотеки в Компас

        private KompasObject _kompas;



        // Название библиотеки

        [return: MarshalAs(UnmanagedType.BStr)]

        public string GetLibraryName()

        {

            return _LIBRARYNAME;

        }



        // Головная функция библиотеки

        public void ExternalRunCommand([In] short command, [In] short mode, [In, MarshalAs(UnmanagedType.IDispatch)] object kompas_)

        {

            _kompas = (KompasObject)kompas_;

            switch (command)

            {

                case 1:

                    InsertInKompas(_kompas);

                    break;

            }

        }



        // Функция получения меню

        // Описание функции можно найти в SDK API Компас

        [return: MarshalAs(UnmanagedType.BStr)]

        public string ExternalMenuItem(short number, ref short itemType, ref short command)

        {

            var result = string.Empty;

            itemType = 1; // "MENUITEM"

            switch (number)

            {

                case 1:

                    result = "Вставить";

                    command = 1;

                    break;

                //

                // Для корректной работы библиотеки необходимо добавить конец меню (или подменю)

                //

                case 2:

                    command = -1;

                    itemType = 3; // "ENDMENU"

                    break;

            }

            return result;

        }

        #endregion



        // Делегаты для работы с методами из plclient_kompas.dll

        [UnmanagedFunctionPointer(CallingConvention.StdCall)]

        private delegate int _PLInsert2D(IPARTLibProvider aPLClient, IBOResponse aMethodResponse, double aX, double aY, double aAngle);

        [UnmanagedFunctionPointer(CallingConvention.StdCall)]

        private delegate void _PLInsert3D([Out] out IDispatch retVal, IPARTLibProvider aPLClient, IBOResponse aMethodResponse, ksPlacement aPlacement);



        private void InsertInKompas(KompasObject kompas)

        {

            // Подключаемся к plclient_kompas.dll (получаем ссылку на запущенный экземпляр в процессе Компаса)

            IntPtr pDll = IntPtr.Zero;

            try

            {

                pDll = LoadLibrary(_DLLPATH);



                if (pDll == IntPtr.Zero)

                    throw new Exception("Не могу найти plclient_kompas.dll");



                // Получаем адреса экспортируемых функций из ранее загруженной plclient_kompas.dll

                var pProc2D = GetProcAddress(pDll, "PLInsert2D");

                var pProc3D = GetProcAddress(pDll, "PLInsert3D");



                // Получаем экземпляры делегатов, приведенных к соответствующему типу

                var PLInsert2D = (_PLInsert2D)Marshal.GetDelegateForFunctionPointer(pProc2D, typeof(_PLInsert2D));

                var PLInsert3D = (_PLInsert3D)Marshal.GetDelegateForFunctionPointer(pProc3D, typeof(_PLInsert3D));



                IApplication kompasApp = kompas.ksGetApplication7();

                if (kompasApp == null)

                    throw new Exception("Не удалось получить указатель на интерфейс приложения!");



                var doc2D = (Document2D)kompas.ActiveDocument2D();

                var doc3D = (Document3D)kompas.ActiveDocument3D();

                if ((doc2D == null) && (doc3D == null))

                    throw new Exception("Откройте документ или создайте новый!");



                // Подключаемся к API справочника

                IPARTLibProvider PLClient = null;

                try

                {

                    PLClient = new BOSimpleProvider();

                    var errorMsg = String.Empty;



                    // Подключаемся к серверу приложений

                    if (PLClient.Connect(ref errorMsg) == 0)

                    {

                        try

                        {

                            // Получаем доступ к изделиям и папкам в справочнике

                            var commonData = PLClient.CreateCommonDataObj();

                            commonData.InitUserData();



                            string plm2D = "2D"; // Документ 2D

                            string plm3D = "Solid3D"; // Документ 3D



                            // Типы документов Компаса

                            string[] methodNames = { "", "КОМПАС 2D", "КОМПАС 2D", "КОМПАС 3D", "КОМПАС 3D", "КОМПАС 3D", "" };

                            string[] docName = { "?", plm2D, plm2D, plm3D, plm3D, plm3D, "?" };

                           

                            // Получаем тип документа

                            var docType = GetDocType(kompasApp);



                            ksPart mainPart = null;

                            ksPart pPart = null;

                            ksPlacement partPlace = null;

                            if (docType == DocumentTypeEnum.ksDocumentAssembly)

                            {

                                if (doc3D != null)

                                {

                                    mainPart = doc3D.GetPart((short)Part_Type.pTop_Part);

                                    if (mainPart != null)

                                    {

                                        pPart = doc3D.GetPart(0);

                                        partPlace = pPart != null ? pPart.GetPlacement() : mainPart.GetPlacement();

                                 }

                               }

                           }

                           

                            // Задаем режим работы справочника в зависимости от типа активного документа в КОМПАС

                            commonData.SetFindOptions(docName[(int)docType]);

                            // Путь до корневого каталога с ISO стандартами по уникальному ID

                            var ISOFolder = commonData.FolderByID("A259_151417DFF6474BF6");

                            // Просматриваем каталог в глубину



                            while (ISOFolder.FolderCollection().Count() > 0)

                            {

                                ISOFolder = ISOFolder.FolderCollection().Folder(0);

                                // В случае если в каталоге есть хотя бы один класс

                                if (ISOFolder.ClassCollection().Count() > 0)

                                {

                                    // Получаем указатель на интерфейс первой типоразмерной таблицы его изделий

                                    var ISOClass = ISOFolder.ClassCollection().plClass(0);

                                    var instance = ISOClass.Instances("", docName[(int)docType]);

                                    var paramGrid = instance.ParamGrid(0);

                                   

                                    // Просматриваем типоразмерную таблицу сверху-вниз

                                    for (int i = 0; i < paramGrid.PGRowCount(); i++)

                                    {

                                        // Выбираем строку

                                        paramGrid.SelectRow(i);

                                        // Получаем полный location получившегося изделия

                                        var location = instance.plPart().GetLocation(0);

                                        // Получаем метод для вставки изделия в зависимости от типа активного документа

                                        var methodResponce = PLClient.GetMethod(location, methodNames[(int)docType]);



                                        // Вставляем изделие в КОМПАС

                                        var X = 5 * i * Math.Sin(15 * Math.PI * i / 180);

                                        var Y = 5 * i * Math.Cos(15 * Math.PI * i / 180);

                                        var Angle = 180 - i * 15;

                                        IDispatch kPart;

                                        switch (docType)

                                        {

                                            case DocumentTypeEnum.ksDocumentAssembly:

                                                // Задаем место в сборке

                                                partPlace.SetOrigin(X, Y, 0);

                                                PLInsert3D(out kPart, PLClient, methodResponce, partPlace);

                                                break;

                                            case DocumentTypeEnum.ksDocumentDrawing:

                                                PLInsert2D(PLClient, methodResponce, X, Y, Angle);

                                                break;

                                            case DocumentTypeEnum.ksDocumentFragment:

                                                PLInsert2D(PLClient, methodResponce, X, Y, Angle);

                                                break;

                                            case DocumentTypeEnum.ksDocumentSpecification:

                                                PLInsert3D(out kPart, PLClient, methodResponce, null);

                                                break;

                                        }

                                    }

                                }

                            }

                        }

                        catch (Exception ex)

                        {

                            kompas.ksMessage(ex.Message);

                        }

                        finally

                        {

                            // Отключаемся от сервера приложений

                            PLClient.Disconnect();

                        }

                    }

                    else

                        kompas.ksMessage("Ошибка подключения к серверу приложений: " + errorMsg);

                }

                catch (Exception ex)

                {

                    kompas.ksMessage("Ошибка! Не удалось создать COM-объект." + ex.Message);

                }

            }

            catch (Exception ex)

            {

                kompas.ksMessage(ex.Message);

            }

            finally

            {

                // Освобождаем загруженную plclient_kompas.dll

                FreeLibrary(pDll);

            }

        }



        /// <summary>

        /// Метод определения типа документа

        /// </summary>

        /// <param name="kompasApp"></param>

        /// <returns></returns>

        private DocumentTypeEnum GetDocType(IApplication kompasApp)

        {

            return kompasApp.ActiveDocument == null ? DocumentTypeEnum.ksDocumentUnknown : kompasApp.ActiveDocument.DocumentType;

        }



        // Импортируем в проект методы из kernel32.dll для подключения к plclient_kompas.dll

        [DllImport(_KERNEL32, CharSet = CharSet.Unicode, SetLastError = true)]

        [ResourceExposure(ResourceScope.Process)]

        public static extern IntPtr LoadLibrary(string libFilename);



        [DllImport(_KERNEL32, CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]

        static internal extern IntPtr GetProcAddress(IntPtr HModule, [MarshalAs(UnmanagedType.LPStr), In] string funcName/*lpcstr*/);



        [DllImport(_KERNEL32, CharSet = CharSet.Unicode, SetLastError = true)]

        [ResourceExposure(ResourceScope.Process)]

        public static extern bool FreeLibrary(IntPtr hModule);

       



        #region COM Registration

        // Эта функция выполняется при регистрации класса для COM

        // Она добавляет в ветку реестра компонента раздел Kompas_Library,

        // который сигнализирует о том, что класс является приложением Компас,

        // а также заменяет имя InprocServer32 на полное, с указанием пути.

        // Все это делается для того, чтобы иметь возможность подключить

        // библиотеку на вкладке ActiveX.

        [ComRegisterFunction]

        public static void RegisterKompasLib(Type t)

        {

            RegistryKey regKey = Registry.LocalMachine;

            try

            {

                var keyName = string.Format("{0}{1}{2}", _KEYNAME, t.GUID.ToString(), "}");

                regKey = regKey.OpenSubKey(keyName, true);

                regKey.CreateSubKey(_KOMPASLIBRARY);

                regKey = regKey.OpenSubKey("InprocServer32", true);

                regKey.SetValue(null, System.Environment.GetFolderPath(Environment.SpecialFolder.System) + @"\mscoree.dll");

            }

            catch (Exception ex)

            {

                MessageBox.Show(string.Format("При регистрации класса для COM-Interop произошла ошибка:\n{0}", ex));

            }

            finally

            {

                regKey.Close();

            }

        }



        // Эта функция удаляет раздел Kompas_Library из реестра

        [ComUnregisterFunction]

        public static void UnregisterKompasLib(Type t)

        {

            RegistryKey regKey = Registry.LocalMachine;

            var keyName = string.Format("{0}{1}{2}", _KEYNAME, t.GUID.ToString(), "}");

            RegistryKey subKey = regKey.OpenSubKey(keyName, true);

            try

            {

                subKey.DeleteSubKey(_KOMPASLIBRARY);

            }

            finally { subKey.Close(); }

        }

        #endregion

    }

}