liorafar
Level 6

How Do you get the full path name of file in dynamic file library?

Hi All!
Please help!!
When I install i want to get the full path of the destination files that are about to be installed in a C# custom Action(using Microsoft.Deployment.WindowsInstaller dll)
these files are in dynamic file linking.
I could only get the their specific names while doing the query ("SELECT FileName FROM File") on the session database.
Im new to Installshield And Im new to my company.
I want to prove myself usfull so please help me
Thanks!
Lior.
Labels (1)
0 Kudos
10 Replies
Christopher_Pai
Level 16

As a starting point, consider querying the File table for the File ID's and then loop through that calling session format with

[#FILEKEY]

This will only work after file costing of course.

That should give you the paths. If it's safe to assume all files will be installed that might be enough.

WiX DTF also has another assembly that has an InstallPackage class. I've never tried this in a custom action but you might be able to use Session.Database and cast is as an InstallPackage and reference the InstallFiles property. I don't know that you'll like the way it refers to the paths though.
0 Kudos
liorafar
Level 6

Hi Christopher,
First of all I want to thank for your fast answer! , However It still doesn't work for me. I will try to explain exactly what I've done.
First, I want to mention that I'm not familiar with session.Format therefore I didn't really understand what you've meant by '[#FILEKEY]' so I've tried different ways.
In my MSI I install 5 files(1 is static file and 4 are dynamic file linking)
Moreover as presented below is my custom action C# code:

[CustomAction]
public static ActionResult CustomAction1(Session session)
{
Log.LogMessageToFile("Begin CustomAction1");
// getting database and retrieving File(File ID) column from File table
Database database = session.Database;
View view = database.OpenView("SELECT File FROM File");
view.Execute();
// loop on every record in view
IEnumerator recordEnum = view.GetEnumerator();
while (recordEnum.MoveNext())
{
Record record = recordEnum.Current;
string keyValue = record.GetString(1);
// writing the original key value to log
Log.LogMessageToFile("File key before formating = " + keyValue);
// trying to format with FormatRecorde
string formattedValueWithFormatRecordMethod = session.FormatRecord(record, "[#File]");
Log.LogMessageToFile("File key after record format = " + formattedValueWithFormatRecordMethod);

// trying to format the values strictly
string formattedValueWithFormatMethod = session.Format(keyValue);
Log.LogMessageToFile("File key after format = " + formattedValueWithFormatMethod);
}

return ActionResult.Success;
}

I tried using the session format with two different methods:
1. session.FormatRecord
2. session.Format

However as you can see in the following Log, you can see that in run time(while installing) the view gives me back the static file key as its file name and as for the dynamic file linking files their keys is something like GUID or registry values.
when I write to the log the format on each one of these keys it returns me the same value or empty string(in both cases)
Therefore I didn't succeed to get the file paths as you've mentioned.
Also I cant understand how it connects to their paths since its only their keys(of course because of lack of my InstallShield experience)

I will be really greatfull if you can tell me what I'm doing wrong and if you can explain a little of what does this function actually does(and sure if you have link that gives information and examples for these method and DTF at all I will be greatfull)
THE LOG:
17/02/2011 14:38:14: Begin CustomAction1.
17/02/2011 14:38:14: File key before formating = _7300413E133141B0BD59192ED381EA64.
17/02/2011 14:38:14: File key after record format = .
17/02/2011 14:38:14: File key after format = _7300413E133141B0BD59192ED381EA64.
17/02/2011 14:38:14: File key before formating = staticfile.txt.
17/02/2011 14:38:14: File key after record format = .
17/02/2011 14:38:14: File key after format = staticfile.txt.
17/02/2011 14:38:14: File key before formating = _352A5A268A49D97DAAC04053495F2E25.
17/02/2011 14:38:14: File key after record format = .
17/02/2011 14:38:14: File key after format = _352A5A268A49D97DAAC04053495F2E25.
17/02/2011 14:38:14: File key before formating = _2DEC5EFAAF2F31B3E0DE1DB84F6B3304.
17/02/2011 14:38:14: File key after record format = .
17/02/2011 14:38:14: File key after format = _2DEC5EFAAF2F31B3E0DE1DB84F6B3304.
17/02/2011 14:38:14: File key before formating = _C3BAFAFC98E4927E023F83BCBD2FF9B0.
17/02/2011 14:38:14: File key after record format = .
17/02/2011 14:38:14: File key after format = _C3BAFAFC98E4927E023F83BCBD2FF9B0.


As for the InstallPackage I didnt understand how to connect it to the installed session since its constructor wants the package path and not session.

I want to add that my MSI is Compressed(and it has to be this way) if its connected somehow.

Again, Thank you very much,
Lior.
0 Kudos
RobertDickau
Flexera Alumni

As a stab in the dark---dim, anyway---perhaps this line:

session.FormatRecord(record, "[#File]");


wants the actual key (from keyValue) in place of "File" in the [#File] expression?
0 Kudos
liorafar
Level 6

Well I thought about that too and i have already tried it before. However still the same. What do you think? Is anyone familiar with it? Thanks! 
0 Kudos
RobertDickau
Flexera Alumni

Hmm, the general thing seemed to work for me; a hasty VBScript action after CostFinalize seems to work:

[code]Set viewfile = Database.OpenView("SELECT `File` FROM `File`")
viewfile.Execute

Set recfile = viewfile.Fetch

While Not (recfile Is Nothing)
Set formatrec = Installer.CreateRecord(1)

formatrec.StringData(0) = "[#" & recfile.StringData(1) & "]"

str = recfile.StringData(1) & ": " & Session.FormatRecord(formatrec)

MsgBox str

Set recfile = viewfile.Fetch
Wend

viewfile.Close[/code]
0 Kudos
liorafar
Level 6

Wow!!! Worked like charm!
Moreover the custom action must come after CostFinalize as an immediate custom action
Thank you very much RobertDickau! Thank you very much Christopher!
It really gave me the full path of the installed files in run time(include the dynamic file linking files)
Where can I get more information on string formats??
Does it suppose to work on others keys in other tables?(since I tried on Component in Component table and it returned me empty strings)
Where else can I retrieve information(and code samples) on the classes and methods of DTF and what they exactly they do(As you can see I didn't know this Format method of session and it doesn't have explanation on it in the object browser of Visual studio...)

Please for getting me and others an efficient Installer Developers,please answer those important questions.

I really appreciate your help!
Lior.

P.S:
For the C# programmers of us here is the equivalent code:

[CODE]
[CustomAction]
public static ActionResult CustomAction1(Session session)
{
Log.LogMessageToFile("Begin CustomAction1");
// getting database and retrieving File(File ID) column from File table
Database database = session.Database;
View view = database.OpenView("SELECT File FROM File");
view.Execute();
// loop on every record in view(in File column view)
Record recordFile = view.Fetch();
while (recordFile != null)
{
//set the record format string with its file key value
recordFile.FormatString = "[#" + recordFile.GetString(1) + "]";
// write to log the file key and its value(in this matter its the installed file full path)
string filePath = recordFile.GetString(1) + " = " + session.FormatRecord(recordFile);
Log.LogMessageToFile(filePath);
recordFile = view.Fetch();
}

return ActionResult.Success;
}
[/CODE]
0 Kudos
liorafar
Level 6

I forgot to add that the Log in the code sample below is a class that I built and not the session Log. Therefore if you use this code , please remember to replace the Log.LogMessageToFile method.
0 Kudos
RobertDickau
Flexera Alumni

Glad it's working! The help topics "Session.FormatRecord Method" and "Formatted" describe the different [%$#\Zzz] formats you can use. These formats generally apply to MSI database table fields that use the Formatted data type (the Shortcut table's Arguments field does, its Description field doesn't, for example).
0 Kudos
Christopher_Pai
Level 16

Make sure you get in the habit of "Using" those classes. Remember that Databases, Views and Records all have unmanaged handles and you want to leverage the built-in IDisposable interface to free them up.

MSI can get really wonky if you don't close your handles.

using( var view = session.database.OpenView("SELECT File FROM File"))
{
// Do Stuff Here
} // view goes out of scope and invokes view.Dispose() which calls MsiCloseHandle( hView ) automatically. Later the garbage collector will free up view at it's leisure
0 Kudos
liorafar
Level 6

Thanks for the extra knowledge!
Its so important to keep in mind memory and efficiancy while programming.
every note like that makes me feel great since it is actual added value!
0 Kudos