Easier. Why not to create a batch file for each VS you are using, that will modify the register to change file association for the one its going about to run, like
vs08.bat -> associate cpp,hpp with vs08 -> run vs08
vs10.bat -> associate cpp,hpp with vs10 -> run vs10
You can use "assoc" to change file associations from the command line.
I don't have VisualStudio on this machine to check the exact syntax but running "assoc .cpp" will show you the current association. Just changing the version number is usually enough ...
August 9, 2010 at 2:03 PM
Anonymous said...
Try ASSOC and FTYPE. Looks like ASSOC maps extension to type, and FTYPE maps type to application. I guess you could create one type for each version of VS, then use ASSOC to change the mapping.
Goddamnit, blogger ate my first post with my second one. My first post was basically "see ASSOC and FTYPE, the mapping is 2-step, oh and here's a link: http://ss64.com/nt/assoc.html".
That doesn't support the default "open in notepad" though. That same problem has been pissing me off for a while, so I wrote a little app which reroutes file opens-
// Take a snapshot of all modules in the specified process. hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID ); if( hModuleSnap == INVALID_HANDLE_VALUE ) { return( TRUE ); }
// Set the size of the structure before using it. me32.dwSize = sizeof( MODULEENTRY32 );
// Retrieve information about the first module, // and exit if unsuccessful if( !Module32First( hModuleSnap, &me32 ) ) { CloseHandle( hModuleSnap ); // Must clean up the snapshot object! return( TRUE ); }
// Now walk the module list of the process, // and display information about each module do { if (strstr(me32.szModule, "devenv.exe")) { std::string path = "start \""; path += me32.szExePath; path += "\" "; path += filename; printf(path.c_str()); system(path.c_str()); CloseHandle( hModuleSnap ); return FALSE; } } while( Module32Next( hModuleSnap, &me32 ) );
// Do not forget to clean up the snapshot object. CloseHandle( hModuleSnap ); return( TRUE ); }
// Take a snapshot of all running threads hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); if( hThreadSnap == INVALID_HANDLE_VALUE ) return( TRUE );
// Fill in the size of the structure before using it. te32.dwSize = sizeof(THREADENTRY32 );
// Retrieve information about the first thread, // and exit if unsuccessful if( !Thread32First( hThreadSnap, &te32 ) ) { CloseHandle( hThreadSnap ); // Must clean up the snapshot object! return( TRUE ); }
// Now walk the thread list of the system, // and display information about each thread // associated with the specified process do { if (!ListProcessModules(te32.th32OwnerProcessID, filename)) return TRUE; } while( Thread32Next(hThreadSnap, &te32 ) );
// Don't forget to clean up the snapshot object. CloseHandle( hThreadSnap ); return( FALSE ); }
// Take a snapshot of all modules in the specified process. hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID ); if( hModuleSnap == INVALID_HANDLE_VALUE ) { return( TRUE ); }
// Set the size of the structure before using it. me32.dwSize = sizeof( MODULEENTRY32 );
// Retrieve information about the first module, // and exit if unsuccessful if( !Module32First( hModuleSnap, &me32 ) ) { CloseHandle( hModuleSnap ); // Must clean up the snapshot object! return( TRUE ); }
// Now walk the module list of the process, // and display information about each module do { if (!strcmp(me32.szModule, "devenv.exe")) { std::string path = "start \""; path += me32.szExePath; path += "\" "; path += filename; printf(path.c_str()); system(path.c_str()); CloseHandle( hModuleSnap ); return FALSE; } } while( Module32Next( hModuleSnap, &me32 ) );
// Do not forget to clean up the snapshot object. CloseHandle( hModuleSnap ); return( TRUE ); }
I'm turning this into a more generic utility I'll call SendTo , which will look for any process name and send the file to it, and errorlevel return if not found, so you can then run the default from a batch file.
#include <Windows.h> #include <tlhelp32.h> #include <stdio.h> #include <string> BOOL ListProcessModules( DWORD dwPID, const char* processName, const char* filename ) { HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; // Take a snapshot of all modules in the specified process. hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID ); if( hModuleSnap == INVALID_HANDLE_VALUE ) { return( TRUE ); } // Set the size of the structure before using it. me32.dwSize = sizeof( MODULEENTRY32 ); // Retrieve information about the first module, // and exit if unsuccessful if( !Module32First( hModuleSnap, &me32 ) ) { CloseHandle( hModuleSnap ); // Must clean up the snapshot object! return( TRUE ); } CloseHandle( hModuleSnap ); // Must clean up the snapshot object! if (strstr(processName, me32.szModule) == processName) { std::string path; path += "start \"\" /B \""; path += me32.szExePath; path += "\" "; path += processName + strlen(me32.szModule); path += " \""; path += filename; path += "\""; printf("%s\n", path.c_str()); system(path.c_str()); return FALSE; } return( TRUE ); } BOOL ListProcessThreads(const char* processName, const char* filename) { HANDLE hThreadSnap = INVALID_HANDLE_VALUE; THREADENTRY32 te32; // Take a snapshot of all running threads hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); if( hThreadSnap == INVALID_HANDLE_VALUE ) return( TRUE ); // Fill in the size of the structure before using it. te32.dwSize = sizeof(THREADENTRY32 ); // Retrieve information about the first thread, // and exit if unsuccessful if( !Thread32First( hThreadSnap, &te32 ) ) { CloseHandle( hThreadSnap ); // Must clean up the snapshot object! return( TRUE ); } // Now walk the thread list of the system, // and display information about each thread // associated with the specified process do { if (!ListProcessModules(te32.th32OwnerProcessID, processName, filename)) return TRUE; } while( Thread32Next(hThreadSnap, &te32 ) ); // Don't forget to clean up the snapshot object. CloseHandle( hThreadSnap ); return( FALSE ); } int main( int argc, const char** argv ) { if (argc != 3) { printf("usage: %s [process name] [filename]\n", argv[0]); return -1; } if (!ListProcessThreads(argv[1], argv[2])) { return 1; } return 0; }
@echo off "%~dp0sendto" "devenv.exe /Edit" %1 if ERRORLEVEL 1 start notepad %1
August 23, 2010 at 7:32 PM
This is my annoyance of the moment. I rarely double-click CPP/H files, but once in a while it's handy.
On my work machine, I currently have VC 2003,2005,2008, and 2010 installed. Which one should the CPP/H file open in?
The right answer is obviously : whichever one is currently running.
And of course there's no way to do that.
Almost every day recently I've had a moment where I am working away in VC ver. A , and I double click some CPP file,
and it doesn't pop up, and I'm like "WTF", and then I hear my disk grinding, and I'm like "oh nooes!" , and then the
splash box pops up announcing VC ver. B ; thanks a lot guys, I'm really glad you started a new instance of your gargantuan
hog of a program so that I could view one file.
Actually if I don't have a DevStudio currently running, then I'd like CPP/H to just open in notepad. Maybe I have to
write my own tool to open CPP/H files. But even setting the file associations to point at my own tool is a nightmare. Maybe I have to write
my own tool to set file associations. Grumble.
(for the record : I have 2008 for Xenon, 2005 is where I do most of my work, I keep 2003 to be able to build some old code that I haven't
ported to 2005 templates yet, and 2010 to check it out for the future).
"08-06-10 - Visual Studio File Associations"
19 Comments -
Can't you just associate c and h to a batch 4dos batch file that looks for the MSVC that's running?
August 8, 2010 at 11:22 PM
4dos can look for an MSVC?
August 9, 2010 at 12:20 AM
Easier. Why not to create a batch file for each VS you are using, that will modify the register to change file association for the one its going about to run, like
vs08.bat
-> associate cpp,hpp with vs08
-> run vs08
vs10.bat
-> associate cpp,hpp with vs10
-> run vs10
should be quite simple
August 9, 2010 at 7:34 AM
That's a pretty good idea. How do I do :
-> associate cpp,hpp with vs08
?
August 9, 2010 at 9:50 AM
You can use "assoc" to change file associations from the command line.
I don't have VisualStudio on this machine to check the exact syntax but running "assoc .cpp" will show you the current association. Just changing the version number is usually enough ...
August 9, 2010 at 2:03 PM
Try ASSOC and FTYPE. Looks like ASSOC maps extension to type, and FTYPE maps type to application. I guess you could create one type for each version of VS, then use ASSOC to change the mapping.
A quick google suggests http://ss64.com/nt/assoc.html has some info...
August 9, 2010 at 2:21 PM
BTW Here's what my PC says for .cpp:
[0][ C:\bin\4nt ]assoc .cpp
.cpp=VisualStudio.cpp.8.0
[0][ C:\bin\4nt ]ftype VisualStudio.cpp.8.0
VisualStudio.cpp.8.0="C:\vs2005\Common7\IDE\devenv.exe" /dde
August 9, 2010 at 2:22 PM
Goddamnit, blogger ate my first post with my second one. My first post was basically "see ASSOC and FTYPE, the mapping is 2-step, oh and here's a link: http://ss64.com/nt/assoc.html".
August 9, 2010 at 2:24 PM
Whoah , I had no idea assoc & ftype existed. Awesome.
August 9, 2010 at 3:24 PM
Woah, assoc and ftype. That is awesome!
August 10, 2010 at 6:25 AM
That doesn't support the default "open in notepad" though. That same problem has been pissing me off for a while, so I wrote a little app which reroutes file opens-
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <string>
// Forward declarations:
BOOL ListProcessModules( DWORD dwPID, const char* filename );
BOOL ListProcessThreads(const char* filename);
void main( int argc, const char** argv )
{
if (argc != 2)
{
printf("usage: %s [filename]\n", argv[0]);
return;
}
if (!ListProcessThreads(argv[1]))
{
std::string path;
path += "start notepad ";
path += argv[1];
system(path.c_str());
}
}
BOOL ListProcessModules( DWORD dwPID, const char* filename )
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
return( TRUE );
}
// Set the size of the structure before using it.
me32.dwSize = sizeof( MODULEENTRY32 );
// Retrieve information about the first module,
// and exit if unsuccessful
if( !Module32First( hModuleSnap, &me32 ) )
{
CloseHandle( hModuleSnap ); // Must clean up the snapshot object!
return( TRUE );
}
// Now walk the module list of the process,
// and display information about each module
do
{
if (strstr(me32.szModule, "devenv.exe"))
{
std::string path = "start \"";
path += me32.szExePath;
path += "\" ";
path += filename;
printf(path.c_str());
system(path.c_str());
CloseHandle( hModuleSnap );
return FALSE;
}
} while( Module32Next( hModuleSnap, &me32 ) );
// Do not forget to clean up the snapshot object.
CloseHandle( hModuleSnap );
return( TRUE );
}
BOOL ListProcessThreads(const char* filename)
{
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
// Take a snapshot of all running threads
hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
if( hThreadSnap == INVALID_HANDLE_VALUE )
return( TRUE );
// Fill in the size of the structure before using it.
te32.dwSize = sizeof(THREADENTRY32 );
// Retrieve information about the first thread,
// and exit if unsuccessful
if( !Thread32First( hThreadSnap, &te32 ) )
{
CloseHandle( hThreadSnap ); // Must clean up the snapshot object!
return( TRUE );
}
// Now walk the thread list of the system,
// and display information about each thread
// associated with the specified process
do
{
if (!ListProcessModules(te32.th32OwnerProcessID, filename))
return TRUE;
} while( Thread32Next(hThreadSnap, &te32 ) );
// Don't forget to clean up the snapshot object.
CloseHandle( hThreadSnap );
return( FALSE );
}
August 14, 2010 at 10:08 PM
Well done sir, I just built it and it seems to work dandy.
Yeah the assoc/ftype thing is awesome but doesn't actually solve the problem in question.
I mean, say I run vs08.bat , then vs10.bat , then close my vs10, it's associated to the wrong thing. Buggy, fragile.
August 14, 2010 at 10:33 PM
This version's a little bit quicker. I was finding it a little bit laggy when running through VM Ware on my laptop-
#include <tlhelp32.h>
#include <stdio.h>
#include <string>
#pragma comment(lib, "User32.lib")
// Forward declarations:
BOOL ListProcessModules( DWORD dwPID, const char* filename );
BOOL CALLBACK EnumWindowsProc(__in HWND hwnd, __in LPARAM lParam);
void main( int argc, const char** argv )
{
if (argc != 2)
{
printf("usage: %s [filename]\n", argv[0]);
return;
}
if (EnumWindows(&EnumWindowsProc, (LPARAM)argv[1]))
{
std::string path;
path += "start notepad ";
path += argv[1];
system(path.c_str());
}
}
BOOL ListProcessModules( DWORD dwPID, const char* filename )
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
return( TRUE );
}
// Set the size of the structure before using it.
me32.dwSize = sizeof( MODULEENTRY32 );
// Retrieve information about the first module,
// and exit if unsuccessful
if( !Module32First( hModuleSnap, &me32 ) )
{
CloseHandle( hModuleSnap ); // Must clean up the snapshot object!
return( TRUE );
}
// Now walk the module list of the process,
// and display information about each module
do
{
if (!strcmp(me32.szModule, "devenv.exe"))
{
std::string path = "start \"";
path += me32.szExePath;
path += "\" ";
path += filename;
printf(path.c_str());
system(path.c_str());
CloseHandle( hModuleSnap );
return FALSE;
}
} while( Module32Next( hModuleSnap, &me32 ) );
// Do not forget to clean up the snapshot object.
CloseHandle( hModuleSnap );
return( TRUE );
}
BOOL CALLBACK EnumWindowsProc(__in HWND hwnd, __in LPARAM lParam)
{
DWORD threadId;
GetWindowThreadProcessId(hwnd, &threadId);
const char* filename = (const char*)lParam;
return ListProcessModules(threadId, filename);
}
August 15, 2010 at 7:49 AM
Why don't you just use TH32CS_SNAPPROCESS ?
I'm turning this into a more generic utility I'll call SendTo , which will look for any process name and send the file to it, and errorlevel return if not found, so you can then run the default from a batch file.
August 15, 2010 at 8:18 AM
Well I guess you don't really need to enumerate all processes, just the ones with windows
August 15, 2010 at 8:23 AM
In fact you only need to check the first module of each process too, as that is guaranteed to be the exe
August 15, 2010 at 8:38 AM
" Well I guess you don't really need to enumerate all processes, just the ones with windows "
Yeah but the number of processes is like an order of magnitude smaller than the number of windows typically (a few hundred vs a few thousand)
August 15, 2010 at 9:22 AM
sendto.cpp-
#include <Windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <string>
BOOL ListProcessModules( DWORD dwPID, const char* processName, const char* filename )
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
return( TRUE );
}
// Set the size of the structure before using it.
me32.dwSize = sizeof( MODULEENTRY32 );
// Retrieve information about the first module,
// and exit if unsuccessful
if( !Module32First( hModuleSnap, &me32 ) )
{
CloseHandle( hModuleSnap ); // Must clean up the snapshot object!
return( TRUE );
}
CloseHandle( hModuleSnap ); // Must clean up the snapshot object!
if (strstr(processName, me32.szModule) == processName)
{
std::string path;
path += "start \"\" /B \"";
path += me32.szExePath;
path += "\" ";
path += processName + strlen(me32.szModule);
path += " \"";
path += filename;
path += "\"";
printf("%s\n", path.c_str());
system(path.c_str());
return FALSE;
}
return( TRUE );
}
BOOL ListProcessThreads(const char* processName, const char* filename)
{
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
// Take a snapshot of all running threads
hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
if( hThreadSnap == INVALID_HANDLE_VALUE )
return( TRUE );
// Fill in the size of the structure before using it.
te32.dwSize = sizeof(THREADENTRY32 );
// Retrieve information about the first thread,
// and exit if unsuccessful
if( !Thread32First( hThreadSnap, &te32 ) )
{
CloseHandle( hThreadSnap ); // Must clean up the snapshot object!
return( TRUE );
}
// Now walk the thread list of the system,
// and display information about each thread
// associated with the specified process
do
{
if (!ListProcessModules(te32.th32OwnerProcessID, processName, filename))
return TRUE;
} while( Thread32Next(hThreadSnap, &te32 ) );
// Don't forget to clean up the snapshot object.
CloseHandle( hThreadSnap );
return( FALSE );
}
int main( int argc, const char** argv )
{
if (argc != 3)
{
printf("usage: %s [process name] [filename]\n", argv[0]);
return -1;
}
if (!ListProcessThreads(argv[1], argv[2]))
{
return 1;
}
return 0;
}
August 23, 2010 at 7:31 PM
vcsendto.bat-
@echo off
"%~dp0sendto" "devenv.exe /Edit" %1
if ERRORLEVEL 1 start notepad %1
August 23, 2010 at 7:32 PM