Monday, October 14, 2013

excel addin subs called from vba

Hi,

SITUATION:
excel 2007, 2010, 2013
tested on excel 2013 only
compiled as any cpu
visual studio 2012 with office kit installed

PROBLEM:
We have too many subs in many excel sheets in our compagny
I am about to make some new subs for sharepoint 2013 and they need to be accessible for everyone
As you know vba cannot really access sharepoint 2013 client object model (yeah yeah i could call the DLL with all parameters, but, no thanks)

SOLUTION:
Program a excel addin and include the subs in it

PROBLEM:
you cannot simply call a sub in a addin from VBA
you need to go through a test first ;)

So here is my resulting code:

after you create a normal excel addin, you get:
Public Class ThisAddIn

    Private Sub ThisAddIn_Startup() Handles Me.Startup

    End Sub

    Private Sub ThisAddIn_Shutdown() Handles Me.Shutdown

    End Sub

end class

Your addin project must be called "exceladdin1" for this code

Change the code of the addin for this to be able to call any sub in your addin from vba:
(with parameter in bonus)
note: the test sub is "shared" to be able to call it from the other class created to be able to be called from vba

'=== use addin sub in vba in excel

'=== call from VBA:
'Sub CallVSTOMethod()
'    Dim addIn As COMAddIn
'    Dim automationObject As Object
'    addIn = Application.COMAddIns("exceladdin1")
'    automationObject = addIn.Object
'    automationObject.ImportData("Hello world!")
'End Sub

'=== http://msdn.microsoft.com/en-us/library/vstudio/bb608614.aspx (video have the right code, demo have not it seems)
'=== video CallAddInFromVBA.wmv (working)

Imports System.Data
Imports System.Runtime.InteropServices
Imports Excel = Microsoft.Office.Interop.Excel

<System.Runtime.InteropServices.ComVisibleAttribute(True)> _
<System.Runtime.InteropServices.InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface IAddInUtilities
    Sub ImportData(message As String)
End Interface


<System.Runtime.InteropServices.ComVisibleAttribute(True)> _
<System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)> _
Public Class AddInUtilities
    Implements IAddInUtilities

    ' This method tries to write a string to cell A1 in the active worksheet. 
    Public Sub ImportData(message As String) Implements IAddInUtilities.ImportData
        Call ThisAddIn.test(message)

    End Sub
End Class

Public Class ThisAddIn

    Private utilities As AddInUtilities

    Protected Overrides Function RequestComAddInAutomationService() As Object
        If utilities Is Nothing Then
            utilities = New AddInUtilities()
        End If
        Return utilities
    End Function

    Public Shared Sub test(message As String)
        MsgBox(message)
    End Sub
    '=== stas excel addin
    '=== made with visual studio 2010
    '=== debugged with excel 2013

    '=== this addin rearrange 2 sheet source display: database, notes
    '=== it generate a frame to enter data in it (bottom frame), sheet name: cartouche
    '=== it calculate the right width for database and notes columns to fill an A2 form with the notes and data
    '===
    '=== goal: make the final result PDF to be approvable by 4 poeple (numeric signatures)
    '=== goal: make final printed result usable in factory to adjust instruments settings for a machine


    Private Sub ThisAddIn_Startup() Handles Me.Startup

    End Sub

    Private Sub ThisAddIn_Shutdown() Handles Me.Shutdown

    End Sub

end class


now put that in your vba macro

---------------------- vba macro
'=== call from VBA:
Sub CallVSTOMethod()
    Dim addIn As COMAddIn
    Dim automationObject As Object
    addIn = Application.COMAddIns("exceladdin1")
    automationObject = addIn.Object
    automationObject.ImportData("Hello world!")
End Sub



Saturday, October 12, 2013

sharepoint 2013 copying files that have certain managed metadata terms to ntfs

Sharepoint 2013 - Visual studio 2012

SITUATION:
After migrating files to sharepoint and tagging them with managed metadata terms, our products are well managed. Every file needed to start a new project with a product model need approbation.

