Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - mateiacd

Pages: [1]
1
>I wanted to log the execution of my add-in, and so I've  chosen log4net.

In what programming language have you written the add-in ?

Below is an example using Visual Studio 2012 Express Edition and C#

1.   Create a <<yourAddin>> Class library DLL. Choose of course your own suitable name for <<yourAddin>>

2.   Set the checkbox [ x ] Register for COM Interop  in the Project Settings -> Build tab

3.   Build the project.

If you run with Administrative rights,  Visual Studio will also register the DLL with regasm.exe.

Or if you prefer:

Register manually <<yourAddin>>.DLL with a command below similar to this:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe D:\Temp\<<yourAddin>>.dll /codebase

4.     Copy the log4net.config configuration file near the D:\Temp\<<yourAddin>>.dll

          Or if you prefer, copy the log4net.config file in the Sparx Enterprise Architect folder
"C:\Program Files (x86)\Sparx Systems\EA\log4net.config"
But this requires Administrative rights and in this case is not necessary to call log4net.Config.XmlConfigurator.ConfigureAndWatch

5.     In AssemblyInfo.cs, add the line below to the end of the file

[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]

          Or if you prefer, set a full path to the configuration file, in which case, again, is not necessary to call log4net.Config.XmlConfigurator.ConfigureAndWatch

[assembly: log4net.Config.XmlConfigurator(ConfigFile = "D:\\Temp\\log4net.config", Watch = true)]

6.    Write the code below in the main class of the DLL

Code: [Select]
using EA;
using log4net;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;

[ComVisible(true)]
public class AddIn
{
        private ILog log;

        public string EA_Connect(Repository repository)
        {
         
     //setup the configuration file
     //in this example, at step 4, I decide to use the 
     //log4net.config configuration file placed near the <<yourAddin>>.DLL file

    //this is is not necessary if the log4net.config is in the Sparx Enterprise Architect folder or a full path is specified in AssemblyInfo.cs

            string dllFullPath = Assembly.GetExecutingAssembly().Location;
            String logFile = Path.GetDirectoryName(dllFullPath)+"\\log4net.config";
         
//https://stackoverflow.com/questions/21166126/log4net-separate-config-file-not-working           
            FileInfo fileInfo = new FileInfo(logFile);
            log4net.Config.XmlConfigurator.ConfigureAndWatch(fileInfo);


             log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
             log.Info("\r\nEA_Connect '" + repository.ConnectionString + "'");

            return "AddIn connected";
        }
.
}


Example of log4net.config file

Code: [Select]
<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
    </configSections>

 
 <log4net>
   
<appender name="MyAppender" type="log4net.Appender.ConsoleAppender">
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date %level %logger - %message%newline" />
  </layout>

</appender>


   <appender name="MyFileAppender" type="log4net.Appender.FileAppender">
     <file value="D:\Temp\MainLog.txt" />
     <appendToFile value="true" />
     <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
     <layout type="log4net.Layout.PatternLayout">
       <conversionPattern value="%date{dd-MM-yyyy HH:mm:ss} %level %logger - %message%newline" />
     </layout>
   </appender>

 <root>
      <level value="ALL"/>
      <appender-ref ref="MyAppender" />
      <appender-ref ref="MyFileAppender" />

    </root>

 </log4net>

<startup><supportedRuntime version="v2.0.50727"/></startup>
 
</configuration>


2
Hi Geert,

Many thanks !! ;D The code below works correctly.

Code: [Select]
public void EA_MenuClick(Repository repository, string location, string menuName, string itemName)
  {
    repository.Authors.Refresh();
    MessageBox.Show(repository.Authors.Count.ToString());
  }

3
Hi,

I am using Enterprise Architect 12.1.0.1229

I wrote a C# add-in that reads the values of the Repository object, according to the documentation:

http://www.sparxsystems.com/enterprise_architect_user_guide/12.1/automation_and_scripting/availableresources.html
http://www.sparxsystems.com/enterprise_architect_user_guide/12.1/automation_and_scripting/eaadd-insea_menuclick.html

I wrote:

Code: [Select]
  public void EA_MenuClick(Repository repository, string location, string menuName, string itemName)
  {
    MessageBox.Show(repository.Authors.Count.ToString());
  }

When I follow these steps:

1. Open an EAP model
2. Call my Add-in from the menu and notice the value of the Authors.Count variable
3. Add or remove an author by following from the menu:  Project | Settings | Project Types | People > Project Author(s)
4. Call my Add-in again and notice the value of  the Authors.Count variable

You will notice that the two values are identical, which is of course incorrect.



 



4
Hi Geert

Now I understand what you wanted to say....

I mistyped the error message when I posted my question.
The error message looks like this:
Quote
An error has occurred: "U:\getting-started.eap"  isn't a valid path.

Thank you for answering, yes  indeed, "\\" gets translated to a single backslash.


The syntax  is correct. In C# folder paths must contain \\ as a folder separator.

And as mentioned, if I open a local model, like r.OpenFile("C:\\getting-started.eap");  everything is fine

And for the sake of clarity this doesn't work as well r.OpenFile(@"U:\getting-started.eap");

