Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How do I integrate compiled .NET code with QuickMacros?
#1
Say I have the following very simple class in C#:

Code:
Copy      Help
public class Arithmetic {

     public Arithmetic () {
     }

     public static int AddIntegers (int a, int b) {
          return a + b;
     }

}

Let's say I need to use this AddIntegers function from my class. What is it I should do? I first thought of creating a class library in Visual Studio .NET 2003 and compiling it into a DLL, hoping I could use the QM dll function like this:

Code:
Copy      Help
dll "C:\Program Files\MyApp\MyDLL.dll" #AddIntegers a b

However, although QM does find my DLL, it says it does not find the function. I also can't do

Code:
Copy      Help
dll "C:\Program Files\MyApp\MyDLL.dll" #Arithmetic.AddIntegers a b

because QM complains that the "." is an unexpected character.

I'm sure I'm not going the right way. In fact, I'm pretty sure I am not. I hope you guys enlighten me.

Thanks in advance!
#2
I am not familiar with C#, and don't know how to export functions as dll functions. But you can create COM dll. I experimented with it a little. Not perfect, but works.

In project properties, set Register for COM Interop to True. Without this, type library is not created. Add IArithmetic interface, and set the Arithmetic class to implement it. Here is the code:

Code:
Copy      Help
using System;

namespace ClassLibrary2
{
public interface IArithmetic
{
int AddIntegers(int a, int b);
}

/// <summary>
/// Summary description for Class1.
/// </summary>
public class Arithmetic :IArithmetic
{
public Arithmetic()
{
//
// TODO: Add constructor logic here
//
}

#region IArithmetic Members

public int AddIntegers(int a, int b)
{
// TODO:  Add Arithmetic.AddIntegers implementation
return a+b;
}

#endregion
}
}

In QM, add type library declaration, and compile the macro. Then you can view members when you type a period. Create object of type IArithmetic, and call its member functions.

