4

I am facing very strange issue:

I got a 64 bit c#.net application on 64 bit Windows Server 2008 R2 machine and it is being invoked by a Windows Service and it is started under Local System User, Moreover,this 64 bit c#.net application launches 32 bit java application and this java application has application data folder to C:\Windows\SysWOW64\config\systemprofile\AppData. 64 bit c#.net application has app data folder to C:\Windows\System32\config\systemprofile\AppData

So for 32 bit application app data folder is (in case of Local system User):-C:\Windows\SysWOW64\config\systemprofile\AppData

and for 64 bit application app data folder is(in case of Local system User):-C:\Windows\System32\config\systemprofile\AppData

Please Note: this is not typing mistake that they refer to opposite folders(it is a decision by microsoft for 64 bit OS), you can read https://msdn.microsoft.com/en-us/library/aa384187.aspx for detailed explanation.

Now, I need to write few files to 32 bit app data folder from 64 bit application as these files would be used by 32 bit java application.

So, I need to know How I can get 32 bit app data folder from 64 bit application using c#.net.

Important Note: this issue would be faced when application is launched under local system user (i.e. application has been launch by window services) and there won't be any issue when a user explicitly launches the application beacause in this case,user app data folder would be same for 64 bit and 32 bit application.

Yogesh
  • 3,044
  • 8
  • 33
  • 60
  • 1
    "it is a bug by microsoft for 64 bit OS" - it's not a *bug*, it's a deliberate design decision. – Damien_The_Unbeliever Feb 11 '15 at 07:03
  • could be let me correct my statement – Yogesh Feb 11 '15 at 07:04
  • 1
    Why dont you use **Environment.GetFolderPath(Environment.SpecialFolder.SystemX86)** and **Environment.GetFolderPath(Environment.SpecialFolder.System)** for 32 bit and 64 bit app data path and then append the config/systemprofile/AppData ? – Rohit Prakash Feb 11 '15 at 07:06
  • I use this line Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) – Yogesh Feb 11 '15 at 07:06

4 Answers4

1

You first check if you actually are running inside of a 64 bit process on a 64 bit OS. And if so, you construct the path yourself. Otherwise you can just retrieve the system path and append your target path.

String path;
//detect if the current application is 64 bit and running on a 64 bit system
//NOTE: needs .NET Framework 4 to work
if (Environment.Is64BitOperatingSystem && Environment.Is64BitProcess)
{
    path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "SysWOW64");
}
else
{
    path = Environment.GetFolderPath(Environment.SpecialFolder.System);
}
//append your target path
path = Path.Combine(path, @"config\systemprofile\AppData");

Please note that using EnvironmentIs64BitOperatingSystem and Environment.Is64BitProcess requires at least .NET-Framework 4.

  • 2
    This depends on an implementation detail, so it might break in future versions of Windows. – Harry Johnston Feb 11 '15 at 21:34
  • Indeed `SysWOW64` is an implementation detail, but it won't change in the future - if you look at your `System32` directory, you see why. It should be named `System64` in 64 bit versions of Windows, but due to legacy compatibility it is not. – Sebastian Baumhekel Feb 12 '15 at 10:56
  • Unless you've got that in writing, you can't count on it. While the syswow64 folder is unlikely to be renamed or removed for the foreseeable future, there's no compelling reason that I'm aware of why the local system profile has to be inside that folder. Third-party software isn't supposed to use that folder anyway, and I'm not aware of any major software products that do, so backwards compatibility isn't likely to be a firm constraint in this case. Oh, the odds are in your favor, but IMO this sort of gamble is only appropriate if there is no other choice. – Harry Johnston Feb 12 '15 at 18:50
1

The simplest solution is to rebuild the C# application as 32-bit, or to use 64-bit Java.

If you can't do either, create a 32-bit application that does nothing but look up the application data path, and run it from your C# application. The 32-bit application could be written in C, C#, or Java.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • there is not anything else that I could do with code itself...Because, first two solution, I was aware and there were some reason. So, I could not go with them. Moreover, launching 32 bit application is that right?? because my application will be called by a wcf service and there would be so many instance of the application as it per call instance. – Yogesh Feb 12 '15 at 03:33
  • Since you're already running a separate instance of 32-bit Java for each call, running another 32-bit application first is unlikely to affect performance much. But you could cache the result if you wanted to streamline things. One way would be to put it in the registry; if you create a registry key with REG_OPTION_VOLATILE, it will disappear the next time the system is rebooted, which ensures that the cached data won't become invalid. – Harry Johnston Feb 12 '15 at 03:58
0

Are you using "shortcut" keyword to point appdata directory, eg %APPDATA%? Could you use a direct path, eg @"C:\Users\%username%\AppData\Local"

LPs
  • 16,045
  • 8
  • 30
  • 61
0

This is the same answer as #2 above (via Sebastian Baumhekel), with some errors corrected. I am on Win 7 and have the same issue. As some have pointed out this may not be future OS safe... However it solves my current issue.

The issue is on 64bit Win7 when you run a 32bit Windows Service as Local System user and ask for this folder:

Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

It returns the 64bit version (with System32):

C:\Windows\System32\config\systemprofile\AppData\

Main point of clarification (as OP states):

SysWOW64 gets 32bit application data...

System32 gets 64bit application data...

This from OP link:

https://learn.microsoft.com/en-us/windows/desktop/WinProg64/file-system-redirector

I just wasted 4 hours of my life getting to the bottom of this so I wanted to clarify!

    public 32bitWindowsServiceOn64bitWindows()
    { 
        // Note: this service is configured to run as "Local System" user...

        string appdata;

        // need to do this, because this runs as Local System user... 
        // which gets the wrong SpecialFolder.ApplicationData (ie, System32 for 64bit apps) should be SysWOW64 (for 32bit apps)

        if (Environment.Is64BitOperatingSystem && Environment.Is64BitProcess)
        {
            // the application is a 64 bit app
            appdata = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "System32");
        }
        else
        {
            // the application is a 32 bit app
            appdata = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "SysWOW64");
        }
        // Append your target path. Do you want Local or Roaming?
        appdata = Path.Combine(appdata, @"config\systemprofile\AppData\Roaming\MyApp");
        //appdata = Path.Combine(appdata, @"config\systemprofile\AppData\Local\MyApp");
        ...
Alex Martin
  • 156
  • 9