Using Microsoft.office.interop.word in sharepoint server - sharepoint

So I really need to run word and microsoft.office.interop.word on a sharepoint server. There are no replacement libraries that it is possible to use in order to gain this functionality in order to get the following code to work.
string filenameopen = #"C:\tmp\file.docx";
Word.Application wordApp = new Word.Application();
properties.ListItem["Title"] = "1725";
properties.ListItem.Update();
Word.Document document = wordApp.Documents.Open(filenameopen);
int commentscount = document.Comments.Count;
int revisionscount = document.Revisions.Count;
document.ActiveWindow.Close();
wordApp.Application.Quit(-1);
Would anyone be able to tell me a viable workaround for this.
If you are going to say "You should not use Word (a desktop application for users) in a server process (headless). " or words to that effect, please do not comment here.

Microsoft recommends against installing those libraries on your server. Use OpenXML and the SharePoint CSOM API instead.

Related

Unable to add records to Sharepoint List from Excel VBA using shared link

I'm trying to create an Excel user form that will add newrecords to a Sharepoint List. The problem is that this form needs to be available to all users in my organization, without their being specifically permissioned to the List.
The basic URL for the Sharepoint List looks something like this:
https://myorg.sharepoint.com/personal/myname/;LIST=SubmissionsTest;
However, this link only works for me. If I try to Share the List with people in my company, Sharepoint provides me with a link that looks like this:
https://myorg.sharepoint.com/:l:/g/personal/myname/arandom50charactertextstring
Test users have confirmed they can access the List via the second link, but not the first.
To push records into the List from Excel, I've created the following VBA code:
Dim cnt As ADODB.Connection
Dim rst As ADODB.Recordset
Dim mySQL As String
Set cnt = New ADODB.Connection
Set rst = New ADODB.Recordset
mySQL = "SELECT * FROM SubmissionsTest;"
With cnt
.ConnectionString = _
"Provider=Microsoft.ACE.OLEDB.12.0;WSS;IMEX=0;RetrieveIds=Yes;" _
& "DATABASE=https://myorg.sharepoint.com/personal/myname/;LIST=SubmissionsTest;"
.Open
End With
rst.Open mySQL, cnt, adOpenDynamic, adLockOptimistic
rst.AddNew
rst.Fields("Title") = Int(Now() * 100000)
rst.Fields("testEntry") = "This is a test submission"
rst.Fields("testSubmitter") = Environ("UserName")
rst.Update
If CBool(rst.State And adStateOpen) = True Then rst.Close
If CBool(cnt.State And adStateOpen) = True Then cnt.Close
MsgBox "Your submission has been received."
This code works fine when I run it. As expected, it does not run for my test users. However, when I try substituting that second, Sharepoint-provided link into the Connection String, the code no longer works either for me or my test users. Instead, we receive errors telling us the SubmissionsTest object cannot be found.
I have yet to be able to figure out how I can tweak this code so that the Shareable link is recognized. Does anyone have any ideas on how this can be accomplished?
Thanks in advance for any suggestions.
OK, I found the solution after studying this posting on the Microsoft forums: https://social.technet.microsoft.com/Forums/en-US/2a1b718a-e9a5-4a1d-96a9-97804ebef769/vba-to-insert-record-to-an-existing-sharepoint-online-list?forum=sharepointgeneral
As indicated in the code above, the Connection String I was trying to use was:
DATABASE=https://myorg.sharepoint.com/personal/myname/;LIST=SubmissionsTest;
Even after permissioning the Sharepoint List for anyone in the firm, Excel reported that it was unable to find the table "SubmissionsTest". On the recommendation of the post above, I looked up the GUID values for the List. That returned a string that looked something like this:
<LIST><VIEWGUID>alongstringofalphanumericcharacters</VIEWGUID>
<LISTNAME>anotherstringofcharacters</LISTNAME>
<LISTWEB>https://myorg.sharepoint.com/personal/myname/</LISTWEB>
<LISTSUBWEB></LISTSUBWEB><ROOTFOLDER></ROOTFOLDER></LIST>
Once I changed the Connection String to this:
DATABASE=https://myorg.sharepoint.com/personal/myname/;LIST={anotherstringofcharacters};
the code now works for everyone. My conclusion is that, on SharePoint O365, table names cannot necessarily be trusted. Sometimes, the GUID values will need to be referenced directly.

Secure data type to store password in a VBA.NET forms app in Systems.Setting