We have a site for each product, a document library for each product, and all our departements can work on the product itself before a new order (project) is processed.
So instead of starting a new order with an old order, we start it with a new product. That way, developpement and research can work on the product before we start a new order.

PROBLEM:
Unfortunatly, not all programs support sharepoint 2013 file access

So when a new order is started (new project or new submission) we copy all thoses files on a ntfs drive. Mainly because we have automation programs and cad software that does not support sharepoint 2013 web access very well.

Acrobat support the metadata terms tagging since 11.0.4, autocad does not. Webdav exist since a lot of years and is not yet supported by all software for accessing files. So i bet sharepoint with terms, will take about 20 years to be supported by all software.

Now when your managed metadata fields/columns in sharepoint are mandatory, you cannot even approve a document if the file was saved in sharepoint from a windows application that does not support sharepoint 2013, because the windows that ask you to enter the managed metadata does not pop up when the application does not support sharepoint. (office and acrobat have an activex that manage the save of the file to be able to choose the metadata while saving)

SOLUTION:
So programming such an active x to manage file saving for all the apllications in the world is too long for me. So I will simply put the new project in a normal windows ntfs file system when we start the new project.

I used the client object method to:
- query the main sharepoint site for products (http://sharepointsite/produits)
- query all the sub site (each sub site is a product)
- query all the documents library in each site (1 for each product)
- query the document library fields (columns) and extract the name of each column that use managed metadata
- present a list of choices to choose what product you want (sub site name, doc library name, metadata column name (must have same name as sub site)

Now the user choose: ACD (site name), Documents (library name), ACD (metadata fields with same name as site)

After that, i need to query the termstore to get sub product specification (type and number of rotors)
termstore:
- ACD
- RI
- ACD -- flux
- ACD -- type2
- ACD -- flux --- 4 rotors
- ACD -- flux --- 6 rotors

So i present the user with the second choice:
What type of ACD:
1 type01
2 type02
3 type03
4 type04

After this choice is made i get from the resultant term GUID the childrens terms from termstore
and present the third level of product choice:
type 02 was choosen
now choose sub specification:
1 2 rotors
2 4 rotors
3 6 rotors with stuff

I save the GUID of the 3 choices the user made in variables

Then i start scanning all the documents in the library that was choosen, in the site that was choosen

i also scanned the metadata field for all terms collections (multiple choices for each product)
Each document that have 1 of the 3 terms in the choices are selected to be copied in the new product
(in the managed metadata field of the document)

Note:
a document in sharepoint can now be tagger for ACD, type01, 4 rotor
if we make a new ACD we need the documents tagged ACD
if it's type01 we need the documents tagged type01
if a document is common for all type01, then we tag all sub terms (2 rotor, 4 rotor, 6 rotor)
etc.

I was told by many post on internet that this could not be done with client object model (COM) but it can.

PROBLEM:
the approved status of sharepoint is not very bright
if you show unnaproved files in your library, sharepoint will tell the file 3.1 is approved but it is not. only 3.0 is the right version
Now you can say hide unnaproved files, but the approver will still see then and the same problem come back

So i had to scan all version of all files to find last approved version by scanning the version number digits (3.1, i get version 3.0 url)

After that i asked kindly sharepoint to extract version 3.0 but it cannot be done
So i used the webclient to "download" the file with the version URL and it worked

Also, sharepoint was not always responding to a web query from client object model. So i had to use the timeout and make 3 request if neceesary, then a REAL error if all 3 request failed.

In short:
- choose product site, doc library that contain a metadata field that have the same name as site (this give term for product)
- ask termstore for subterms to make a sub choice
- choose product type (term)
- ask termstore for subterms to make a sub choice
- choose product sub type (number of rotors)
- scan files in the library
- scan terms fields of the file and choose every file that have one term common with any choice we made
- scan all version of the file and get URL of last major version (last approved version)
- download file and put it in a ntfs folder to start a new project

All this with COM (client object model) in a vb.net 2012 program running on computer client

Sorry i cannot post code here, it's a business project.
But i can gladly post some part of it if asked.