Code:
Copy      Help
typelib ClassLibrary2 "C:\Documents and Settings\G\Desktop\ClassLibrary2\bin\Debug\ClassLibrary2.tlb"
;ClassLibrary2.Arithmetic a._create ;;this does not work, because IArithmetic is not default interface (I don't know why)
ClassLibrary2.IArithmetic i._create(uuidof(ClassLibrary2.Arithmetic))
out i.AddIntegers(2 4)
#3
And this is with two methods and two properties.

When compiling C#, exit QM, because the type library is locked by QM.

Code:
Copy      Help
using System;

namespace ClassLibrary2
{
    public interface IArithmetic
    {
        int AddIntegers(int a, int b);
        string AddStrings(string a, string b);

        int Prop1
        {
            get;
            set;
        }

        string Prop2
        {
            get;
        }
    }

    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    public class Arithmetic :IArithmetic
    {
        int m_prop1;
        string m_prop2;

        public Arithmetic()
        {
            //
            // TODO: Add constructor logic here
            //
            m_prop1=0;
            m_prop2="aaaaaaa";
        }

        #region IArithmetic Members

        public int AddIntegers(int a, int b)
        {
            // TODO:  Add Arithmetic.AddIntegers implementation
            return a+b;
        }

        public string AddStrings(string a, string b)
        {
            return a+b;
        }

        public int Prop1
        {
            get
            {
                return m_prop1;
            }
            set
            {
                m_prop1=value;
            }
        }

        public string Prop2
        {
            get
            {
                return m_prop2;
            }
        }

        #endregion

    }
}

Code:
Copy      Help
typelib ClassLibrary2 "C:\Documents and Settings\G\Desktop\ClassLibrary2\bin\Debug\ClassLibrary2.tlb"
ClassLibrary2.IArithmetic i._create(uuidof(ClassLibrary2.Arithmetic))

out i.AddIntegers(2 4)

out i.AddStrings("Q" "M")

i.Prop1=5
out i.Prop1

out i.Prop2
#4
I will try that today and report results.

Thank you.
#5
This worked like a charm! Thanks a lot, Gintaras!

Now, how do I create triggers for my macros? I need for one of my macros to start at certain time everyday and another one to watch for a file in certain directory and start once that file gets created. Is this all possible?

I'm still trying to understand the difference between a macro, a function and a member function.
#6
To run macro at a certain time, in Properties click Schedule, and create scheduled task.

To run macro when certain file is created, create function like this:

Code:
Copy      Help
str s.expandpath("$desktop$\test2.txt")
rep
,if(dir(s)) break
,1

mes "created"

To run it when QM starts, insert this in the init2 function:

mac "FunctionName"

Here is another version:
Code:
Copy      Help
str s.expandpath("$desktop$\test2.txt")

rep
,;wait until deleted
,rep
,,if(!dir(s)) break
,,1
,,
,;wait until created
,rep
,,1
,,if(dir(s)) break
,
,mac "MacroName"
#7
I haven't even been able to test this. Here's my dilema:

This is part of the code of my class:

Code:
Copy      Help
namespace NamespaceX
{

    public enum DatabaseType
    {
        SQLServer = 1,
        DB2 = 2
    }

    public struct JobParameter
    {
        public string parameterName, parameterValue;
    }

    public interface IDbJobHandler
    {
        void Configure (string appDbServer, string appDbName,
            bool appDbWindowsAuthentication, string appDbUserName, string appDbPassword);

        bool RunJob (string jobId, JobParameter[] parameters, bool autoCommits,
            string server, string dbName, string dataSource,
            bool windowsAuthentication, string userName, string password,
            ref long mainCommandAffectedRows);
    }

    public class DbJobHandler: IDbJobHandler
    {
        
        private string appDbServer, appDbName, appDbUserName, appDbPassword;
        private bool appDbWindowsAuthentication;
        
        public DbJobHandler ()
        {
        }

        
        public void Configure (string appDbServer, string appDbName,
            bool appDbWindowsAuthentication, string appDbUserName, string appDbPassword)
        {
            this.appDbServer = appDbServer;
            this.appDbName = appDbName;
            this.appDbWindowsAuthentication = appDbWindowsAuthentication;
            this.appDbUserName = appDbUserName;
            this.appDbPassword = appDbPassword;
        }


        public bool RunJob (string jobId, JobParameter[] parameters, bool autoCommits,
            string server, string dbName, string dataSource,
            bool windowsAuthentication, string userName, string password,
            ref long mainCommandAffectedRows)
        {
            :
            :
            some code
            :
            :
        }
    }

}

And here's my QM code so far:

Code:
Copy      Help
typelib library "D:\Development\SyncS6MIS\SyncS6MISData\bin\Release\SyncS6MISData.tlb"

;----------------------------------------------------------------------------------
; DbJobHandler database configuration
;----------------------------------------------------------------------------------
str DJH_SERVER, DJH_DBNAME, DJH_USERNAME, DJH_PASSWORD
int DJH_WINAUTH

DJH_SERVER = "xxxxx"
DJH_DBNAME = "xxxxx"
DJH_WINAUTH = -1  ;;False
DJH_USERNAME = "xxxxx"
DJH_PASSWORD = "xxxxx"

;----------------------------------------------------------------------------------
; S6MIS database configuration
;----------------------------------------------------------------------------------
str S6M_SERVER, S6M_DBNAME, S6M_DATASOURCE, S6M_USERNAME, S6M_PASSWORD
int S6M_WINAUTH

S6M_SERVER = "xxxxx"
S6M_DBNAME = "xxxxx"
S6M_DATASOURCE = "xxxxx"
S6M_WINAUTH = -1  ;;False
S6M_USERNAME = "xxxxx"
S6M_PASSWORD = "xxxxx"

;----------------------------------------------------------------------------------
; Miscellaneous configuration
;----------------------------------------------------------------------------------
int AUTOCOMMITS

AUTOCOMMITS = 1  ;;True

library.IDbJobHandler jobHandler._create(uuidof(library.DbJobHandler))
jobHandler.Configure(DJH_SERVER, DJH_DBNAME, DJH_WINAUTH, DJH_USERNAME, DJH_PASSWORD)

library.IJobParameter parameter
ARRAY(library.IJobParameter) parameterSet
int successful
long affectedRows

jobHandler.Configure(DJH_SERVER, DJH_DBNAME, DJH_WINAUTH, DJH_USERNAME, DJH_PASSWORD)

;----------------------------------------------------------------------------------
; Job: CP_CAT (Create & Populate Catalog tables
;----------------------------------------------------------------------------------
parameterSet.create(0)
successful = jobHandler.RunJob("CP_CAT", parameterSet, AUTOCOMMITS, S6M_SERVER, S6M_DBNAME, S6M_DATASOURCE, S6M_WINAUTH, S6M_USERNAME, S6M_PASSWORD, affectedRows)

out "I'm done!"

When I run it, I get a type mismatch error in the parameterSet parameter. I've also tried declaring parameter and parameterSet the following way instead and get the same type mismatch error:

Code:
Copy      Help
type PARAMETER str name, str value
PARAMETER parameter
ARRAY(PARAMETER) parameterSet

Any ideas?

Also, feel free to correct anything in my code or suggest other ways to do things. This is my first time coding in QM and my knowledge is only limited to the few examples I have seen on here, the application help and, most of all, your feedback.

Thanks once again!
#8
There is a bug in QM. It cannot pass arrays of structures. You can pass two array of strings instead.

C#:

public bool RunJob (string jobId, ref string[] pNames, ref string[] pValues, ...

QM:

ARRAY(BSTR) pNames.create(0)
ARRAY(BSTR) pValues.create(0)

successful = jobHandler.RunJob("CP_CAT", pNames, pValues, ...
#9
I copyed the exact example listed here. Set the COM DLL interop flag.

If I follow the directions and use the QM TypeLibraryies dialog, I can click "Browser" and add the type library. I can type "i" and access the methods.

But when I goto run the macro I get

Code:
Copy      Help
Error (RT) in Macro19: 0x80040154, Class not registered

If I tryed to register using Regsvr32 I get a messages about "dllResisterServer" entry point not found. I read on the web that for .net code you should use RegAsm.exe insted of the Regsvr32.

When I use regasm.exe it does get registered. But now when i try to run the macro i now get this

Code:
Copy      Help
Error (RT) in Macro19: 0x80070002, The system cannot find the file specified

This occurs on the line

Code:
Copy      Help
ClassLibrary2.IArithmetic i._create(uuidof(ClassLibrary2.Arithmetic))


I checked the path and permissions on the directory.

Any ideas?


Attached Files Image(s)
   
#10
When I create new project, I select Visual C# Projects, Class Library in the New Project dialog. Name project ClassLibrary2. Then set Register for COM interop in project Properties. Add code to Class1.cs. Compile. I see ClassLibrary2.dll and ClassLibrary2.tlb in bin\Debug folder. Add QM code. Run macro. Works well. If type library is specified by path, you even don't have it register with Type Libraries dialog or whatever. Maybe you selected something other than Class Library when creating new project.


Forum Jump:


Users browsing this thread: 3 Guest(s)