Need to store the username and password for an outside application inside of a windows forms vb.net app. For initial testing, I just set the settings type to "Text", but want more security.
There are System.Security and Encryption types available, but not sure where to begin. Any suggestions on how to Add, Update, and Delete the values is appreciated. Seems to be much more involved than the plain text.
Although I want some level of security, this is not for any type of financial or medical application.
EDIT: Code Error System.Configuration.Configuration Type is not defined.
Dim config As System.Configuration.Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
Dim configSection ConfigurationSection
configSection = config.ConnectionStrings
If Not (configSection Is Nothing) Then
If Not (configSection.ElementInformation.IsLocked) Then
configSection.SectionInformation.ProtectSection ("DataProtectionConfigurationProvider")
configSection.SectionInformation.ForceSave = True
config.Save(ConfigurationSaveMode.Full)
End If
End If
.NET Framework Developer's Guide: Cryptographic services
Decided to stick with the string type and just encrypt the values being saved. The answer to this was helpful: How to encrypt a string in .NET?

SharePoint 2007: How to check if a folder exists in a list using web services?

Using SharePoint 2007 webservices or even Webdav, how can I check if a folder exists in a list (not document library) in SharePoint.
I would also like to check for subfolders...
Anyone have any idea on how this is done? I've asked Microsoft, and their official stance is that Microsoft provide no documentation on this. so any help will be most welcome...
Thanks in advance...
I have this code that creates a folder, but not sure how to modify it to check if the folder exists, also not even sure if this will work with sub folders...
private void CreateFolderUsingWebService(string listName, string folderName)
{
//Check Databox Folder Exists
//string folderAddress = siteAddress + #"/lists/" + listAddress + #"/" + folderName;
//wsDws.CreateFolder(folderAddress);
var doc = new XmlDocument();
XmlElement batch = doc.CreateElement("Batch");
string item = "<Method ID=\"1\" Cmd=\"New\">" +
"<Field Name=\"ID\">New</Field>" +
"<Field Name=\"FSObjType\">1</Field>" +
"<Field Name=\"BaseName\">" + folderName + "</Field></Method>";
batch.SetAttribute("ListVersion", "1");
//batch.SetAttribute("ViewName", "{GUID of View, including braces}");
batch.InnerXml = item;
wsLists.UpdateListItems(listName, batch);
}
Ok - this info might help the next SharePoint developer:
The function above works, and will even create a directory structure. BUT you need to pass the list name, not the list URL, this means if you localize your code, you need to pass the localized list name to the function.
I didn't bother adding a check for ifExists, because it seems to NOT create duplicates or fail if the directory already exists. I know this isn't a great solution, but I just don't have 2-3 weeks to research how to do it properly, so if you have any suggestions, comments are welcome.
Lastly any Microsoft representation reading this - might want to consider why there isn't any really good documentation on this with how to's from MS? Mmmmm
I went as far as downloading the MOSS Web Services SDK, and it contains 1 very vague example of how to use 1 function in the Lists web service, this simply is not enough information for those of us trying to put together robust solutions in MOSS. We need way more documentation please...

Extending WSS3 task lists to support recurring reminders

