This website uses cookies. By clicking Accept, you consent to the use of cookies. Click Here to learn more about how we use cookies.
Turn on suggestions
Auto-suggest helps you quickly narrow down your search results by suggesting possible matches as you type.
- Revenera Community
- :
- InstallShield
- :
- InstallShield Forum
- :
- Custom Action problem -
Subscribe
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Subscribe
- Mute
- Printer Friendly Page
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 14, 2008
07:16 AM
Custom Action problem -
I have the unfortunate duty of trying to update a small desktop application for Windows Vista compatibility. I need to utilize the "All Users\Documents" folder so my application can read and write files for all the users of a machine. Since the CSIDL_COMMON_DOCUMENTS folder is not one of the predefined folders in the Files view in InstallShield, I am trying to write a Custom Action to set my folder to the correct path.
Here is what I have done.
I created a folder in the Files view (Destination Computer's Folders pane) called CommonDocsAll, underneath it, I have a folder named "AppName". I placed all the files that should be in that folder there (Destination Computer's Files pane). Then I went to the Custom Actions view and created a custom action under "After Initialization (before first dialog)". I named the custom action "FindCommonDocsFolder".
Here are it's properties:
Source Location: Browse File System
File Name:\FindSpecialFolder.vbs
Function Name: GetFolderPath
Wait for Action: Yes
Ignore Exit Code: Yes
Comments:
Condition: No Conditions
Here is the code in the FindSpecialFolder.vbs file:
I don't get any errors from this code but, the path to the folder is not changed. On my Vista test machine, the "AppName" folder is installed like this C:\CommonDocsAll\AppName.
I wanted the files to be installed like this C:\Users\Public\Documents\AppName
What am I doing wrong? How can I set that folder to the correct path?
How can I point the installation to the "CommonDocsAll" path I have set?
Thanks, in advance, for any help you can give.
Here is what I have done.
I created a folder in the Files view (Destination Computer's Folders pane) called CommonDocsAll, underneath it, I have a folder named "AppName". I placed all the files that should be in that folder there (Destination Computer's Files pane). Then I went to the Custom Actions view and created a custom action under "After Initialization (before first dialog)". I named the custom action "FindCommonDocsFolder".
Here are it's properties:
Source Location: Browse File System
File Name:
Function Name: GetFolderPath
Wait for Action: Yes
Ignore Exit Code: Yes
Comments:
Condition: No Conditions
Here is the code in the FindSpecialFolder.vbs file:
Option Explicit
Private Const CSIDL_COMMON_DOCUMENTS = &H2E
Private Const SHGFP_TYPE_CURRENT = &H0
Private Const SHGFP_TYPE_DEFAULT = &H1
Private Const MAX_LENGTH = 260
Private Const S_OK = 0
Private Const S_FALSE = 1
Private Declare Function SHGetFolderPath Lib "shfolder.dll" _
Alias "SHGetFolderPathA" _
(ByVal hwndOwner As Long, _
ByVal nFolder As Long, _
ByVal hToken As Long, _
ByVal dwReserved As Long, _
ByVal lpszPath As String) As Long
Private Function GetFolderPath()
Dim buff As String
buff = Space$(MAX_LENGTH)
If SHGetFolderPath(0, CSIDL_COMMON_DOCUMENTS, 0, SHGFP_TYPE_CURRENT, buff) = S_OK Then
MsiSetTargetPath(hMSI, "CommonDocsAll", TrimNull(buff))
GetFolderPath = S_OK
Else
GetFolderPath = S_FALSE
End If
End Function
Private Function TrimNull(startstr As String) As String
TrimNull = Left$(startstr, InStr(startstr, Chr(0)) - 1)
End Function
I don't get any errors from this code but, the path to the folder is not changed. On my Vista test machine, the "AppName" folder is installed like this C:\CommonDocsAll\AppName.
I wanted the files to be installed like this C:\Users\Public\Documents\AppName
What am I doing wrong? How can I set that folder to the correct path?
How can I point the installation to the "CommonDocsAll" path I have set?
Thanks, in advance, for any help you can give.
(13) Replies
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 16, 2008
02:38 PM
In the 2nd parameter of the MsiSetTargetPath API, you need to specify the folder identifier which is a primary key in the Directory table. It would probably be COMMONDOCSALL in your case. To verify it, you need to check the Location: property on the Properties dialog that can be launched from the Properties right-click menu on the folder.
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 16, 2008
04:10 PM
Thanks very much for responding.
I am not sure I understand what you are saying.
The folder identifier I should specify should be the key value in the Directory Table? That is the directory table in the installer, right?
If I right-click on the CommonDocsAll folder that I defined in the Files view ("Destination computer's folders" pane), then I do see "Location: [COMMONDOCSALL]".
Also, to update:
I changed the way I am implementing this...I created a .dll and I now point my Custom Action to the dll. I am using Function Signature = New. here is the code from the dll: (FindPublicDocsFolder.dll)
Public Function GetFolderPath(ByVal hMSI As Long) As Long
Dim buff As String
buff = Space$(MAX_LENGTH)
If SHGetFolderPath(0, CSIDL_COMMON_DOCUMENTS, 0, SHGFP_TYPE_CURRENT, buff) = S_OK Then
MsiSetTargetPath hMSI, "COMMONDOCSALL", TrimNull(buff)
GetFolderPath = -1
Else
GetFolderPath = 0
End If
End Function
Private Function TrimNull(startstr As String) As String
TrimNull = Left$(startstr, InStr(startstr, Chr(0)) - 1)
End Function
The code compiles. But, when I try to do the install, I get this:
"Can not find the entry point of function 'GetFolderPath', make sure it is exported."
I wrote the dll in VB. Do I need to include some additional file? FindPublicDocsFolder.exp perhaps? If so, where/how do I do that?
Thanks again for any help you can provide.
I am not sure I understand what you are saying.
The folder identifier I should specify should be the key value in the Directory Table? That is the directory table in the installer, right?
If I right-click on the CommonDocsAll folder that I defined in the Files view ("Destination computer's folders" pane), then I do see "Location: [COMMONDOCSALL]".
Also, to update:
I changed the way I am implementing this...I created a .dll and I now point my Custom Action to the dll. I am using Function Signature = New. here is the code from the dll: (FindPublicDocsFolder.dll)
Public Function GetFolderPath(ByVal hMSI As Long) As Long
Dim buff As String
buff = Space$(MAX_LENGTH)
If SHGetFolderPath(0, CSIDL_COMMON_DOCUMENTS, 0, SHGFP_TYPE_CURRENT, buff) = S_OK Then
MsiSetTargetPath hMSI, "COMMONDOCSALL", TrimNull(buff)
GetFolderPath = -1
Else
GetFolderPath = 0
End If
End Function
Private Function TrimNull(startstr As String) As String
TrimNull = Left$(startstr, InStr(startstr, Chr(0)) - 1)
End Function
The code compiles. But, when I try to do the install, I get this:
"Can not find the entry point of function 'GetFolderPath', make sure it is exported."
I wrote the dll in VB. Do I need to include some additional file? FindPublicDocsFolder.exp perhaps? If so, where/how do I do that?
Thanks again for any help you can provide.
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 16, 2008
06:45 PM
COMMONDOCSALL is the key of the Directory table for the CommonDocsAll folder, and that is what you need to specify in the MsiSetTargetPath API. Since DLLs that are built using VB do not export functions, the custom action cannot call your function. You need to write your DLL in C/C++ or use a VBScript custom action to get it working.
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 17, 2008
07:33 AM
Thanks very much for your help.
I originally implemented my custom action with vbscript, and switched to using a dll when the script didn't work properly. I will switch back to the script, now that I have a better understanding. Hopefully I can get it to work now.
Thanks again.
I originally implemented my custom action with vbscript, and switched to using a dll when the script didn't work properly. I will switch back to the script, now that I have a better understanding. Hopefully I can get it to work now.
Thanks again.
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 17, 2008
07:57 AM
In my VBScript, if I use the MsiSetTargetPath function, I will need to pass in the handle to the .msi database. I understood that, if I was calling a .dll, I could use the "New" function signature to pass the handle into my named function, and I could have that function require the handle as an argument.
If I use VBScript, how can I pass the handle to the .msi database into my script, so I can use the MsiSetTargetPath function? I haven't seen an example of passing arguments to VBScripts. Or, can I refer to "COMMONDOCSALL" using the Session.Property() functionality, which doesn't require the handle?
Thanks again for your help.
UPDATE:
I have verified that using Session.Property("COMMONDOCSALL") does not work. So, I guess I need to figure out a way to pass the .msi handle into my VBScript.
If I use VBScript, how can I pass the handle to the .msi database into my script, so I can use the MsiSetTargetPath function? I haven't seen an example of passing arguments to VBScripts. Or, can I refer to "COMMONDOCSALL" using the Session.Property() functionality, which doesn't require the handle?
Thanks again for your help.
UPDATE:
I have verified that using Session.Property("COMMONDOCSALL") does not work. So, I guess I need to figure out a way to pass the .msi handle into my VBScript.
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 17, 2008
02:08 PM
What a miserable experience this is!!!
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 17, 2008
02:25 PM
Try using Session.TargetPath as the equivalent to MsiSetTargetPath. It should just work like this:
Session.TargetPath("COMMONDOCSALL") = "C:\Somewhere"
Session.TargetPath("COMMONDOCSALL") = "C:\Somewhere"
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 17, 2008
03:07 PM
Here is my script:
I am attaching a screen shot ()of the directory tree from the Files view. If I right-click on the CommonDocsAll folder, I see that Location: "COMMONDOCSALL".
Here is my Custom Action view:
It seems to me that this should work. I must be doing something really stupid.
Thank you for your patience, and any further help you can give.
Option Explicit
Private Const CSIDL_COMMON_DOCUMENTS = &H2E
Private Const SHGFP_TYPE_CURRENT = &H0
Private Const SHGFP_TYPE_DEFAULT = &H1
Private Const MAX_LENGTH = 260
Private Const S_OK = 0
Private Const S_FALSE = 1
Private Declare Function SHGetFolderPath Lib "shfolder.dll" _
Alias "SHGetFolderPathA" _
(ByVal hwndOwner As Long, _
ByVal nFolder As Long, _
ByVal hToken As Long, _
ByVal dwReserved As Long, _
ByVal lpszPath As String) As Long
Public Function GetFolderPath() As Long
Dim buff As String
buff = Space$(MAX_LENGTH)
If SHGetFolderPath(0, CSIDL_COMMON_DOCUMENTS, 0, SHGFP_TYPE_CURRENT, buff) = S_OK Then
Session.TargetPath("COMMONDOCSALL") = TrimNull(buff)
GetFolderPath = 1
Else
GetFolderPath = 0
End If
End Function
Private Function TrimNull(startstr As String) As String
TrimNull = Left$(startstr, InStr(startstr, Chr(0)) - 1)
End Function
I am attaching a screen shot ()of the directory tree from the Files view. If I right-click on the CommonDocsAll folder, I see that Location: "COMMONDOCSALL".
Here is my Custom Action view:
It seems to me that this should work. I must be doing something really stupid.
Thank you for your patience, and any further help you can give.
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 17, 2008
05:47 PM
You need to translate your VB code to VBScript. Try this one and see if it works:
Const ssfCOMMONDOCUMENTS = &H2E
Const ssfCOMMONAPPDATA = &H23
Const ssfAPPDATA = &H1A
Function GetFolderPath()
If getSHSF(ssfCOMMONDOCUMENTS, sPath) Then
Session.TargetPath("COMMONDOCSALL") = sPath
GetFolderPath = 1
Else
GetFolderPath = 0
End If
End Function
Function getSHSF(ssfConst,sPRet)
Set oSHA = CreateObject("Shell.Application")
Set oSpecFold = oSHA.Namespace (ssfConst)
If TypeName(oSpecFold) = "Nothing" then
getSHSF = false : sPRet = ""
Else
getSHSF = true : sPRet = oSpecFold.Self.Path 'XP/2000/ME only
End If
End Function
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 17, 2008
05:58 PM
Wow! Your code is very different from my implementation.
I will have to wait until tomorrow morning to get into the office and try your code.
I can't thank you enough for your help with this problem. I have tried to find out as much as I could about this issue but I am obviously way off base.
Thank you for all your work on this.
I will respond in the morning as soon as I have tested your code.
I will have to wait until tomorrow morning to get into the office and try your code.
I can't thank you enough for your help with this problem. I have tried to find out as much as I could about this issue but I am obviously way off base.
Thank you for all your work on this.
I will respond in the morning as soon as I have tested your code.
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 17, 2008
10:14 PM
What happens when this code runs on a Vista machine? Your comment ('XP/2000/Me only) leads me to believe that this code won't work on Vista. Is that correct?
The entire reason I am doing this is to get my app to run on Vista by putting certain files in the Common_Documents folder.
Thanks agian.
The entire reason I am doing this is to get my app to run on Vista by putting certain files in the Common_Documents folder.
Thanks agian.
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 18, 2008
11:20 AM
I borrowed the code from this page, and it is actually working on my Vista test box. You cannot use the SHGetFolderPath function in your code because VBScript cannot call exported DLL functions. For more information, please look at this page, and/or search the word for "VBScript COMMONAPPDATA" or "VBScript Common_Documents" to find code like that.
- Mark as New
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
‎Jun 18, 2008
12:44 PM
I can't thank you enough for your help. Your script works perfectly on the Vista test machine I have.
What a relief!
I had actually spent the morning writing a .dll in C++ (its been a long time since I did any of that!) but, I will use your script instead. My C++ still needs a little more work, and the VBScript seems much more straight-forward.
Thank you for all your continued work with this. You really went above and beyond the call of duty!
I will continue looking at this, though. I am disappointed that I wasn't able to find the answer myself but, your code looks very different from any examples I encountered. My searching skills must need some work.
Thanks again. You are a life-saver.
What a relief!
I had actually spent the morning writing a .dll in C++ (its been a long time since I did any of that!) but, I will use your script instead. My C++ still needs a little more work, and the VBScript seems much more straight-forward.
Thank you for all your continued work with this. You really went above and beyond the call of duty!
I will continue looking at this, though. I am disappointed that I wasn't able to find the answer myself but, your code looks very different from any examples I encountered. My searching skills must need some work.
Thanks again. You are a life-saver.