I tried to port my own version. Very humbling... :)
This is the C# class I used:
public class CallMsi
{
[DllImport("msi")]
public static extern int MsiOpenDatabase (string dbpath, string persist, ref IntPtr msihandle);
[DllImport("msi")]
public static extern int MsiDatabaseOpenView(IntPtr handle, string query, ref IntPtr viewhandle);
[DllImport("msi")]
public static extern int MsiViewExecute (IntPtr viewhandle, IntPtr recordhandle);
[DllImport("msi")]
public static extern int MsiViewFetch (IntPtr viewhandle, ref IntPtr recordhandle);
[DllImport("msi", CharSet=CharSet.Auto)]
public static extern int MsiRecordGetString (IntPtr recordhandle, int recno,
string szbuff,
ref int len);
[DllImport("msi")]
public static extern int MsiCloseHandle (IntPtr handle);
[DllImport("msi")]
public static extern int MsiViewClose (IntPtr viewhandle);
}
and this is class I'm working with to perform queries on a database, no error coding.
public class GetMsiData : IDisposable
{
string thepath = null;
IntPtr dbhandle = IntPtr.Zero;
public GetMsiData (string package)
{
thepath = package;
int nres = CallMsi.MsiOpenDatabase (thepath, null, ref dbhandle);
}
~GetMsiData ()
{
InternalDispose (false);
}
public string DoQuery(string query)
{
IntPtr viewhandle = IntPtr.Zero;
IntPtr nothing = IntPtr.Zero;
int nres = CallMsi.MsiDatabaseOpenView (dbhandle, query, ref viewhandle);
nres = CallMsi.MsiViewExecute (viewhandle, nothing);
IntPtr rechandle = IntPtr.Zero;
nres = CallMsi.MsiViewFetch (viewhandle, ref rechandle);
if (0!=nres) // No data
return null;
string outbuff = new String (' ', 255);
int outlen = 255;
nres = CallMsi.MsiRecordGetString (rechandle, 1, outbuff, ref outlen);
nres = CallMsi.MsiViewClose (viewhandle);
if (0!=nres) // No data
return null;
return outbuff.Substring(0, outlen); // trim to actual length
}
public void InternalDispose(bool disposing)
{
CallMsi.MsiCloseHandle (dbhandle);
dbhandle = IntPtr.Zero;
}
public void Dispose()
{
InternalDispose (true);
GC.SuppressFinalize(this);
}
}
"Rick Foster" <_Rick....@Autodesk.com> wrote in message news:u8UGLieSCHA.2792@tkmsftngp09...
Looks like we'll have to roll our own for a while!
Rick
"Phil Wilson" <phil....@unisys.spamcom> wrote in message
news:#gWmxmgSCHA.1976@tkmsftngp11...
can any one help ?
sith
"Rick Foster" <_Rick....@Autodesk.com> wrote in message
news:u8UGLieSCHA.2792@tkmsftngp09...
"sith" <ako...@poczta.wp.pl> wrote in message
news:#MvBOBnTCHA.3924@tkmsftngp12...
"Andreas Magnusson" <andreas_c...@hotmail.com> wrote in message
news:uSBICeoTCHA.2780@tkmsftngp09...
"sith" <ako...@poczta.wp.pl> wrote in message news:euCnwNpTCHA.3588@tkmsftngp08...
The issue I raised was not how to use msi or how to use msi api but _how to
use msi automation interface from c#_. Loading library and calling its
functions is a trivial task even for a begginer. Is was com automation that
i wanted to use from c# (actually i am porting some stuff from c++)
GetTypeFromProgID doesn't work as it needs a CoClass which is not defined in
msi.dll; as a consequence you can not call Activator.CreateInstance.
I finally figured out how it's done. I needed to create a wrapper class for
WindowsInstaller.Installer interface and from then on it was as simple as it
was from c++.
"Phil Wilson" <phil....@unisys.spamcom> wrote in message
news:uuBuMp5TCHA.3740@tkmsftngp08...
Type comType=Type.GetTypeFromProgID(ProgID);
object comObject=Activator.CreateInstance(comType);
then:
comType.InvokeMember (string methodname, bindingflags etc..........)
so I assume you're doing something similar with the Windows Installer ProgID.
It's not that I'm a hardcore Win32 programmer, but I do prefer type safety, and you don't get it
with late-binding automation interfaces. You make a parameter mistake or spell a method name wrong
you find out at run time, not compile time.
COM might be everywhere, but it's pretty much finished as a tool for new development as you can see
from .Net.
"sith" <ako...@poczta.wp.pl> wrote in message news:eLsQOCAUCHA.3964@tkmsftngp12...
I have tried the approach you show below, with no effect whatsoever.
The problem was that msi.dll defined interfaces only. There was no coclass
from which you could create an object.
WindowsInstaller.Installer progID ( which i passed to
Type.GetTypeFromProgID ) was in fact an Installer interface ID so executin
the sequence below resulted in an error message stating that you could not
create an instance of an interface directly. The reason for this is probably
that Type returne by GetTypeFromProgID was an interface type.
After having writen a wrapper class which was pretty much as that:
[ComImport, Guid("000c1090-0000-0000-c000-000000000046")]
class WindowsInstallerClass
{
}
the usage was even more simpler
WindowsInstaller.Installer msi = null;
msi = new WindowsInstallerClass() as WindowsInstaller.Installer;
WindowsInstaller.Database db =
OpenDatabase"PATH_TO_DB",WindowsInstaller.MsiOpenDatabaseMode.msiOpenDatabas
eModeReadOnly);
You made the point, though, .net is not com oriented; does that make ME a
hard-core COM progremmer ? ;-)
cheers,
sith
"Phil Wilson" <phil....@unisys.spamcom> wrote in message
news:#xmXudEUCHA.3072@tkmsftngp13...