 |
 |

06-01-2008, 11:41 PM
|
|
Freshman
|
|
Join Date: May 2008
Posts: 27
|
|
File Associations in VBE 2008
|
|
Ok, another day, another puzzler...
I get the impression that VBE does not have the "file type editor" that allows me to associate custom file types with my application.
I tried writing a console application to do the association, but it seems I'm not skillful enough to make that work in Vista.
Furthermore, I thought (or perhaps imagined???) that MS is not recommending the use of the Registry anymore. If that's correct, then what is the modern way of associating file extensions to applications?
It's easy enough to do manually, but I'd like to be able to put an installer together that will automate the process on the user's PC.
Thanks for any and all help!!
-Andy.
|
|

06-02-2008, 07:12 AM
|
 |
Ultimate Contributor
Forum Leader * Guru *
|
|
Join Date: Feb 2004
Location: Austin, TX
Posts: 7,598
|
|
They don't recommend using the registry for application setting storage when developing new applications; for legacy applications the registry is going to be supported at least as long as Windows requires it.
Oddly enough, there's not much information about how to do this that I found with a few searches. It's not that difficult, but it seems like since there's a couple of tools to do it for you everyone quit documenting the programmatic way to do so. Here's the basics.
First, you need to associate a "class" with the file extension that you want to be associated with your program. The keys that define these classes live in HKEY_CLASSES_ROOT\, and they follow a specific format. The name of the key should be the extension (including the dot) and its default value should be some friendly name (I believe this is what's displayed in the Folder Options dialog). After creating the class key, you create an association key. These keys are also located in HKEY_CLASSES_ROOT, but follow a different format. The name of the key must be the value of the class key, and there are many, many different values the key may have. For the most basic file association, you should add the subkey shell\open\command, which is the default "Open" action. This subkey's value should be the path to your executable, with the replacement string "%1" to represent the path to the file; if your program takes other parameters feel free to add them. Keep in mind any path that contains spaces should be surrounded in quotes.
As an example, suppose you are installing an editor as "C:\Program Files\MyEditor\edit.exe", and you want to associate files with the "zzz" extension with it. You would first create this registry key (the class key):
HKEY_CLASSES_ROOT\.zzz Value: MyEditorFile
Next, you would create this registry key (the association key):
HKEY_CLASSES_ROOT\MyEditorFile\shell\open\command Value: "C:\Program Files\MyEditor\edit.exe" "%1"
Note that every quote in the above is intentional; you don't know if the replacement string will be a path with spaces, so it must be escaped as well.
The following program contains a general-purpose function that does this, and demonstrates using the function to associate ".zzz" files with Notepad.
Code:
Imports Microsoft.Win32
Module Module1
Sub Main()
Dim extension As String = ".zzz"
Dim className As String = "MyEditorFile"
Dim action As String = "C:\Windows\Notepad %1"
If (CreateAssociation(extension, className, action)) Then
Console.WriteLine("Created!")
Else
Console.WriteLine("Not created!")
End If
End Sub
Private Function CreateAssociation(ByVal extension As String, _
ByVal classname As String, _
ByVal action As String) As Boolean
Dim createdSuccessfully As Boolean = False
Dim HKCR As RegistryKey = Registry.ClassesRoot
' Create the class key
Dim classKey As RegistryKey = HKCR.CreateSubKey(extension)
If classKey IsNot Nothing Then
classKey.SetValue("", classname)
Dim associationPath As String = String.Format("{0}\shell\open\command", classname)
Dim associationKey As RegistryKey = HKCR.CreateSubKey(associationPath)
If associationKey IsNot Nothing Then
associationKey.SetValue("", action)
createdSuccessfully = True
associationKey.Close()
End If
classKey.Close()
End If
Return createdSuccessfully
End Function
End Module
On digging through the MSDN documentation, supposedly the keys in HKCR come from both HKLM\Software and HKCU\Software; I have no idea which this method installs it to. You can probably replace all usage of HKCR with one or the other and get per-user or global file associations, but I have not tested this.
|
Last edited by AtmaWeapon; 06-02-2008 at 07:46 AM.
|

06-02-2008, 11:00 AM
|
|
Freshman
|
|
Join Date: May 2008
Posts: 27
|
|
|
|
Thank you so much for your detailed reply!
However, running the code you offered gives this error:
System.UnauthorizedAccessException was unhandled
Message="Access to the registry key 'HKEY_CLASSES_ROOT\.zzz' is denied."
at the line:
Dim classKey As RegistryKey = HKCR.CreateSubKey(extension)
As I feared, Vista does not allow direct modification of that Registry Class. There may be ways to elevate your rights to do this, but if I'm going to use a method like this on other people's PCs as part of the install of my program, I have to look for a "Vista-friendly" method.
In doing some hunting around, it seems that Vista requires keys to be set under HKCU. However, if I change the line:
Dim classKey As RegistryKey = HKCU.CreateSubKey(extension)
and
Dim associationKey As RegistryKey = HKCU.CreateSubKey(associationPath)
Then the program succeeds, but does not create an association.
I have searched for hours, but as yet have been unable to find an "approved" programmatic method of associating file types that will work in Vista.
Vista has it's own command line tools, like assoc and ftype, but I get "access is denied" when I try to run them. I assume I have to elevate my rights or some other trickery to get that to work, again, probably not possible on a user's PC.
So, what I did was associate a file by using the open with... command and tried to see what happened in the Registry.
What I have found is that in Vista it seems that the following key seems to have changed. This key is added to:
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts
It adds a subkey that is the extension you want to associate, like .zzz
Then adds a subkey called OpenWithProgIds
It adds a value to that subkey that is the name of the file type like zzz_auto_file which is what Windows must use as a default id since you can't specify the name when using "Open With..."
This value is a REG_NONE Binary value. I have no idea how to specify what type of value to add within VB.
Then, it looks like you need another subkey under HKEY_USERS. This is where it gets tricky. Under HKEY_USERS is what appears to be a coded list of users. In my case they start with S-1-5-18 then S-1-5-19, but the next key gets added under S-1-5-21-xxxxxxxxxx-xxxxxxxx-xxxxxxx (whole heap of numbers). No idea how to specify that particular subkey which I can only assume is an identification of me as a user on the system.
Below that alphanumeric subkey is:
Software\Classes\zzz_auto_file
Under that are the shell\open\command subkeys
Inside that is the (default) value (REG_EXPAND_SZ) that is %SystemRoot%\system32\NOTEPAD.EXE %1
So that last key is:
HKU\S-1-5-21-xxxxx\Software\Classes\zzz_auto_file\shell\open\command
There is also \shell\edit\command but I'm sure in my case the open would be fine.
THEN, it creates an identical set of keys (the .zzz key and zzz_auto_file) under
HKU\S-1-5-21-xxxxx_Classes
As in:
HKU\S-1-5-21-xxxxx_Classes\.zzz
and
HKU\S-1-5-21-xxxxx_Classes\zzz_auto_file\shell\open\command
So, the issues are:
How do I create a "REG_NONE" and "REG_EXPAND_SZ" value?
How do I find out what my user "name" is under the HKEY_USERS class (that string of numbers)
Will any method I come up with actually work on Vista AND XP?
Man, this is tough! Maybe I should just buy Visual Studio so it can be done for me!!
-Andy.
|
|

06-02-2008, 12:19 PM
|
|
Freshman
|
|
Join Date: May 2008
Posts: 27
|
|
I have no idea how I found this, but it seems to offer a lot of information, at least about Vista... (This was INCREDIBLY hard to find, due to the fact that most every link to the MSDN library from more than a year ago is invalid!)
http://msdn.microsoft.com/en-us/libr...73(VS.85).aspx
Gonna read the hell out of that and hopefully figure this out!
-Andy.
|
|

06-02-2008, 02:55 PM
|
|
Freshman
|
|
Join Date: May 2008
Posts: 27
|
|
Here's the converted function (by a C++ to VB converter) from C++ to VB...
Code:
Private Function SetContosoAsDefaultForDotHTM() As Integer
Dim pAAR As IApplicationAssociationRegistration
Dim hr As Integer = CoCreateInstance(CLSID_ApplicationAssociationRegistration, Nothing, CLSCTX_INPROC, __uuidof(IApplicationAssociationRegistration), (IntPtr *) pAAR)
If SUCCEEDED(hr) Then
hr = pAAR.SetAppAsDefault("Contoso.WebBrowser.1.06", ".htm", AT_FILEEXTENSION)
pAAR.Release()
End If
Return hr
End Function
The conversion is wrong, as (IntPtr *) pAAR doesn't mean anything in VB.
Also, IApplicationAssociationRegistration as a type as well as SUCCEEDED and AT_FILEEXTENSION is unrecognized in VBE. I assume there's an "imports" I need to do but I don't know what library that would be in.
Here's the original C++ (?) code:
Code:
HRESULT SetContosoAsDefaultForDotHTM()
{
IApplicationAssociationRegistration* pAAR;
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
NULL,
CLSCTX_INPROC,
__uuidof(IApplicationAssociationRegistration),
(void**)&pAAR);
if (SUCCEEDED(hr))
{
hr = pAAR->SetAppAsDefault(L"Contoso.WebBrowser.1.06",
L".htm",
AT_FILEEXTENSION);
pAAR->Release();
}
return hr;
}
Anyone able to help??
-Andy.
|
|

