none
Fonts from MSI do not get installed

    Question

  • Hi Guys,

     

    Bit of a strange issue here - we have an MSI file that installs some files into Program Files, installs a couple of fonts, then creates a shortcut on all users desktops. Everything works fine when I run the MSI file manually as admin but when pushed out via SCCM (set to require admin permissions and run whether or not a user is logged on) the fonts don't get installed. The workstations we are pushing this out to are all Windows 7, with a mixture of 64 bit and 32 bit - so far I have only tested this MSI on 64 bit so can't confirm yet whether or not the same font problem occurs on 32 bit versions.

    I tried running it from the 32 bit version of command prompt to simulate it being run from the SCCM client and I ran the exact same command that SCCM runs (msiexec /i "blah.msi" /qb!) and it installs the fonts fine so I can't understand why SCCM is not installing them. The only difference is that SCCM will be running it under the Local System account but surely that shouldn't affect the ability to install fonts..

    Anyone got any ideas?

    Thanks

    Chris


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    Tuesday, June 7, 2011 10:22 PM

Answers

  • IT WORKS! :)

    Pretty ridiculously complicated solution just to install some fonts without the user needing to log out and back on but hey, it was fun getting there.

    Here's an explanation of my full solution:

     

    First of all a definition of the files used:

    install.msi is obviously an example name for the MSI we want to install that includes the font installation

    StartInConsoleSession.exe is a VB.NET program I wrote that uses similar code to what I posted on my blog here to launch a process in the session (and security context) of the user that is currently logged on to the computer (e.g the console session) when run from a windows service running as Local System. It does a little more than the code in that blog post, like using the CreateEnvironmentBlock API to setup the correct environmental variables for the new process, but essentially it is the same thing. Specifying the "/W" argument makes it wait for the newly launched process to exit before this program returns control to the batch file / command prompt running it.

    CurrentSessionFonts.exe is another VB.NET program I wrote that uses the Windows API AddFontResource to install a font for the session it is being run from (or remove a font if you specify the "remove" argument instead of the "add" argument). Once the font changes have been made it sends the WM_FONTCHANGE message to all top level windows to let them know about the new font. Although ideally this should be a command line program, as mentioned in the previous post I could not get my StartInConsoleSession.exe app to work with launching a command line program, so this is actually a window forms application that is just invisible and accepts command line arguments. Note that admin permissions are not required for this, as it only affects the current user.

     

    and here is how they are all tied together to make this work:

    The SCCM agent service is told to run a batch file that looks something like this (i.e this is the "Program" that is advertised in SCCM):

    msiexec /i %~dp0install.msi /qb!
    %~dp0StartInConsoleSession /W %~dp0CurrentSessionFonts.exe add C:\Windows\Fonts\Font1.FON
    %~dp0StartInConsoleSession /W %~dp0CurrentSessionFonts.exe add C:\Windows\Fonts\Font2.FON

    For anyone unfamiliar with the %~dp0 environmental variable, it is the full path to the directory a batch file is being run from - as those two programs I wrote are part of this Package in SCCM we know they will exist in the same location that the batch file is in.

    So obviously the first line in that batch file is just installing the MSI silently as normal. Then we use StartInConsoleSession.exe to launch the CurrentSessionFonts.exe process in the currently logged on user's session instead of in the SCCM agent service's session. Even though technically these are all still arguments for the StartInConsoleSession.exe, each argument after CurrentSessionFonts.exe is passed directly to that EXE (CurrentSessionFonts). So we pass in the arguments "add" to tell it we ant to install a font not remov afont, and the path to the font file (which already exists in C:\Windows\Fonts from the MSI installation, even though we can't see it in explorer). Then we repeat the same thing for another font file - if I get chance I will make the CurrentSessionFonts.exe allow you to install multiple fonts by separating them with a comma so that we don't have to call both EXEs again just to add another font.

    Now the user can launch the program installed by install.msi and the fonts work straight away. Once they log off the fonts that were installed by my CurrentSessionFonts program will be lost but it doesn't matter because next time they log on they will get the fonts from the MSI installation as normal :)

    If anyone wants a copy of either of the programs I wrote for this, let me know.

     


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    • Marked as answer by Chris128 Saturday, June 11, 2011 5:56 PM
    Saturday, June 11, 2011 5:03 PM
  • OK the full write up and download links for both programs are now on my blog here: http://cjwdev.wordpress.com/2011/06/12/install-fonts-for-logged-on-user-via-sccm-package/

    If anyone wants the source code just send me an email (email address is at the end of that blog post) and I will send you the VS 2010 project files for both applications.


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    • Marked as answer by Chris128 Sunday, June 12, 2011 7:50 PM
    Sunday, June 12, 2011 7:49 PM

All replies

  • Trying using psexec to create a command prompt as the local SYSTEM and then installing the MSI. Also, add /l*v to the msiexec command-line to get a verbose log from msiexec and see if there are any errors.
    Jason | http://myitforum.com/cs2/blogs/jsandys | Twitter @JasonSandys
    Tuesday, June 7, 2011 11:22 PM
    Moderator
  • thanks, tried that and it does indeed have the same problem... so it is purely the fact it is running as the local system account that is causing the problem then. I enabled logging as you suggested, here are what I think are the relevant parts that relate to one of the font files. From looking at the log it looks like everything worked fine... but the fonts are definitely not installed. I can upload the entire log somewhere if it helps? Its not particularly big as its a very simple install package.

     

    MSI (s) (04:38) [08:56:13:130]: Executing op: SetTargetFolder(Folder=C:\WINDOWS\Fonts\)
    MSI (s) (04:38) [08:56:13:130]: Executing op: SetSourceFolder(Folder=1\FONTSF~1\|Fonts Folder\)
    MSI (s) (04:38) [08:56:13:130]: Executing op: FileCopy(SourceName=TERMTC~1.FON|TERMTCS3_0.FON,SourceCabKey=_39F16108450B4C0C9DAE370E1DB31A69,DestName=TERMTCS3_0.FON,Attributes=512,FileSize=4784,PerTick=65536,,VerifyMedia=1,,,,,CheckCRC=0,,,InstallMode=58982400,,,,,,,)
    MSI (s) (04:38) [08:56:13:145]: File: C:\WINDOWS\Fonts\TERMTCS3_0.FON; To be installed; Won't patch; No existing file

    ...

    MSI (s) (04:38) [08:56:13:364]: Executing op: ActionStart(Name=RegisterFonts,Description=Registering fonts,Template=Font: [1])
    MSI (s) (04:38) [08:56:13:380]: Executing op: ProgressTotal(Total=4,Type=1,ByteEquivalent=1800000)
    MSI (s) (04:38) [08:56:13:380]: Executing op: SetTargetFolder(Folder=C:\WINDOWS\Fonts\)
    MSI (s) (04:38) [08:56:13:380]: Executing op: FontRegister(Title=TermTCS3,File=TERMTCS3_0.FON)
    MSI (s) (04:38) [08:56:13:380]: SHELL32::SHGetFolderPath returned: C:\WINDOWS\Fonts

    Thanks

    Chris


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    Wednesday, June 8, 2011 5:29 PM
  • Nothing to go there. Would need to see the whole thing to know if there any errors.

    How was the MSI created?


    Jason | http://myitforum.com/cs2/blogs/jsandys | Twitter @JasonSandys
    Thursday, June 9, 2011 12:57 AM
    Moderator
  • Command line must be total silent use the /qn switch

     

    msiexec /i "blah.msi" /qn

    Thursday, June 9, 2011 8:43 AM
  • Command line must be total silent use the /qn switch

     

    msiexec /i "blah.msi" /qn

    Why is that? Is does not matter at all IMHO for the installation results.

    Torsten Meringer | http://www.mssccmfaq.de
    Thursday, June 9, 2011 9:03 AM
    Moderator
  • Also if the MSI is creating an "all users desktop" shortcut you have to use the ALLUSERS=1 switch or it won't work

    msiexec /i "blah.msi" /qn ALLUSERS=1

     

    Louis

     


    Thursday, June 9, 2011 1:29 PM
  • Also if the MSI is creating an "all users desktop" shortcut you have to use the ALLUSERS=1 switch or it won't work

    msiexec /i "blah.msi" /qn ALLUSERS=1

     

    Louis

     



    Not sure what desktop shortcuts have got to do with installing fonts... but thanks anyway :) I had actually already hard coded the ALLUSERS=1 property into the Property table in the MSI though so its not that.

    Oh and I will try with /qn but like Torsten I don't think it will make any difference at all because it is not that the app isn't getting installed - it gets installed perfectly fine (and silently) when running the msiexec command manually as an admin and it installs everything but the fonts when run under the local system account.

    Anyway, here is the full log file: http://www.cjwdev.co.uk/Other/C2000.log

    The MSI file was created in Visual Studio 2010

    Would it help if I uploaded the log from doing the same install but as an administrator rather than as local system for comparison?

    Also something I forgot to mention in my first post is that I did originally have problems getting the fonts to install at all - this is basically an ancient application that we have created our own installer for because the original installer will not install on Windows 7 simply because it does not recognise the OS version number. So we just took all of the files and fonts and added them to a setup project in VS 2010 and that generates an MSI for us. I've explained how I finally managed to get the fonts to install on my blog here to help anyone else out that had the same problem but maybe it helps point you in the right direction of where the problem here might be: http://cjwdev.wordpress.com/2011/03/14/installing-non-truetype-fonts-with-visual-studio-installer/

    Thanks

    Chris

     


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com


    Thursday, June 9, 2011 5:32 PM
  • OK well I used Process Monitor to track everything that msiexec.exe was doing during both an admin install and a local system install and then compared all of the font related parts of each log... and found that whilst they are not identical, the logs clearly show that the install run as local system is installing the fonts without a problem. Now when I said the fonts were not installed, the way I was checking this was by running the app we are installing (it looks weird if the fonts are not installed) and also by looking in C:\Windows\Fonts, but after seeing the ProcMon log showing that the fonts were being created in there I tried doing a DIR command from command prompt in the C:\Windows\Fonts directory... and sure enough my font files were there. Presumably when you view this folder in explorer it does more than just show any files in there and actually only shows you fonts that are correctly registered and available to you.

    So now that I knew the fonts were actually there, I wondered if maybe it was just a case of needing a reboot or logging out and back in before they would be available to my user account. Yep, logged out and logged back in and then the fonts worked correctly! I feel kind of stupid for not trying that first but I don't think its unreasonable to expect fonts to be installed without requiring a logoff, especially when this is not required if the fonts get installed by your own user account (which is how it normally happens of course).

    You might think I would be happy to accept this as a solution... but you would be wrong! :) I don't want to tell users they need to reboot or logoff when we push this app out to them via SCCM, it almost feels like it defeats the purpose of doing it via SCCM if it still requires some form of user interaction. Yeah I know it is still much better than us having to connect to their machine and manually install it, but even so - if there is some way to get this to work without the user doing anything at all then I am keen to find out how. Anyone have any suggestions? Is there some way I can get the system to 'refresh' the available fonts for the currently logged on user? I'm no stranger to calling Windows APIs (from .NET code anyway) so I'll take a look at the font APIs to see if there is anything there but if there is an easier way I'm all ears :)


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    • Edited by Chris128 Thursday, June 9, 2011 9:42 PM
    Thursday, June 9, 2011 9:25 PM
  • Think I might have found something in this MSDN article on the AddFontResource API: http://msdn.microsoft.com/en-us/library/dd183326(v=VS.85).aspx

    "Any application that adds or removes fonts from the system font table should notify other windows of the change by sending a WM_FONTCHANGE message to all top-level windows in the operating system. The application should send this message by calling the SendMessage function and setting the hwnd parameter to HWND_BROADCAST"

    I think because the install is being run from another session (the local system's session) then the WM_FONTCHANGE messages that it broadcasts to all windows when it installs the new fonts will not get to any of the windows in the logged on user's session. Its simple enough for me to write a program that sends the WM_FONTCHANGE message manually but the tricky part is going to be getting that program to run in the currently logged on user's session when it is being launched from the local system session... hmmmm.

    EDIT: Actually now I'm not so sure about this theory. I mean I could understand if it was apps that I already had open that were not picking up the new font, but as I'm launching the newly installed application after the fonts have been installed then this WM_FONTCHANGE message wouldn't hit it anyway even when installing as a normal admin user. I have just tried installing the app as local system, then tried installing one of the fonts manually whilst still logged on as my normal account and it didn't say the font already exists or anything, just let me install it (when I tried again it said it already was installed). So I think there is something more to it... back to Process Monitor I guess.


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com

    Thursday, June 9, 2011 9:40 PM
  • Last update for today I promise :P

    I think I was completely wrong about the whole WM_FONTCHANGE thing so given up on that. I've been looking into the issue further and found that absolutely everything is in the right places for these fonts (comparing files, registry entries etc after installation from the local system account to installation from normal account). The only difference is that when I look in C:\Windows\Fonts after the local system install (without logging off first) I don't see the font files even though they definitely are there because I can see them from command prompt and also if I delete the desktop.ini file from C:\Windows\Fonts then I can see them in explorer. They just don't actually work until logging out and back in :(

     None of the registry keys or files change at all after I have logged back in, so I'm starting to think there is nothing I can do about it by just simple file/registry edits. I'm thinking I might be able to call AddFontResource (using PSEXEC to launch my program that will do this in the user's session) and add the fonts that way - because according to MSDN the fonts added that way will get removed after a reboot so then in theory I just end up with the fonts from the install and the ones I installed from AddFontResource just act as a temporary install until the next reboot. Will see how that goes...


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    Thursday, June 9, 2011 11:38 PM
  • Where did the MSI come from that's installing your fonts? Is it actually using the Fonts table in the MSI?
    Jason | http://myitforum.com/cs2/blogs/jsandys | Twitter @JasonSandys
    Friday, June 10, 2011 1:04 AM
    Moderator

  • The MSI file was created in Visual Studio 2010

    ...

    Also something I forgot to mention in my first post is that I did originally have problems getting the fonts to install at all - this is basically an ancient application that we have created our own installer for because the original installer will not install on Windows 7 simply because it does not recognise the OS version number. So we just took all of the files and fonts and added them to a setup project in VS 2010 and that generates an MSI for us. I've explained how I finally managed to get the fonts to install on my blog here to help anyone else out that had the same problem but maybe it helps point you in the right direction of where the problem here might be: http://cjwdev.wordpress.com/2011/03/14/installing-non-truetype-fonts-with-visual-studio-installer/


    Where did the MSI come from that's installing your fonts?

    See quote above from my earlier post

    Is it actually using the Fonts table in the MSI?

    yeah the fonts are in the Fonts table, as mentioned in that link above


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com

    Friday, June 10, 2011 6:04 PM
  • I think for now we are just going to install these fonts on every machine as part of the OS deployment task sequence, then if a machine ever gets this particular app pushed out to it then it will already have the fonts so this won't be an issue.

    I'm keen to try to understand why exactly it requires a logoff/logon to get the fonts to be usable though, when the fonts are actually in C:\Windows\Fonts and the relevant registry keys are there... but its not really worth spending much more time on it when we can just get around the issue by installing the fonts on all machines.


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    Friday, June 10, 2011 6:09 PM
  • Marking your workaround as "Answer"
    Friday, June 10, 2011 9:13 PM
    Moderator
  • I think for now we are just going to install these fonts on every machine as part of the OS deployment task sequence, then if a machine ever gets this particular app pushed out to it then it will already have the fonts so this won't be an issue.

    I'm keen to try to understand why exactly it requires a logoff/logon to get the fonts to be usable though, when the fonts are actually in C:\Windows\Fonts and the relevant registry keys are there... but its not really worth spending much more time on it when we can just get around the issue by installing the fonts on all machines.



    Sorry to come late to the party, but we've had this issue with a custom font installer, via MSI, via LocalSystem, for over 10 years through NT4-XP.
    we reluctantly resolved to jam it in (using the MSI) during OSD (or our old imaging process).
    that's what we still do, under Win7.

    regardless, might be somebody in the core/platform forums or team that could better answer - as this isn't a ConfigMgr defect or limitation, it really seems to be a Windows platform issue.


    Don
    Saturday, June 11, 2011 12:51 AM
  • Thanks Don, good to know its not just me! and yeah I totally agree its nothing to do with SCCM (I just didn't realise that when I first posted this).

     

    The only theory I can come up with of why this happens is as follows:

    When you log on, Windows looks at the list of fonts in HKLM\Software\Microsoft\Windows NT\CurrentVersion\Fonts and for each font calls AddFontResource so that those fonts are available in your session (again, this is all just a theory, it might not work like this at all). Then when you install a font while you are actually logged on (either manually or from an MSI install etc) Windows adds it to that registry key and to C:\Windows\Fonts but then also calls AddFontResource to make the font instantly available to you. AddFontResource only makes a font available to the session it is called from, so therefore when the MSI installs a font and calls AddFontResource from another session (it will be in another session when run from a service) then the user's session is not aware of the new font... until they log back on of course because then it will get picked up from that registry key.

    I'm currently writing a program that will test this theory - it will be called from the SCCM service but will force itself to be launched in the the console session instead of the services session and will call AddFontResource from there to add the fonts that have just been installed by the MSI to the currently logged on user's session. Might not work at all... but we will see :)


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    Saturday, June 11, 2011 10:43 AM
  • Why not move this thread to an MSDN or Windows Installer forum? You'll probably get someone who is more knowledge on the low-level details and can cofirm your theory.
    Jason | http://myitforum.com/cs2/blogs/jsandys | Twitter @JasonSandys
    Saturday, June 11, 2011 2:41 PM
    Moderator
  • That's probably a good idea yeah - the guys in the Windows Installer forum may have come across this before. I assume only a moderator could move it though or am I just not seeing the option?
    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    Saturday, June 11, 2011 3:15 PM
  • Oh and by the way I did test running the install as Local System and then calling AddFontResource from the user's session (just manually running my program that does this) and it worked perfectly - the fonts were available straight away :) everything worked correctly still after logging off and back on as well. Doesn't necessarily prove my theory of exactly why this works the way it does, but its a usable solution to the problem.

    The only issue is getting this program that calls AddFontResource to execute in the current user's session when it is going to be called from the SCCM agent service (as services run in a separate session). I've got some code working that will do this but it has some quirks... it will launch any process successfully in the currently logged on user's session if the code is executed directly from a windows service but it will not launch command line programs if it is run from a separate EXE that a windows service calls. Obviously we can't modify the SCCM agent service itself, we just tell it what programs to run, so I'm stuck with the second scenario. No idea why it works from an EXE running as a service but not from another EXE that a service launches, currently looking into it. However, if I can't get that working I could just make a GUI app that is invisible and have this call AddFontResource (as for some reason launching GUI apps in the user's session works fine even when called from a separate EXE that the service launches). Will give this a try and post my results. Don't you love it when something so simple ends up being so complicated :)


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    Saturday, June 11, 2011 3:53 PM
  • IT WORKS! :)

    Pretty ridiculously complicated solution just to install some fonts without the user needing to log out and back on but hey, it was fun getting there.

    Here's an explanation of my full solution:

     

    First of all a definition of the files used:

    install.msi is obviously an example name for the MSI we want to install that includes the font installation

    StartInConsoleSession.exe is a VB.NET program I wrote that uses similar code to what I posted on my blog here to launch a process in the session (and security context) of the user that is currently logged on to the computer (e.g the console session) when run from a windows service running as Local System. It does a little more than the code in that blog post, like using the CreateEnvironmentBlock API to setup the correct environmental variables for the new process, but essentially it is the same thing. Specifying the "/W" argument makes it wait for the newly launched process to exit before this program returns control to the batch file / command prompt running it.

    CurrentSessionFonts.exe is another VB.NET program I wrote that uses the Windows API AddFontResource to install a font for the session it is being run from (or remove a font if you specify the "remove" argument instead of the "add" argument). Once the font changes have been made it sends the WM_FONTCHANGE message to all top level windows to let them know about the new font. Although ideally this should be a command line program, as mentioned in the previous post I could not get my StartInConsoleSession.exe app to work with launching a command line program, so this is actually a window forms application that is just invisible and accepts command line arguments. Note that admin permissions are not required for this, as it only affects the current user.

     

    and here is how they are all tied together to make this work:

    The SCCM agent service is told to run a batch file that looks something like this (i.e this is the "Program" that is advertised in SCCM):

    msiexec /i %~dp0install.msi /qb!
    %~dp0StartInConsoleSession /W %~dp0CurrentSessionFonts.exe add C:\Windows\Fonts\Font1.FON
    %~dp0StartInConsoleSession /W %~dp0CurrentSessionFonts.exe add C:\Windows\Fonts\Font2.FON

    For anyone unfamiliar with the %~dp0 environmental variable, it is the full path to the directory a batch file is being run from - as those two programs I wrote are part of this Package in SCCM we know they will exist in the same location that the batch file is in.

    So obviously the first line in that batch file is just installing the MSI silently as normal. Then we use StartInConsoleSession.exe to launch the CurrentSessionFonts.exe process in the currently logged on user's session instead of in the SCCM agent service's session. Even though technically these are all still arguments for the StartInConsoleSession.exe, each argument after CurrentSessionFonts.exe is passed directly to that EXE (CurrentSessionFonts). So we pass in the arguments "add" to tell it we ant to install a font not remov afont, and the path to the font file (which already exists in C:\Windows\Fonts from the MSI installation, even though we can't see it in explorer). Then we repeat the same thing for another font file - if I get chance I will make the CurrentSessionFonts.exe allow you to install multiple fonts by separating them with a comma so that we don't have to call both EXEs again just to add another font.

    Now the user can launch the program installed by install.msi and the fonts work straight away. Once they log off the fonts that were installed by my CurrentSessionFonts program will be lost but it doesn't matter because next time they log on they will get the fonts from the MSI installation as normal :)

    If anyone wants a copy of either of the programs I wrote for this, let me know.

     


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    • Marked as answer by Chris128 Saturday, June 11, 2011 5:56 PM
    Saturday, June 11, 2011 5:03 PM
  • I'd be very interested in these tools (and the code). Funny thing is, it sounds like you did exactly what is described here: http://blogs.technet.com/b/cameronk/archive/2010/04/27/creating-a-user-interactive-task-sequence-experience.aspx.

    If you direct message me on Twitter, I'll get you my e-mail address.


    Jason | http://myitforum.com/cs2/blogs/jsandys | Twitter @JasonSandys
    Saturday, June 11, 2011 10:03 PM
    Moderator
  • Yeah it is quite similar, though they make it a fair bit more complicated than it needs to be (maybe that is just so that it handles terminal servers, I only intend for my code to be run on a system with one person logged on interactively). I condense pretty much the whole of steps 4 and 5 in that link into just a couple of lines of code by using WTSQueryUserToken (though it looks like a lot more than that in my code exampl below just from the error handling and status updates etc).

    Anyway, I'll get my EXEs (and code) uploaded to my web server and post a link some time soon :) I'm still trying to figure out why I can't launch a command line application between sessions, as I imagine that might be useful to some people (if they wanted to run a batch file in the logged on user's session for example). I have discovered that if I make my StartInConsoleSession.exe program a GUI app rather than a command line app then it will launch anything (command line or GUI) in the user's session successfully, so I guess that is a bit better than it being the other way around like it is at the moment (where the StartInConsoleSession app is command line but can't launch other command line apps in the user's session). It just means that people won't be able to work with it from the command line like normal, but it still accepts the same command line arguments so its still scriptable - it just won't behave quite how people expect it to behave (if you run it from command prompt you won't get any output in the command prompt window for example).

    I'm keen to get a proper solution where it can be a command line application and also be able to launch command line applications in the user's session but at the moment I'm not getting anywhere fast after spending hours examining process monitor traces and call stacks. It seems to be do with the conhost.exe process that gets spawned by csrss.exe when you launch a command line application - when my StartInConsoleSession.exe is a command line app and it tries to launch a command line app in the user's session then conhost.exe runs in the local system account and dies pretty much instantly, but if StartInConsoleSession.exe is a GUI app and it tries to launch a command line app in the user's session then conhost.exe runs in the user's session and works as normal. Can't for the life of me figure out why...

    EDIT: Here's the main part of the code as it is at the moment if you are interested though:

     

     Private Sub LaunchProcessInConsoleSession(ByVal CommandLine As String, ByVal WaitForExit As Boolean)
     Console.WriteLine("Command line = " & CommandLine & vbNewLine & "Wait for exit = " & WaitForExit.ToString)
     Dim UserTokenHandle As IntPtr = IntPtr.Zero
     Dim EnvironmentBlock As IntPtr = IntPtr.Zero
     Dim ProcInfo As New WindowsApi.PROCESS_INFORMATION
    
     'Not much point in adding comments here - just read the Console.WriteLine strings
     Try
      Console.WriteLine("Attempting to get console session ID...")
      Dim ConsoleSessionId As UInteger = WindowsApi.WTSGetActiveConsoleSessionId
      Console.WriteLine("Console session ID = " & ConsoleSessionId)
    
      Console.WriteLine("Attempting to get handle to primary access token of console session user...")
      Dim QueryTokenResult As Boolean = WindowsApi.WTSQueryUserToken(ConsoleSessionId, UserTokenHandle)
      If QueryTokenResult AndAlso Not UserTokenHandle = IntPtr.Zero Then
      Console.WriteLine("Primary token handle successfully obtained")
      Else
      Console.WriteLine("Failed to get handle to primary token, the last error reported was: " & New ComponentModel.Win32Exception().Message)
      Exit Sub
      End If
    
      Console.WriteLine("Creating environment block for user...")
      Dim CreateEnvironmentResult As Boolean = WindowsApi.CreateEnvironmentBlock(EnvironmentBlock, UserTokenHandle, False)
      If CreateEnvironmentResult AndAlso Not EnvironmentBlock = IntPtr.Zero Then
      Console.WriteLine("Successfully created environment block")
      Else
      Console.WriteLine("Failed to create environment block for user, the last error reported was: " & New ComponentModel.Win32Exception().Message)
      Exit Sub
      End If
    
      Console.WriteLine("Attempting to launch process...")
      Dim StartInfo As New WindowsApi.STARTUPINFOW
      StartInfo.cb = CUInt(Runtime.InteropServices.Marshal.SizeOf(StartInfo))
    
      Dim CreateProcessResult As Boolean = WindowsApi.CreateProcessAsUser(UserTokenHandle, Nothing, CommandLine, IntPtr.Zero, IntPtr.Zero, False, &H400, EnvironmentBlock, Nothing, StartInfo, ProcInfo)
      If CreateProcessResult AndAlso Not ProcInfo.dwProcessId = 0 Then
      Console.WriteLine("Process successfully launched (Process ID = " & ProcInfo.dwProcessId & ")")
      Else
      Console.WriteLine("Failed to launch process, the last error reported was: " & New ComponentModel.Win32Exception().Message)
      End If
     Finally
      'Clean up
      If Not UserTokenHandle = IntPtr.Zero Then
      WindowsApi.CloseHandle(UserTokenHandle)
      End If
      If Not EnvironmentBlock = IntPtr.Zero Then
      WindowsApi.DestroyEnvironmentBlock(EnvironmentBlock)
      End If
     End Try
    
     'Wait for the process to exit if that has been requested
     If WaitForExit AndAlso Not ProcInfo.dwProcessId = 0 Then
      Dim LaunchedProcess As Process = Nothing
      Try
      LaunchedProcess = Process.GetProcessById(CInt(ProcInfo.dwProcessId))
      Catch ex As ArgumentException
      Console.WriteLine("Process has terminated")
      End Try
      If Not LaunchedProcess Is Nothing Then
      Console.WriteLine("Waiting for process to exit...")
      LaunchedProcess.WaitForExit()
      Console.WriteLine("Process has terminated")
      End If
     End If
    
     End Sub
    

     

     


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com


    Sunday, June 12, 2011 12:20 AM
  • Finally got it all working correctly! Perseverance pays off eh (can't believe I've spent literally days on this just so that user's dont need to log off and back on lol).

    Now it can launch command line applications in the user's session without a problem :) All I needed to do was specify the CREATE_NEW_CONSOLE flag in the dwCreationFlags argument of CreateProcessAsUser, it just took a lot of experimenting and testing to realise that. Using this method, a new conhost.exe will get spawned by csrss.exe and it will be in the user's session and security context instead of the new process inheriting the console that StartInConsoleSession.exe is already using (which is obviously in the services session and running as local system so it doesn't work for a command line app running in the user's sessin).

    So now I can chang my CurrentSessionFonts.exe app to be a command line application as it should be, instead of an invisible GUI app (or I could just use RegisterFont as I believe it does the same thing but I couldn't use it before as it is command line). Will get the finished executables and code uploaded and post a link soon.


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    Sunday, June 12, 2011 12:03 PM
  • OK the full write up and download links for both programs are now on my blog here: http://cjwdev.wordpress.com/2011/06/12/install-fonts-for-logged-on-user-via-sccm-package/

    If anyone wants the source code just send me an email (email address is at the end of that blog post) and I will send you the VS 2010 project files for both applications.


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    • Marked as answer by Chris128 Sunday, June 12, 2011 7:50 PM
    Sunday, June 12, 2011 7:49 PM
  • Hi

     

    I got a similar situation. In my case it was an msi containing entries for two msi components both pointing to the aame font file. When I removed one of them it worked as expected. I did not have to logout/login to se the font under windows/fonts

     

    Thanks,

    Tuesday, September 6, 2011 2:36 PM
  • It should work without problem with Msi (at least those made with Adminstudio)

    If you deploy via batch (file copy and reg import) you just need to reboot the machine to see the fonts.

    (you can also send a WM FONTCHANGE message to the applications (which is normally included in Adminstudio packages)

    Hope it helps


    bruno
    Wednesday, September 7, 2011 9:23 AM
  • Are you answering my original question? If so, please see the other posts I made (and the post marked as an answer) in this thread as well as my blog post here: http://cjwdev.wordpress.com/2011/06/12/install-fonts-for-logged-on-user-via-sccm-package/

    Trust me no MSI, no matter what it was made with, is going to install the font for the currently logged on user (without a logoff/logon) when it is being run from the SCCM agent service, as this runs in a separate session to the user's session. Sending WM_FONTCHANGE also does not work because again it will only send it to windows in the service session (session 0) not the user's session. Even if you did send WM_FONTCHANGE to the windows in the user's session, this wouldn't help because you need to call the AddFontResource API to actually register the font with the current session. So that is what I did, I wrote a program that launches any specified executable in the currently logged on user's session and told it to run another program I wrote that calls the AddFontResource API. Works fine without a logoff/logon :)


    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    Wednesday, September 7, 2011 1:35 PM
  • Hi All,

    I'm packaging some branding fonts for a client using Installshield to create a basic MSI and then added the font files into C:\Windows\Fonts. Whilst this works fine in XP, it doesn't in Windows 7 Enterprise x86.

    Copying the font files directly into C:\Windows\Fonts gives me instant access through Word 2007, for example on the Windows 7 host.

    My question is this, if you have had to instigate a supercomplicated methodology to counter this issue, what are vendors doing when presenting applications which have fonts as part of the fileset, as msi's?

    I don't recall ever having to reboot a Windows 7 msi package in order for fonts to be accessible. What about MS office for example?

    Is the gist of this thread that all vendors would have to be implementing something similar to your solution to provide this functionality when delivering through an msi, without the reboot or log/off requirement?

    Cheers,

    Franks

    Wednesday, September 14, 2011 2:54 AM
  • I think you are missing a vital point - this MSI installation of mine was being run from a service (as it is pushed out via SCCM), not from the user's session. When you install MS Office yourself you are installing it in your current user session, so you don't see this issue.
    My website: www.cjwdev.co.uk My blog: cjwdev.wordpress.com
    Wednesday, September 14, 2011 10:58 AM
  • Dear Chris,

    Ive been doing the OSD deployment with softwares in an organization but very recently a requirement came up to put 4 fonts in fonts folder of windows7 machine.

    Will the creation of batch file for copying and pasting the fonts in the respective folder work???

    When i open the font it has install button on top which according to me is like doing the installation of the font. so how do we install the fonts silently using the SCCM so that it is reflected onto the users profile.

    If you can provide me with the answer will help me understand this new thing. Im really surprised how such a small requirement can be so tricky even though we know it can be achieved but still im unable to crack the solution.

    Please help me with a solution.

    Thanks,

    Shoeb Mirza.

    Monday, February 13, 2012 11:19 AM
  • I've already provided the full solution and the programs that I made to get to that solution, so I'm not quite sure what it is you want me to explain. Have you actually read this full thread and my blog post here ? Is there something specifically you don't understand?


    My website (free apps I've written for IT Pro's) : www.cjwdev.co.uk My blog: cjwdev.wordpress.com


    • Edited by Chris128 Monday, February 13, 2012 1:00 PM
    Monday, February 13, 2012 12:50 PM
  • Chris's font problem was very specific to installing fonts using an MSI and really should have nothing to do with OSD.

    If you need to install fonts during OSD, it's more than just copying the files to the Fonts folder. This should help: http://blog.configmgrftw.com/?p=140.


    Jason | http://myitforum.com/myitforumwp/community/members/jasonsandys/ | Twitter @JasonSandys

    Monday, February 13, 2012 2:31 PM
    Moderator