WSS 3.0 will let me send an email to a group when a new task is added to a task list. What I would like to do is to run a weekly task that sends out reminders of tasks due within certain periods, i.e. 2 days, 7 days, 14 days etc. I thought the simplest way would be to build a little C# app that sits on the WS2K3 box and queries the WSS database. Any ideas on which tables I should be checking? More generally is there an overall schema for the WSS3 database system?
If anyone is aware of an existing solution with code please let me know.
Thx++
Jerry
My suggestions:
don't create a console app, create a class that inherits from SPJobDefinition.
set SPJobLockType.Job to this timer, this will grant that the job is executed only once in the whole farm, even if you are running multiple front-end servers
in the, timer job, open the SPSite, SPWeb objects you need, then find the SPList\
Using SPQuery filter out only the items you need - I believe, you will have to filter out the ones where Status!=Complete
Loop through the results collection (which will be of type SPListItemCollection, apply your rules, checking the DueDate and Datetime.Now, send the e-mails
Since a task is simply a SPListItem, it has a Properties property, which is actually a property bag - you can add whatever properties you need. So, add a property My_LastSentReminderDate. Use this property to check if you are not sending too much of "corporate spam" :-)
To install your SPJobDefinition in a SharePoint farm, you can use a PowerShell script. I can give you examples, if needed.
Don't forget to Threading.Thread.CurrentThread.CurrentCulture = Your_SPWeb_Instance.Locale, otherwise date comparisons may not work if the web has a different locale!
EDIT: This is how a typical reminder looks like in my applications:
Public Class TypicalTimer
Inherits SPJobDefinition
Public Sub New(ByVal spJobName As String, ByVal opApplication As SPWebApplication)
'this way we can explicitly specify we need to lock the JOB
MyBase.New(spJobName, opApplication, Nothing, SPJobLockType.Job)
End Sub
Public Overrides Sub Execute(ByVal opGuid As System.Guid)
'whatever functionality is there in the base class...
MyBase.Execute(Guid.Empty)
Try
Using oSite As SPSite = New SPSite("http://yourserver/sites/yoursite/subsite")
Using oWeb As SPWeb = oSite.OpenWeb()
Threading.Thread.CurrentThread.CurrentCulture = oWeb.Locale
'find the task list and read the "suspects"
Dim oTasks As SPList = oWeb.Lists("YourTaskListTitle")
Dim oQuery As New SPQuery()
oQuery.Query = "<Where><Neq><FieldRef Name='Status'/>" & _
"<Value Type='Choice'>Complete</Value></Neq></Where>"
Dim oUndoneTasks As SPListItemCollection = oTasks.GetItems(oQuery)
'extra filtering of the suspects.
'this can also be done in the query, but I don't know your rules
For Each oUndoneTask As SPListItem In oUndoneTasks
If oUndoneTask(SPBuiltInFieldId.TaskDueDate) IsNot Nothing AndAlso _
CDate(oUndoneTask(SPBuiltInFieldId.TaskDueDate)) < Now().Date Then
' this is where you send the mail
End If
Next
End Using
End Using
Catch ex As Exception
MyErrorHelper.LogMessage(ex)
End Try
End Sub
End Class
To register a timer job, I typically use this kind of a script:
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Administration")
[System.Reflection.Assembly]::LoadWithPartialName("Your.Assembly.Name.Here")
$spsite= [Microsoft.SharePoint.SPSite]("http://yourserver/sites/yoursite/subsite")
$params = [System.String]("This text shows up in your timer job list (in Central Admin)", $spsite.WebApplication
$newTaskLoggerJob = new-object -type Your.Namespace.TypicalTimer -argumentList $params
$schedule = new-object Microsoft.SharePoint.SPDailySchedule
$schedule.BeginHour = 8
$schedule.BeginMinute = 0
$schedule.BeginSecond = 0
$schedule.EndHour = 8
$schedule.EndMinute = 59
$schedule.EndSecond = 59
$newTaskLoggerJob.Schedule = $schedule
$newTaskLoggerJob.Update()
Any time you need something in sharepoint that is executed periodically, 99 times out of a 100 you'll need to build a TimerJob. These are scheduled tasks that run inside SharePoint and you can create your own, then using a feature + featurereceiver to actually "install" the timoerjob (definition) and assign it a schedule.
For more info: see Andrew Connell's article on TimerJobs.
P.S. Never query /update the databases related to SharePoint directly! This will make you "unsupported", i.e. if anything happens microsoft will charge (a lot of) money to come and fix it, instead of being able to ask for regular support. (if you are say an MSDN subscriber you get up to 4 free support calls a year).
Don't bother trying to go directly to the database. You will have a very hard time because it's undocumented, unsupported, and not recommended. SharePoint does in fact have a full featured object model though.
If you reference Microsoft.SharePoint.dll (located in the Global Assembly Cache of a machine with SharePoint installed on it) you can access the data that way. The objects you'll want to start with are SPSite, SPWeb, SPList, SPQuery, and SPListItem. All of which you can find very easily on http://msdn.microsoft.com in a search.
Another less-flexible but code-free possibility you could try is creating several different views that include upcoming tasks then via the GUI set up an alert for when items are added to that view.

COM Integration from ALBPM - Cannot find IDispatch for '{00020906-0000-0000-C000-000000000046}'

I am trying to use the Office COM components in order to create Word and Excel documents. Unfortunately I can not achieve this because I am getting an error.
Cannot find IDispatch for
'{00020906-0000-0000-C000-000000000046}'
in module
'{00020905-0000-0000-C000-000000000046}',
v8.3
I tried reinstalling Office, my application (ALBPM) and my interface (combsvc) but it is not working.
I want to know how can I install IDispatch, or how can I know if it is installed in the correct module. Some times the error says:
Cannot find IDispatch for
'{000209FF-0000-0000-C000-000000000046}'
... instead of
00020906-0000-0000-C000-000000000046
The code I'm using generate these errors is:
wordAppl.visible = false
wordDocs = wordAppl.documents
contratoTemplate = "C:\\albpmFiles\\mandatory\\aTemplate.doc"
// .doc template
convenioTemplate = "C:\\albpmFiles\\mandatory\\ConvenioModificatorio.doc"
// .doc template
saveContrato = "C:\\albpmFiles\\temp\\"
// where to save.
saveConvenio = "C:\\albpmFiles\\temp\\"
contratoName = "NewContact.doc"
wordDoc = open(wordDocs, fileName : contratoTemplate)
bookmark = item(wordDoc.bookmarks, index : "atrDescripcion")
insertAfter bookmark.range
using text = instSolicitud.atrDescripcion
bookmark = item(wordDoc.bookmarks, index : "atrObjProveedor_atrNombre")
insertAfter bookmark.range
using text = instSolicitud.atrObjProveedor.atrNombre
bookmark = item(wordDoc.bookmarks, index : "atrObjProveedor_atrDireccion")
insertAfter bookmark.range
using text = instSolicitud.atrObjProveedor.atrDireccion
filename = saveContrato + contratoName
end
// Extras - Fin
saveAs wordDoc
using fileName = filename
Any information you have about the IDispatch, or these registry entries, well be very appreciated, even if you can tell me where to find more info about this.
Thanks a lot.
Daniel.
From the error you get I assume that you are using Word 2003.
Have you made sure that the COM brigde service is correctly installed and running?
combsvc -install
combsvc -start
will register combsvc as service and then start it.
Please also have a look at the example for Word at the bottom of page 150 in the ALBPM Reference Guide.
The fact that it is sometimes working and sometimes could be an issue with ALBPM. Are you using the latest version and updates?
Another option - and quite frequent problem with Word automation - would be that the automated instance of Word is displaying a modal dialog box and is waiting for user interaction. You can switch of the display of modal dialogs by setting
Application.DisplayAlerts = 0
However, this will unfortunately not prevent all popups from being displayed.
Is there actually an instance of Word started? If so, can you make the Window visible and see if documents can be opened or if there is a popup blocking the application?
Daniel,
I'm taking a stab in the dark here. It looks like you're using BEA systems Aqualogic BPM which I have a feeling is a Java based tool. From digging about it looks like combsvc is actually a COM bridge service to allow ALBPM to speak to COM from Java:
http://edocs.bea.com/albsi/docs60/studio/index.html?t=studio/catalog/catalog_component/COM/c_COM_Bridge.html
I'm thinking this is your point of failure.
About your question on IDispatch, you don't actually install IDispatch. IDispatch is a interface used by COM to expose objects, methods and properties to late bound COM automation clients such as scripting languages (e.g. ASP or VBScript). It's part of the infrastructure of COM, if this was broken you'd see lots more problems with your machine.
I'd probably advise popping a question in here:
http://forums.oracle.com/forums/forum.jspa?forumID=560
To inspect installed COM Interfaces on your PC i suggest you download oleview.exe which is part of the Windows 2003 resource Kit
I actually have {00020906-0000-0000-C000-000000000046} but also no IDispatch interface and get a "Class not registered" error when trying to create an instance of it. My home PC doesn't have office installed just the Office tools which is most likely the cause.
In the past when automating Office Applications i was always able to talk to a version independent ProgID's such as "Excel.Application". Are you sure your referencing the right COM Objects ? Check it out in oleview or give us some more code to munch on :)
The code I am using is this, but I can not even see the first log, so I assume thereĀ“s an error with the conection, not with the code
wordAppl.visible = false
wordDocs = wordAppl.documents
contratoTemplate = "C:\\albpmFiles\\mandatory\\aTemplate.doc"
// .doc template
convenioTemplate = "C:\\albpmFiles\\mandatory\\ConvenioModificatorio.doc"
// .doc template
saveContrato = "C:\\albpmFiles\\temp\\"
// where to save.
saveConvenio = "C:\\albpmFiles\\temp\\"
contratoName = "NewContact.doc"
wordDoc = open(wordDocs, fileName : contratoTemplate)
bookmark = item(wordDoc.bookmarks, index : "atrDescripcion")
insertAfter bookmark.range
using text = instSolicitud.atrDescripcion
bookmark = item(wordDoc.bookmarks, index : "atrObjProveedor_atrNombre")
insertAfter bookmark.range
using text = instSolicitud.atrObjProveedor.atrNombre
bookmark = item(wordDoc.bookmarks, index : "atrObjProveedor_atrDireccion")
insertAfter bookmark.range
using text = instSolicitud.atrObjProveedor.atrDireccion
filename = saveContrato + contratoName
end
// Extras - Fin
saveAs wordDoc
using fileName = filename

Resources