06-03-2008, 03:46 PM
|
|
Freshman
|
|
Join Date: May 2008
Posts: 27
|
|
Success!
Ok, a lot of study of what happens in the registry and a lot more reading on the internet have led me to a method that seems to work in both Vista and XP.
The cool thing is that after doing this, the program will be listed in the "Default Programs" program that ships with Vista and you can set or unset file types with your application from there.
Ok, here's the code:
Code:
Imports Microsoft.Win32
Module Module1
Structure AppExt ' A file extension and short name for that type
Dim Ext As String
Dim Type As String
End Structure
Sub Main()
Dim AppExtArray(1) As AppExt ' 2 types associated with my application
AppExtArray(0).Ext = ".zz1"
AppExtArray(0).Type = "Sleepy 1 File"
AppExtArray(1).Ext = ".zz2"
AppExtArray(1).Type = "Sleepy 2 File"
' Location of my program
Dim AppPath As String = """" & "C:\My Programs\Sleepy.exe" & """" & " ""%1"""
' Dim IconStr As String = "shell32.dll,116" ' I didn't use an icon
For Each ae As AppExt In AppExtArray
' What to do with .zzn-files (icon, open command etc.)
' The 1st parameter "Sleepy.zz1" in this 1st line needs to match the 2nd parameter in the 2nd line,
' and the 1st parameter on the 3rd line.
SaveToRegistry("SOFTWARE\Classes\Sleepy" & ae.Ext, "", ae.Type)
SaveToRegistry("SOFTWARE\Classes\" & ae.Ext, "", "Sleepy" & ae.Ext)
SaveToRegistry("SOFTWARE\Classes\Sleepy" & ae.Ext & "\shell\open\command", "", AppPath)
' Uncomment this if you have an icon
'SaveToRegistry("SOFTWARE\Classes\Sleepy" & ae.Ext & "\DefaultIcon", "", IconStr)
' A description of the program and what kind of files are we capable of handling.
' This is for Vista's "Default Programs" Program
SaveToRegistry("SOFTWARE\MyCompany\Sleepy\Capabilities", "ApplicationDescription", _
"Sleepy - the most tired program ever!")
SaveToRegistry("SOFTWARE\MyCompany\Sleepy\Capabilities\FileAssociations", ae.Ext, "Sleepy" & ae.Ext)
' Register to Default Programs
SaveToRegistry("SOFTWARE\RegisteredApplications", "Sleepy", "Software\MyCompany\Sleepy\Capabilities")
Next
Console.WriteLine("Press Any Key To Continue...")
Console.ReadLine()
End Sub
' Saves a value name with its data and parent key in the registry
' This won't work in Vista unless you elevate the user to administrator
' HKLM works, but HKCR does not in Vista
Public Sub SaveToRegistry(ByVal KeyPath As String, ByVal ValueName As String, ByVal ValueData As Object)
Dim regKey As Microsoft.Win32.RegistryKey
'Open the key with write access
Console.WriteLine("Opening Key: " & KeyPath)
regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(KeyPath, True)
'If not found, create the key
If regKey Is Nothing Then
'Create a key in HKEY_LOCAL_MACHINE\[Path]
Console.WriteLine("Not Found. Creating Key: " & KeyPath)
regKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(KeyPath)
End If
'Set the new value
Console.WriteLine("Setting Value: " & IIf(ValueName = "", "(Default)", ValueName) & "=" & ValueData)
regKey.SetValue(ValueName, ValueData)
Console.WriteLine()
End Sub
End Module
For this to work in Vista, you need to change app.manifest (found by pressing the "View UAC settings " on the Application tab of your project) to the following:
Code:
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv1="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv2="urn:schemas-microsoft-com:asm.v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC Manifest Options
If you want to change the Windows User Account Control level replace the
requestedExecutionLevel node with one of the following.
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
-->
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<!--
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
If you want to utilize File and Registry Virtualization for backward
compatibility then delete the requestedExecutionLevel node.
-->
</requestedPrivileges>
</security>
</trustInfo>
</asmv1:assembly>
i.e. you're raising the requestedExecutionLevel to "requireAdministrator".
I need to thank MS and the (unknown) writer of the article I linked to, as well as the person calling himself "Assomon_7" who wrote the VB code example attached to that article. And also Ataman for his code and guidance. Never would have gotten here if it wasn't for all these people!
-Andy.
|
|

06-08-2008, 07:39 PM
|
|
Freshman
|
|
Join Date: May 2008
Posts: 27
|
|
Easy way
Ok, don't you hate when you've just spent a lot of time and effort to get something to work, only to find that there was an easier way, but didn't know about it until you'd already done all that work???
Well, that's the case for VBE 2008's "clickonce" and file associations.
Turns out you can add file associations by modifying app.manifest.
The details are here. http://blogs.msdn.com/mwade/archive/...plication.aspx
Seems to work, at least on the machine I'm building the applications on, but fails on machines that I try to install my clickonce application to. Simply does not write the associations to the registry.
Not sure how to solve this one, and I seem to be talking to myself here...
-Andy.
|
|

06-09-2008, 10:20 AM
|
|
Freshman
|
|
Join Date: May 2008
Posts: 27
|
|
I think this should be a blog instead of a forum post!
The target machine needs to have Net 3.5 installed on it. Also, since ClickOnce "by design" does not support command line parameters, associating files is pointless. You double-click the data file, sure your application opens, but it doesn't load the data file because CommandLineArguments is emtpy. Pretty dumb, MS!!
That and the .Net 3.5 requirement is too much of a show-stopper. I went back to a modified version my previous method. I have to get the program to associate directly with the application, not to the ClickOnce launcher. One of the issues was uninstalling and having the program remove all the registry entries. I "seems" that using ClickOnce AND the registry method removes the registry entries when uninstalling the software.
What a lot of hoops to jump through!
-Andy.
|
|
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
|
|
|
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
| |
|
|
|
 |
|