|
Hi!
I'm currently having a little trouble with calling the Windows XP photo printing wizard. I found this VB.NET code on the web, but when I port it to C# it tells me that vector has no add method
'create the vector COM object
Dim vector As Object = CreateObject("WIA.Vector")
' add files to the vector object
For Each file As String In files
vector.Add(file)
Next
' create the common dialog COM object, and
' display the photo print wizard
Dim dialog As Object = CreateObject("WIA.CommonDialog")
dialog.ShowPhotoPrintingWizard(vector)
vector = Nothing
dialog = Nothing
|
|
|
|
|
The .Add() method of the WIA.Vector object takes 2 parameters, a Variant and an optional Index. C# doesn't support optional parameters, so you'll have to include one in your call to .Add() . The default value for Index, according to the documentation for WIA.Vector, is 0, so:
vector.Add(file, 0);
should work.
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
The problem ist that the compiler doesn't even treat the vector object correctly - it tells me that it doesn't contain a definition for the method add() (the same goes for dlg and method ShowPhotoPrintingWizard())
Here's my code:
// create the vector COM object
Type vProgID = Type.GetType("WIA.Vector");
object vector = Activator.CreateInstance(vProgID);
// add the paths of our photos to the vector
foreach(Photo.Photo p in _Photos)
vector.Add(p.Path, 0);
// create and display the COM printing dialog
Type dlgProgID = Type.GetType("WIA.CommonDialog");
object dlg = Activator.CreateInstance(dlgProgID);
dlg.ShowPhotoPrintingWizard(vector);
|
|
|
|
|
How about scrapping the Activator code and just adding a Reference to the Micrsoft Windows Image Acquisition Libary 2.0 and changing the code:
WIA.Vector vector = new WIA.VectorClass();
foreach(Photo.Photo p in _Photos)
vector.Add(p.Path, 0);
WIA.CommonDialog dlg = new WIA.CommonDialogClass();
dlg.ShowPhotoPrintingWizard(vector);
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
vector in your code is actually an object . In order to call the Add method you must do so with vector cast to the correct type. Inheritence rules do not mean that you can call a method on an object that does not actually define that method, and System.Object (or simply object in C#) does not define an Add method so the compiler is correct.
Dave's suggestion will work, but you can also use reflection to get the MethodInfo for the Add method and invoke it:
Type vectorType = Type.GetType("WIA.Vector, Interop.WIA");
object vector = Activator.CreateInstance(vectorType);
MethodInfo addMethod = vectorType.GetMethod("Add");
if (addMethod != null)
addMethod.Invoke(vector, new object[] {p.Path, 0});
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
It still is not working. For some reason the addMethod is always null.
|
|
|
|
|
You should actually use the following snippet, but please read the documentation[^] for Type.GetMethod to better understand why:
MethodInfo addMethod = vectorType.GetMethod("Add", new Type[] {p.Path.GetType(), typeof(int)}); I'm making an assumption that the second parameter in your example is an int (System.Int32 ). Replace appropriate if I'm mistaken.
See Type.GetMethod(String, Type[])[^] specifically for the documentation for the method used above.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
I forgot to add that I have to retrieve the type with Type vectorType = Type.GetTypeFromProgID("WIA.Vector");, simply Type.GetType will again return a null object.
|
|
|
|
|
You have to specify the assembly as I did in my example. A type is defined by it's namespace and class, the assembly it's defined in, the culture (only relevent for satellite assemblies), and the public key (if signed, and you should really sign your assemblies).
You don't want to use Type.GetTypeFromProgID , which gets a type from a COM server. Please see my example again, where I use "WIA.Vector, Interop.WIA". Replace "Interop.WIA" with the assembly file name (minus the ".dll") that you generated.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
The problem is that the dll I have to reference was not created by myself (in fact it is C:\Windows\System32\wiaaut.dll), actually it is not even a .NET assembly. Since I'm a newbie to .NET and COM interop I have a few problems with referencing wiaaut.dll. Could you please explain me how I obtain a reference to it?
|
|
|
|
|
In the Solution Explorer on the right wide of the IDE, you'll find a folder in your project called, oddly enough, References. Right-click it and pick Add a reference. A dialog comes up with three tabs acrossed the top, click on COM. Scroll down the list until you find "Microsoft Windows Image Acquisition Library 2.0" (assuming WinXP) and double-click it, then click OK.
Now, you'll still run into a problem with pasing the parameters into the methods because the Add method doesn't take a string type, but a COM Variant type, or Object. I'd follow Heath's advice and read up on his documentation links. Heath is the best guy in the Forums (IMHO), particullary when it comes to COM Interop.
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
I do know that way , but what I was thinking of was creating a reference at runtime, since I want my application to be able to work on systems older than XP as well. Since e.g. Win98 doesn't have WIA support the startup of the entire program would fail, if I add a reference at runtime, only the printing will fail.
|
|
|
|
|
You are creating a reference to the COM server at runtime, but the interop assembly you produce is just that: it allows the CLR to marshal calls to a COM server. Even when you work with the Visual Studio Tools for Office (VSTO; a set of interop assemblies to program against Office) or create Office PIAs (primary interop assemblies) you are creating the same type of assembly. This is necessary, or you have to write your own interop interfaces and classes.
Read Exposing COM Components to the .NET Framework[^] for more information.
Do keep in mind that the interop assembly is just a proxy. It does not contain the implementation, but only the information required to marshal calls from the CLR to the COM server and back.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
That's exactly what I was looking for! I now created an interop assembly with the command line tool tlbimp.exe, which serves just my purpose.
A big thank you to both of you!
|
|
|
|
|
Just FYI - the Visual Studio .NET's Add Reference's COM tab does the same thing as tlbimp.exe.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
I ran a test (below) and typeof is many orders of magnitude faster than Type.GetType. I guess it's because of the searching that needs to be done.
My question is why does Microsoft show in all their examples of creating a datatable to use Type.GetType instead of typeof as the columns data type parameter?
[I.E. table.Columns.Add("name",Type.GetType("System.String")) instead of table.Columns.Add("name",typeof(System.String)) ]
I'm working on a project right now where I need to convert a hiearchical business object into a flat datatable for reporting purposes. There are a large number of columns to generate in code for many different objects so I'd prefer to go with what is fastest.
I'm fairly certain that typeof and Type.GetType are functionally identical in this case but I'm wondering why MS goes with the slower option in their samples?
Or is my testing wrong?
(Test for checking performance of typeof versus Type.GetType(""))
private void button1_Click(object sender, System.EventArgs e)<br />
{<br />
Cursor.Current=Cursors.WaitCursor;<br />
<br />
System.DateTime dtThen=DateTime.Now;<br />
Type t;<br />
<br />
<br />
for(int InfamousI=0;InfamousI<500000;InfamousI++)<br />
{<br />
<br />
t=typeof(System.String);<br />
t=typeof(System.DateTime);<br />
t=typeof(System.Int32);<br />
t=typeof(System.String);<br />
t=typeof(System.DateTime);<br />
t=typeof(System.Int32);<br />
t=typeof(System.String);<br />
t=typeof(System.DateTime);<br />
t=typeof(System.Int32);<br />
t=typeof(System.String);<br />
t=typeof(System.DateTime);<br />
t=typeof(System.Int32);<br />
<br />
<br />
<br />
}<br />
MessageBox.Show("Elapsed: " + (System.DateTime.Now-dtThen).ToString());<br />
}
|
|
|
|
|
John,
Microsoft and other ISVs use the CodeDom to output text so that any language that provides a CodeDom provider (like C# and VB.NET) can create source code for a particular component. The component uses the CodeDom to generically create source code using the CodeDom provider.
Why Microsoft does not use the CodeTypeOfExpression class I cannot say for certain (I'm not on that team, though I'm in the same division) but I suspect it is because not all language may support a typeof expression. I can try to find out and let you know.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
I guess I should just take the examples with a grain of salt like I used to in my c++ days.
After many many many years of programming in C++ I was able to interpret the microsoft samples but do it the most efficient way myself. With c# I only have a couple of years under my belt and so I'm prone to deferring to the examples more.
I guess the danger of the samples is that they can perpetuate something out to the general public to the point where it's not questioned. When I looked up this earlier, I found hundreds of non-ms websites and newsgroup postings referring to this process and they all used the MS Type.GetType variant in their c# examples.
I know it's probably trivial, but someone at MS should go through all those samples as time permits and consider if they are setting a good example. Newbies like me are quite dependant on them and they seem to flow out to other developer sites as well. There is still a place I believe for efficiency and good old optimization.
|
|
|
|
|
I would recommend that you pay too much attention to samples. Study the documentation and if you really want to be elite use ildasm.exe (or .NET Reflector, but then you use geek points if you don't use the IL view ) to view the implementation. If you're having problems understanding the documentation (hey...it happens!) the samples can sometimes help.
I actually have been reporting several problems in samples (like GetProcAddress(TEXT("SomeFunction")); , since GetProcAddress only accepts LPCSTR , which is ANSI and the TEXT macro causes strings to be treated as Unicode when _UNICODE is defined) and I recommend you do the same. Most topics have a link at the bottom to send feedback. All of the .NET Framework SDK topics should.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
I can't say why their examples use Type.GetType but I could have guessed that typeof is simply faster than Type.GetType .
Check this out...
System.Type t = typeof(System.String);
Seems to generate this il:
<br />
ldtoken [mscorlib]System.String<br />
call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)<br />
While...
<br />
System.Type t = System.Type.GetType("System.String");<br />
Seems to generate this il:
<br />
ldstr "System.String"<br />
call class [mscorlib]System.Type [mscorlib]System.Type::GetType(string)<br />
Without going farther, I suspect that GetTypeFromHandle is way more speedy than the generic GetType . One has the handle reference readily available for inspection while the other has to go looking for it.
|
|
|
|
|
The latter also has a change of breaking at runtime if the Type is not defined in the current assembly. The former (typeof ) is checked at compile time and you can be sure that the type will be found (so long as the entire assembly isn't missing or the version redirected to where the Type isn't defined) at run-time.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Heath Stewart wrote:
latter also has a change of breaking at runtime if the Type is not defined in the current assembly.
Good point! Even more reason to use typeof. It would be pretty easy to mistype the class name with Type.GetType() and not catch it.
|
|
|
|
|
Thats about right .... with type of the type is kindda known .. .where as in the other one it is looked up from a string literal .....
- The Outlander -
|
|
|
|
|
Hi ~
I am generateing a Word Document in C# and need to put page numbers and information in the footer.
However, when I add information to the Range.Text the page numbers do not display correctly.
This is what I get -
Page 1 of 1 ( Same on all the pages )
*******************
* Somthing here *
*******************
This is what I need -
Page 1 of 47
*******************
* Something Here *
*******************
This is the code I have -
_WordDoc.Sections.First.Footer.Item(Word.WdHenderFooterIndex.wdHeaderFooterPrimary).Range.Text = "Page X of Y";
_WordDoc.Sections.First.Footer.Item(Word.WdHenderFooterIndex.wdHeaderFooterPrimary).Range.InsertAutoText();
_WordDoc.Sections.First.Footer.Item(Word.WdHenderFooterIndex.wdHeaderFooterPrimary).Range.Text += "\n" + String1 + String2 + String3;
Michele
Mercer Engineering Research Center
mstusak@merc.mercer.edu
|
|
|
|
|
When doesn't it display correctly? When you open the document in Word or when you print it? In the latter case, make sure to set Options.UpdateFieldsAtPrint to true .
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|