|
The thing about OLE automation (and COM in general) is that it works practically the same in whatever language you use as a client (though the syntax may be slightly different).
Unfortunately, ApplicationClass.WordBasic returns an object and because of the Common Type System - a component of the .NET Framework - you can't simply call the method like you could in Delphi or VB (which internally uses the DISPID to invoke the dispatch function with any DISPARAMs you might specify).
There is a way, though, and it's not too easy. You need to declare the IDispatch interface in COM (merging the IUnknown methods in the same interface - do not inherit from a declared IUknown ). Then you call IDispatch.GetIDsOfNames to get the DISPID for DisableAutoMacros , and then use that in the call to IDispatch.Invoke .
The last line is easy and there are many eamples here on CodeProject that show examples, though it's pretty easy. The following is, of course, the method signature for Documents.Open :
public Document Open(
ref object FileName,
ref object ConfirmConversions,
ref object ReadOnly,
ref object AddToRecentFiles,
ref object PasswordDocument,
ref object PasswordTemplate,
ref object Revert,
ref object WritePasswordDocument,
ref object WritePasswordTemplate,
ref object Format,
ref object Encoding,
ref object Visible,
ref object OpenAndRepair,
ref object DocumentDirection,
ref object NoEncodingDialog); So, if you wanted to open a document and don't want/need to provide all those parameters, you can simply using Missing.Value (or null ):
object fileName = "C:\Example.doc";
object missing = Missing.Value;
Document doc = app.Documents.Open(ref fileName, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing); If you wanted to open the document as read-only, add the following line before calling Open and change the third parameter to ref readOnly :
object readOnly = true;
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Hi,
Can you tell me if I'm on the right track?
So far I've got:
Type t = Type.GetTypeFromProgID("Word.Application.10");
object MSWord = Activator.CreateInstance(t);
object WordBasic = MSWord.GetType().InvokeMember("WordBasic", BindingFlags.GetProperty,
null, MSWord, null);
WordBasic.GetType().InvokeMember("DisableAutoMacros", BindingFlags.Default |
BindingFlags.InvokeMethod | BindingFlags.Static, null,
WordBasic, new object [] {});
I've also tried :
Word.Application MSWord = new Word.ApplicationClass();
object o = MSWord.WordBasic;
o.GetType().InvokeMember("DisableAutoMacros",
BindingFlags.Default | BindingFlags.InvokeMethod |
BindingFlags.Static, null, o, new object [] {});
I have tried the InvokeMember call with many different Binding Flags but it always throws an Exception. Any help would again be most welcome.
|
|
|
|
|
This won't work. As I mentioned, the Common Type System (CTS) is what defines how types and members are defined and accessed by the runtime (basically). You can't simply get types that don't exist or invoke members that aren't defined on that type. The Type.GetTypeFromProgId , for example, still requires that the ProgID refers to a managed Type.
Instead, you must declare the IDispatch interface in managed code as I mentioned, then doing basically what you're doing above (in concept, not the actual code) to invoke the dispatch method DisableAutoMacros .
You can declare the IDispatch in managed code like so:
[Guid("00020400-0000-0000-c000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDispatch
{
[PreserveSig] int GetTypeInfoCount();
UCOMITypeInfo GetTypeInfo(
[MarshalAs(UnmanagedType.U4)] int iTInfo,
[MarshalAs(UnmanagedType.U4)] int lcid);
[PreserveSig] int GetIDsOfNames(
ref Guid riid,
string[] rgsNames,
[MarshalAs(UnmanagedType.U4)] int cNames,
[MarshalAs(UnmanagedType.U4)] int lcid,
out int[] rgDispId);
[PreserveSig] int Invoke(
int dispIdMember,
ref Guid riid,
[MarshalAs(UnmanagedType.U4)] int lcid,
[MarshalAs(UnmanagedType.U4)] int dwFlags,
ref DISPPARAMS pDispParams,
[Out] object[] pVarResult,
ref EXCEPINFO pExcepInfo,
[Out] IntPtr[] pArgErr);
}
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Firstly thanks for you help. I'm only a Student on my work placement and this type of thing is well above my head.
how about this sort of thing?
IDispatch wb = (IDispatch)WordBasic;
string[] rgsNames = {"disableAutoMacros"};
int[] rgDispId = {0};
Guid blank = Guid.Empty;
int lcid = System.Globalization.CultureInfo.CurrentCulture.LCID;
int result = wb.GetIDsOfNames(ref blank, rgsNames, 1, lcid ,out rgDispId);
rgDispId Array is set to null doing this. Am I now on the right track? Or have I still not got it?
Thanks
|
|
|
|
|
You're on the right track. Just familiarize yourself with how dispatch interfaces work and you should be able to do what you need to.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Bugger still stuck
Word.Application MSWord = new Word.ApplicationClass();
IDispatch wb = (IDispatch)MSWord.WordBasic;
int lcid = System.Globalization.CultureInfo.CurrentCulture.LCID;
string[] rgsNames = {"DisableAutoMacros"};
int[] rgDispId = {};
Guid nullGUID = Guid.Empty;
int result = wb.GetIDsOfNames(ref nullGUID, rgsNames, 2, lcid, out rgDispId);
This code returns a result of -1073741819. There is little info on this error code. I have tried this with the Word.Application object MSWord with methods I know are there and I still get the same error code. Also the rgDispId is always set to null.
It seems I'm still missing a key point of understanding here.
|
|
|
|
|
Actually, try removing the out keyword from the last parameter declaration of GetIDsOfNames since an int[] array is already a reference type. The caller (you) must also allocate the array, so try int[] rgDispId = new int[1]; instead of creating an empty array.
This is definitely the right track, though I've never tried using the dispatch interface in managed code like this.
Another way would be to call IDispatch.GetTypeInfo and use the UCOMITypeInfo interface (which is fortunately defined in the FCL so you don't have to declare it) and use it's member methods to basically do the same thing.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Still get the same error. rgDispId isn't set to null anymore but contains 0, or what ever value I put in it to start with. It must be failing in the GetIDsOfNames method before it gets to assign anything.
Does this have anything to do with OleInitialize and CoCreateInstance . I thought Word.Application MSWord = new Word.ApplicationClass(); called these behind the scenes.
Also
IDispatch wb = (IDispatch)MSWord.WordBasic;
int lcid = System.Globalization.CultureInfo.CurrentCulture.LCID
UCOMITypeInfo tpInf = (UCOMITypeInfo)wb.GetTypeInfo(0, lcid);
Throws the exception No such interface supported .
However
IDispatch ms = (IDispatch)MSWord;
int lcid = System.Globalization.CultureInfo.CurrentCulture.LCID
UCOMITypeInfo tpInf = (UCOMITypeInfo)ms.GetTypeInfo(0, lcid);
doesn't. Can I get at it this way?
|
|
|
|
|
ComInitialize is called behind the scenes by the CLR, and you already have an instance of the WordBasic object so long as it isn't null. The fact that you're getting the IDispatch reference when you cast - for which the CLR performs a QueryInterface - shows that it supports automation, so I'm surprised that GetTypeInfo fails.
At this point, I would recommend going to the Word newsgroup (NNTP news server is msnews.microsoft.com) and seeing if there is another way to disable macros on startup.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Will do. I have a feeling it isn't possible mind
Thanks for all the help, I've learned a great deal this last few days.
|
|
|
|
|
Got it working!!
Needed a few changes to the interface thats all.
[Guid("00020400-0000-0000-c000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDispatch
{
[PreserveSig] int GetTypeInfoCount();
UCOMITypeInfo GetTypeInfo(
[MarshalAs(UnmanagedType.U4)] int iTInfo,
[MarshalAs(UnmanagedType.U4)] int lcid);
[PreserveSig] int GetIDsOfNames(
ref Guid riid,
[MarshalAs(UnmanagedType.LPArray,
ArraySubType=UnmanagedType.LPWStr)]
string[] rgsNames,
int cNames,
int lcid,
[MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);
[PreserveSig] int Invoke(
int dispIdMember,
ref Guid riid,
[MarshalAs(UnmanagedType.U4)] int lcid,
[MarshalAs(UnmanagedType.U4)] int dwFlags,
ref DISPPARAMS pDispParams,
[MarshalAs(UnmanagedType.LPArray)][Out] object[] pVarResult,
ref EXCEPINFO pExcepInfo,
[MarshalAs(UnmanagedType.LPArray)][Out] IntPtr[] pArgErr);
}
Thanks again.
|
|
|
|
|
Glad you got it working, but I find this interesting since the declaration I gave you was pulled out of the .NET FCL assemblies (written by Microsoft). Oh well, whatever works, right?
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Hi,
I need to get a list of computers which are currently logged on a local area network. I can get the server ip by using DNS (API). However, I can not figure out how to get the list of computer . Please help me to figure out this problem.
Thanks,
Nemo
|
|
|
|
|
This has been covered many times in the past. Please click on "Search comments" directly above this message board and search for previous discussions.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
:(I have tried to search for the similar articles but i can not find any...
Nemo
|
|
|
|
|
|
I need to work out week numbers for a given date starting from 1 jan as week 1, so when a user inouts a date i need to work out what week number we are in please
|
|
|
|
|
See the documentation for DateTime structure. It's properties and methods can give you all the infos you need, e.g. DayOfWeek or DayOfYear properties. The rest some simple mathematics you can surely figure out yourself
|
|
|
|
|
yes i was aware of that, your right i was being lazy i was hoping someone may have a formula alreadt sorted cant life be that simple?
|
|
|
|
|
Sometimes it is, but obviously not today
|
|
|
|
|
robmays wrote:
I was hoping someone may have a formula already sorted
What you mean: DayOfYear / 7
robmays wrote:
I was being lazy
It sure looks like it from here.
robmays wrote:
can't life be that simple?
"Life is tough, but if you're tough on yourself, then life is so much easier on YOU!" -- Zig Ziglar
"You can have everything in life you want if you will just help enough other people get what they want." --Zig Ziglar
Coming soon: The Second EuroCPian Event[^].
|
|
|
|
|
no not that one bit mor complicated here is one for someone if needed
// Static Method to return WeekNumber (1-53) for a given year
public static int WeekNumber(DateTime dt) {
// Set Year
int yyyy=dt.Year;
// Set Month
int mm=dt.Month;
// Set Day
int dd=dt.Day;
// Declare other required variables
int DayOfYearNumber;
int Jan1WeekDay;
int WeekNumber=0, WeekDay;
int i,j,k,l,m,n;
int[] Mnth = new int[12] {0,31,59,90,120,151,181,212,243,273,304,334};
int YearNumber;
// Set DayofYear Number for yyyy mm dd
DayOfYearNumber = dd + Mnth[mm-1];
// Increase of Dayof Year Number by 1, if year is leapyear and month is february
if ((IsLeapYear(yyyy) == true) && (mm == 2))
DayOfYearNumber += 1;
// Find the Jan1WeekDay for year
i = (yyyy - 1) % 100;
j = (yyyy - 1) - i;
k = i + i/4;
Jan1WeekDay = 1 + (((((j / 100) % 4) * 5) + k) % 7);
// Calcuate the WeekDay for the given date
l= DayOfYearNumber + (Jan1WeekDay - 1);
WeekDay = 1 + ((l - 1) % 7);
// Find if the date falls in YearNumber set WeekNumber to 52 or 53
if ((DayOfYearNumber <= (8 - Jan1WeekDay)) && (Jan1WeekDay > 4))
{
YearNumber = yyyy - 1;
if ((Jan1WeekDay == 5) || ((Jan1WeekDay == 6) && (Jan1WeekDay > 4)))
WeekNumber = 53;
else
WeekNumber = 52;
}
else
YearNumber = yyyy;
// Set WeekNumber to 1 to 53 if date falls in YearNumber
if (YearNumber == yyyy)
{
if (IsLeapYear(yyyy)==true)
m = 366;
else
m = 365;
if ((m - DayOfYearNumber) < (4-WeekDay))
{
YearNumber = yyyy + 1;
WeekNumber = 1;
}
}
if (YearNumber==yyyy) {
n=DayOfYearNumber + (7 - WeekDay) + (Jan1WeekDay -1);
WeekNumber = n / 7;
if (Jan1WeekDay > 4)
WeekNumber -= 1;
}
return (WeekNumber);
}
|
|
|
|
|
Nice work, but why don't you use properties of the structure DateTime? Some of them i even mentioned in my first comment. I think this could at least spare you some lines of code and therefor increase readibility.
For example you wrote:
DayOfYearNumber = dd + Mnth[mm-1];<br />
<br />
l= DayOfYearNumber + (Jan1WeekDay - 1);<br />
WeekDay = 1 + ((l - 1) % 7);
Alternativ:
DayOfYearNumber = dt.DayOfYear;<br />
<br />
l = dt.DayOfWeek;
|
|
|
|
|
robmays wrote:
// Set DayofYear Number for yyyy mm dd
DayOfYearNumber = dd + Mnth[mm-1];
// Increase of Dayof Year Number by 1, if year is leapyear and month is february
if ((IsLeapYear(yyyy) == true) && (mm == 2))
DayOfYearNumber += 1;
The result of this calculation will be wrong for any date from the 1st February onwards on a leap year. You will increase the DayOfYearNumber on a leap year if the month is February (before the leap day occurs), but not for the remainder of the months in the year (after the leap day).
try:
if ((IsLeapYear(yyyy)) && (mm > 2))
DayOfYearNumber++;
"You can have everything in life you want if you will just help enough other people get what they want." --Zig Ziglar
Coming soon: The Second EuroCPian Event[^].
|
|
|
|
|
Why don't you use System.Globalization.GregorianCalendar object which has GetWeekOfYear method : -
public static int WeekNumber(DateTime dt)
{
System.Globalization.GregorianCalendar gCal=new System.Globalization.GregorianCalendar();
return gCal.GetWeekOfYear(dt,System.Globalization.CalendarWeekRule.FirstDay,System.DayOfWeek.Monday);
}
Cheers
Never comment ur code. If it was hard to write, it should be hard to understand !!!
|
|
|
|
|