It's not a matter of syntax, for some reason, the Automation API doesn't work for mapped network drives.

The EA product itself (GUI) works fine.

5
Hello,

I am using Enterprise Architect 12.1.0.1229

I would like to use the Automation API in C# to open an EAP from a mapped network drive, like U:, R: etc

I mention that I have read/write access in these network folders and I also mention that the code works perfectly with models
opened from the local drive C: or from a MySQL database repository.

Using the simple code indicated below:
http://www.sparxsystems.com/enterprise_architect_user_guide/12.1/automation_and_scripting/setup.html

  EA.Repository r = new EA.Repository();
  r.OpenFile("U:\\getting-started.eap");
  r.CloseFile();
  r.Exit()

I always get the System.Runtime.InteropServices.COMException  error message:

Quote
An error has occurred: "U:\\getting-started.eap"  isn't a valid path.
Make sure that the path name is spelled correctly and you are connected to the server
on which the file resides.

The Interop.EA.dll version is 2.10.238.1, size 303104 bytes, dated 16.03.2016

6
Thank you very much Uffe for pointing me to use EA.Repository as a ProgID!!!

It seems that  EA.exe *32 is closed properly in Task Manager only if we explicitly call all three methods below:
OpenFile
CloseFile
ExitFile

Here is the relevant code, I hope it will be useful for other programmers  working with C++.

Code: [Select]
void Test1()
{
CLSID clsid;
CLSIDFromProgID(L"EA.Repository", &clsid);

IRepository* pRepository;
HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDualRepository, (void**)&pRepository);
if (FAILED(hr))
{
MessageBox(NULL,_T("CoCreateInstance failed"),_T("Testing app"),MB_OK);
return;
}

_variant_t fileName(_T("D:\\Temp\\getting-started.eap"));

pRepository->OpenFile(fileName);
_variant_t pg = pRepository->GetProjectGUID();
pRepository->CloseFile();
pRepository->Exit();

pRepository->Release();
}


and the other relevant code:

Code: [Select]
#include "stdafx.h"
#include <comdef.h>
#include <iostream>

using namespace std;

#import "C:\\Program Files (x86)\\Sparx Systems\\EA\\EA.tlb" no_namespace named_guids

void Test1();

int _tmain(int argc, _TCHAR* argv[])
{
 HRESULT hr = CoInitialize(NULL);
 if(FAILED(hr))
 {
MessageBox(NULL,_T("CoInitialize failed"),_T("Testing app"),MB_OK);
cout << " failed" << endl;
 }

 Test1();

 CoUninitialize();

 MessageBox(NULL,_T("Finish"),_T("Testing app"),MB_OK);
 return 0;

}


7
All right, I tried also EA.Repository

HKEY_CLASSES_ROOT\EA.Repository\CLSID
    {67F4E0FA-46A7-4255-B084-69A9433D08C3}

and still the instance of EA.exe *32 appears in Task Manager after closing my application.

However a colleague using Enterprise Architect version 10.0.1006 does not have this problem !

On his computer, my code works as expected, everything is cleaned up properly...

So it appears to be a case only for me using Enterprise Architect version 12.1.0.1229



8
In C++ I see no such functionality like Repository.Exit()
Can you explain how ? Thank you.

9
Hello,

I am using Enterprise Architect 12.1.0.1229

I would like to use the Automation API in Visual C++ 2010. I created a simple Win32 console project.

After trying a simple code like below for a console application, releasing the COM pointer I still see an EA process left running in the Windows task manager.

I am only trying to launch the Enterprise Architect COM server using the EA.App ProgID

HKEY_CLASSES_ROOT\EA.App\CLSID
    {3A9E4F92-8D27-495B-8B22-1D702B3F0C83}

I succeed, but  even after exiting the console application I see the EA.exe *32 in the list of processes

Can anybody help ? Thanks !
Code: [Select]
CoInitialize(NULL);

CLSID clsid;
OLECHAR wb[] = L"EA.App";
CLSIDFromProgID(wb, &clsid);


IDispatch* pDispatch;
HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void**)&pDispatch);
if (FAILED(hr))
{
MessageBox(NULL,_T("CoCreateInstance failed"),_T("Enterprise Architect"),MB_OK);
return;
}

pDispatch->Release();
CoUninitialize();

I also tried this variation with the same result. After the application closes, I still have the problem of getting rid of the EA.exe *32 process
Code: [Select]
IUnknown* pUnknown;
HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnknown);
if (FAILED(hr))
{
    MessageBox(NULL,_T("CoCreateInstance failed"),_T("Enterprise Architect"),MB_OK);
    return;
}


IDispatch* pDispatch;

cout << "Client: Calling QueryInterface() for IDispatch on " << pUnknown << endl;
hr = pUnknown->QueryInterface(IID_IDispatch, (void**)&pDispatch);

if (FAILED(hr))
{
MessageBox(NULL,_T("QueryInterface failed"),_T("Enterprise Architect"),MB_OK);
pUnknown->Release();
return;
}

pDispatch->Release();
pUnknown->Release();


P.S. Can I attach files to this post ? I would like to attach some screen captures.

Pages: [1]