Support for em-dash in Windows file paths using StgOpenStorage() - visual-c++

I had a customer reporting problems with a file in a specific path. Debugging some old Windows code, I have found that the code in question that fails is a call to StgOpenStorage(). The path in question that fails has an em-dash. If I take this em-dash out by renaming the file, then the call to StgOpenStorage() succeeds.
So my question is this: is this a known limitation with this function? Are there likely to be other Windows SDK functions that fail with special characters like em-dash? I noticed there is a call to mbstowcs() prior to calling this function, which makes me wonder if the problem is due to the code-page mapping the em-dash character incorrectly. The wchar path looks okay in the Visual Studio debugger prior to the call, so it seems weird that the function would fail on a path that the system allows.

You were right Roger Rowland, it was due to the active locale prior to the call to mbstowcs(). I fixed this problem by calling:
setlocale( LC_ALL, "" );
Prior to the call to mbstowcs(). It looks like for some reason the "C" locale doesn't support em-dash, as if I set this instead it fails:
setlocale( LC_ALL, "C" );
My regional settings are set to English (Australia).
Cheers.

Related

Calling WriteRegMultiStr in NSIS properly

With version 3.02 of NSIS came the addition of the WriteRegMultiStr function. When the function is called in my script the script throws an error:
Usage: WriteRegMultiStr /REGEDIT5 rootkey subkey entry_name hex_string_like_660000000000
root_key=(HKCR[32|64]|HKLM[32|64]|HKCU[32|64]|HKU|HKCC|HKDD|HKPD|SHCTX)
The call itself looks like this:
WriteRegMultiStr /REGEDIT5 HKLM "System\CurrentControlSet\Services\SomeService" "DependsOnService" "service1 service2"
Since there is no documentation on this specific function which was added later on, long after WriteRegStr and WriteRegDWORD were available, I have to wonder - how does one use it?
So far with respect to entering REG_MULTI_SZ values I only found the directive to use a registry-NSIS -plugin. Yet the function exists, so how can it be used?
Addendum:
Encoding the string to hex and passing it with ot without quotation marks yields no desirable result either.
I was actually able to find an answer after digging through the depths of the internet. Since I don't think this has been answered on StackOverflow I will leave a response here, in case anyone wants to use this function.
The structure of the command as described in the opening post is basically correct, but the value must be encoded precisely. My command looks like this:
WriteRegMultiStr /REGEDIT5 HKLM "System\CurrentControlSet\Services\SomeService" "DependsOnService" 54,00,63,00,70,00,69,00,70,00,00,00,41,00,66,00,64
For anyone intending to test this string, this is
Tcpip
Afd
encoded in hexadecimal regedit format. Precisely this is Regedit Version 5.0 format, as opposed to REGEDIT4 format. A conversion editor can be used to achieve this, I used OTConvertIt.
The script should then compile, assuming you run NSIS version 3.02 or higher.
As you found out, the value data must be in the exact same format as .reg files from Windows 2000+.
The reason this instruction works this way is because it is actually the same as WriteRegBin under the hood and very little code was added to support this new functionality.
In the future you might be able to drop the /REGEDIT5 switch and give it plain strings but support for that has not been added yet.
The Registry plug-in does allow you to write these strings in a sane manner.

VS2012 & 2013: Can't publish Services project - specified path is too long

I have a VS2012 solution, containing 10 projects, and suddenly, I can no longer publish my Services project to any folder.
When I try to publish to D:\temp, I get this error:
The expression "[System.IO.Path]::GetFullPath(obj\Release%25252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252528Prod%25252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252529\)" cannot be evaluated. The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters. C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.targets
Huh ?
VS2012 (with update 4) seems to have taken my configuration name "Release(Prod)" and completely messed it up, causing the GetFullPath to produce too long a path name.
How the heck can I fix this ?
Out of desperation, I tried to build and publish the same project in VS2013 - and it had the same error message.
One of my colleagues said he'd seen the same thing, but had fixed it by removing the spaces from his configuration name. I tried this, which is why my configuration name is now "Release(Prod)" rather than "Release (Prod)", but it made no difference.
I did also open the file which this error is suggesting is the cause of the error:
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.targets
..and noticed that there's something in there concerning the AnyCPU platform name. I have tried getting my Services project to use "AnyCPU" and "Any CPU" (depressed sigh) but neither seems to make any difference.
<PropertyGroup Condition=" '$(IntermediateOutputPath)' == '' ">
<IntermediateOutputPath Condition=" '$(PlatformName)' == 'AnyCPU' Or '$(PlatformName)' == ''">$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
. . .
</PropertyGroup>
Has anyone else seen this issue ?
(A little bit later..)
This is so odd (and frustrating).
My Solution has 5 configurations - the default Debug and Release ones, plus extra configurations for Test, PreProduction and Production environments.
If I select any of these three configurations containing brackets, I get this ridiculous "The specified path is too long" error, as VS2012 corrupts the pathname (as shown in my first screenshot above).
I can't help wondering... is this some kind of VS2012 bug, handling spaces or brackets in the configuration name ?
I can deploy to a path directly with (, (, )) in the Target Location on tyhe Connection tab when publishing to the file system (i.e. not building a path from the configuration name) - but that is not a solution to targeting different locations based on the Configuration.
If you want to keep special characters in the configuration name, but specify a path to the deployment folder that will not cause and issue this post might help: Visual Studio: How to properly build and specify the configurations and platforms for x64 and x86
Specifically play with the settings in here:
In the project properties page, select the various permutations of
Debug/Release and x86/x64 in the solution dropdowns. Make sure the
target processor is set correctly (it should be, but I found instances
when they were not, probably because of my previous attempts). Also,
set the output directory. That should be okay and automatic
(/bin/x86/Debug, etc.). If not, fix.
Looking at what is actually seems to be going on is also potentially useful:
Looking at the numbers inserted:
%25 is an encoded %,
%28 is an encoded (
%29 is an encoded )
Looking at the path:
obj\Release%252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525***28***Prod%252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525***29***)
What I think is happening:
So that seems like a good clue that these are being URL or XML encoded. What appears to be happening is that the ( is being encoded as %28 and then the % is being recursively encoded as %25 - generating an infinite %252525252525252525....
A more interesting question is actually why it stops creating 25's from the %'s with this bug (both times it stops creating 25's at 214 characters including the % and the 28 / 29 - not a very interesting number).
Looking at the file C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.targets you reference - it makes sense that these strings are being encoded for XML. I would say this is definitely a bug... I have no suggestions for a fix.
Well, I'm going to accept Matthew's answer as the "Accepted Answer".
Thank you for your help.
This is a really odd problem though, and I'm amazed no one else has reported this elsewhere.
Summary of problem (in case Microsoft is interested, or if anyone tries to Google this issue in the coming years)
With a configuration name of "Release (Prod)", I could happily build my code, run it locally, but when I tried to publish it, even to a local drive, I'd get this message:
It's an odd exception, because the Build did create the "obj\Release (Prod)" folder, without any issues. It's just the Publish which seemed to be looking in the wrong place for it.
Following the advice given in this thread, today I attempted to create a new configuration, with the same settings, but without a space in the name: "Release(SecondProd)". Look what happens:
Interestingly, despite this error, it did create a new configuration with this name.
Anyway, I recreated a new configuration, called it ReleaseProduction, and it worked fine.
Of course, I needed to create new "web.config" Transformation for this name, as this doesn't get automatically copied when you create a new configuration based on an old one.
One last thought (just to confuse matters worse !)
When I posted this plea-for-help, the Services project in my Solution refused to publish to a local drive, but my web site would publish okay.
Today, two days since I last attempted a website Publish, I found that the website also now produces the same GetFullPath exception. Nothing's changed ! We use TFS, I have done a file compare with my project files today against two days ago, and they're identical !
It's a really bizarre bug in VS2012 & VS2013.
Btw, this solution & the projects in it, were originally a VS2010 project. They were upgraded to VS2012 over a year ago, but this Publish problem only started happening recently. I'm not sure if the problem is related to using upgraded VS projects.
Again, thanks for your help.
Now I have some Test, PreProd & Production configurations to recreate !
Maybe I'll grab a beer first..
Summarizing and completing Matthew's answer:
Cause: You have configurations with chars that require URI-encoding - in your case, '(' and ')'.
Workaround: Rename those configs.
What happens: Presumably web deploy URI-encodes the path, replacing % => %25, ( => %28, ) => %29. It does so over and over:
obj\Release(Prod)
obj\Release%28Prod%29
obj\Release%2528Prod%2529
obj\Release%252528Prod%252529
...
Until the path exceeds MAX_PATH=260.
I ran into the same thing and all though it does not resolve the issue I found that if I switch the solution configuration away from a build containing "(" or ")"
Then use the appropriate build in the publish dialog it will not error out.

Windows mobile 6.5 - best way to read and write from and to a config file

I have a handheld device running WM6.5 and trying to put together an application that should prompt the user for some information (login, password) and save it to a file for later use.
Have tried app.config files but unfortunately it requires System::Configuration, I can add the DLL but can't get the code to run, it requires CRL or something like that which I can't configure this being a mobile app - the required option is missing from the project/solution configuration section.
I am using Visual Studio 2008 C++
What's the best way to make this happen? Precisely, 1) write a string somewhere and 2) read it back later on.
TIA
Later edit:
I have tried using a binary file, like this
// write to config file
std::string s="helloworldhelloworldhelloworld";
ofstream ofile("test.txt",ios::binary);
ofile.write((char*)s.c_str(),strlen(s.c_str()));
ofile.close();
And then I have tried reading it back like this
// read config file
char read_str[60];
ifstream inf("test.txt",ios::binary);
inf.read(read_str,60);
inf.close();
LPCTSTR application_settings = CA2W(read_str);
What happens is it adds some garbage at the end of the string, if the string is longer less garbage, otherwise more.
Is there a way to sort out this conversion issue?
Turns out, project was using Unicode and had to use wifstream and wofstream to be able to properly read the strings, rather than attempt to convert them from ANSI to unicode.
This should be a reminder for me to stay away from strong typed languages in the future. Too bad there's no other significant choice for Windows Mobile. Spent a bunch of hours on this, I could have used that time for something else.

Runtime error R6034 in embedded Python application

I am working on an application which uses Boost.Python to embed the Python interpreter. This is used to run user-generated "scripts" which interact with the main program.
Unfortunately, one user is reporting runtime error R6034 when he tries to run a script. The main program starts up fine, but I think the problem may be occurring when python27.dll is loaded.
I am using Visual Studio 2005, Python 2.7, and Boost.Python 1.46.1. The problem occurs only on one user's machine. I've dealt with manifest issues before, and managed to resolve them, but in this case I'm at a bit of a loss.
Has anyone else run into a similar problem? Were you able to solve it? How?
The problem was caused by third-party software that had added itself to the path and installed msvcr90.dll in its program folder. In this case, the problem was caused by Intel's iCLS Client.
Here's how to find the problem in similar situations:
Download Process Explorer here.
Start your application and reproduce runtime error R6034.
Start Process Explorer. In the "View" menu go to "Lower Pane View" and choose "DLLs".
In the top pane, locate your application and click on it. The bottom pane should show a list of DLLS loaded for your application.
Locate "msvcr??.dll" in the list. There should be several. Look for the one that is not in the "winsxs" folder, and make a note of it.
Now, check the path just before your application runs. If it includes the folder you noted in step 5, you've probably found the culprit.
How to fix the problem? You'll have to remove the offending entry from the path before running your program. In my case, I don't need anything else in the path, so I wrote a simple batch file that looks like this:
path=
myprogram.exe
That's it. The batch file simply clears the path before my program runs, so that the conflicting runtime DLL is not found.
This post elaborates on #Micheal Cooper and #frmdstryr and gives a better alternative than my earlier answer.
You can put the following in front of a python script to purge the problematic entries.
import os, re
path = os.environ['PATH'].split(';')
def is_problem(folder):
try:
for item in os.listdir(folder):
if re.match(r'msvcr\d\d\.dll', item):
return True
except:
pass
return False
path = [folder for folder in path if not is_problem(folder)]
os.environ['PATH'] = ';'.join(path)
For the vim with YouCompleteMe case, you can put the following at the top of your vimrc:
python << EOF
import os, re
path = os.environ['PATH'].split(';')
def is_problem(folder):
try:
for item in os.listdir(folder):
if re.match(r'msvcr\d\d\.dll', item):
return True
except:
pass
return False
path = [folder for folder in path if not is_problem(folder)]
os.environ['PATH'] = ';'.join(path)
EOF
A more general solution is:
import os
os.environ['path'] = ";".join(
[path for path in os.environ['path'].split(";")
if "msvcr90.dll" not in map((lambda x:x.lower()), os.listdir(path))])
(I had the same problem with VanDyke SecureCRT)
(This might be better as a comment than a full answer, but my dusty SO acct. doesn't yet have enough rep for that.)
Like the OP I was also using an embedded Python 2.7 and some other native assemblies.
Complicating this nicely was the fact that my application was a med-large .Net solution running on top of 64-Bit IIS Express (VS2013).
I tried Dependency Walker (great program, but too out of date to help with this), and Process Monitor (ProcMon -- which probably did find some hints, but even though I was using filters the problems were buried in thousands of unrelated operations, better filters may have helped).
However, MANY THANKS to Michael Cooper! Your steps and Process Explorer (procexp) got me quickly to a solution that had been dodging me all day.
I can add a couple of notes to Michael's excellent post.
I ignored (i.e. left unchanged) not just the \WinSxS\... folder but also the \System32\... folder.
Ultimately I found msvcr90.dll being pulled in from:
C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x64
Going through my Path I found the above and another, similar directory which seemed to contain 32-bit versions. I removed both of these, restarted and... STILL had the problem.
So, I followed Michael's steps once more, and, discovered another msvcr90.dll was now being loaded from:
C:\Program Files\Intel\iCLS Client\
Going through my Path again, I found the above and an (x86) version of this directory as well. So, I removed both of those, applied the changes, restarted VS2013 and...
No more R6034 Error!
I can't help but feel frustrated with Intel for doing this. I had actually found elsewhere online a tip about removing iCLS Client from the Path. I tried that, but the symptom was the same, so, I thought that wasn't the problem. Sadly iCLS Client and OpenCL SDK were tag-teaming my iisexpress. If I was lucky enough to remove either one, the R6034 error remained. I had to excise both of them in order to cure the problem.
Thanks again to Michael Cooper and everyone else for your help!
Using Michael's answer above, I was able to resolve this without a bat file by adding:
import os
# Remove CLS Client from system path
if os.environ['PATH'].find("iCLS Client")>=0:
os.environ['PATH'] = "".join([it for it in os.environ['PATH'].split(";") if not it.find("iCLS Client")>0])
to the main python file of the application. It just makes sure system path didn't include the paths that were causing the issue before the libraries that loaded the dll's were imported.
Thanks!
This post elaborates on #Micheal Cooper and #frmdstryr.
Once you identified the problematic PATH entries, you can put the following in front of a
python script, assuming here that iCLS Client and CMake are problematic.
import os
for forbidden_substring in ['iCLS Client', 'CMake']:
os.environ['PATH'] = ';'.join([item for item in os.environ['PATH'].split(';')
if not item.lower().find(forbidden_substring.lower()) >= 0])
Concerning the vim with YouCompleteMe case, you can put the following at the top of your vimrc:
python << EOF
import os
for forbidden_substring in ['iCLS Client', 'CMake']:
os.environ['PATH'] = ';'.join([item for item in os.environ['PATH'].split(';')
if not item.lower().find(forbidden_substring.lower()) >= 0])
EOF
If none of these solutions is applicable for you, you can try to remove the problem causing
entries from you PATH manually, but you want to make sure you don't break anything else on your
system that depends on these PATH entries. So, for instance, for CMake you could try to remove
its PATH entry, and only put a symlink (or the like) pointing to the cmake.exe binary into some
other directory that is in your PATH, to make sure cmake is still runnable from anywhere.
Thanks for the solution. I just little modified this sample code as the path variable in my system contains the string "ICLS CLIENT" instead of "iCLS Client"
import os
# print os.environ['PATH']
# Remove CLS Client from system path
if os.environ['PATH'].find("iCLS Client") >= 0 or os.environ['PATH'].find("ICLS CLIENT") >= 0:
os.environ['PATH'] = "".join([it for it in os.environ['PATH'].split(";") if not (it.find("iCLS Client")>0 or it.find("ICLS CLIENT")>0)])
I also had the same problem with embedding Python27.dll from a C-program using the Universal-CRT.
A <PYTHON_ROOT>\msvcr90.dll was the offender. And <PYTHON_ROOT> is off-course in my PATH. AFAICS the only users of msvcr90.dll are the PyWin32 modules
<PYTHON_ROOT>\lib\site-packages\win32\win32*.pyd.
The fix was just move <PYTHON_ROOT>\msvcr90.dll to that directory.
PS. PyWin32 still has this as an issue 7 years later!
In my case the rebuilding of linked libraries and the main project with similar "Runtime execution libraries" project setting helped. Hope that will be usefull for anybody.
In my case, I realised the problem was coming when, after compiling the app into an exe file, I would rename that file. So leaving the original name of the exe file doesn't show the error.
The discussion on this page involves doing things way far advanced above me. (I don't code.) Nevertheless, I ran Process Explorer as the recommended diagnostic. I found that another program uses and needs msvcr90.dll in it's program folder. Not understanding anything else being discussed here, as a wild guess I temporarily moved the dll to a neighboring program folder.
Problem solved. End of Runtime error message.
(I moved the dll back when I was finished with the program generating the error message.)
Thank you all for your help and ideas.
Check any library having user specified path by Process Explorer. It is not necessary must be msvcr??.dll
I solved same problem except I run Python 3. Present solutions not helped because they not indicate unusual paths of msvcr90.dll. I debug code step by step inside till error dialog appears after rows (called when my code was importing PyTables module):
import ctypes
ctypes.cdll.LoadLibrary('libbz2.dll')
Then Process Explorer helps to find path to old libbz2.dll caused the problem (steps 3, 4 of #Micheal Cooper algorithm)
Adding this answer for who is still looking for a solution. ESRI released a patch for this error. Just download the patch from their website (no login required), install it and it will solve the problem. I downloaded the patch for 10.4.1 but there are maybe patches for other versions also.

Application data folder under Linux using Qt QDesktopServices::storageLocation

I am trying to get application data folder location under Linux using Qt's storageLocation function:
QDesktopServices::storageLocation(QDesktopServices::DataLocation)
But this function returns path with two slashes at the end:
/home/user/.local/share/data//
Two slashes at the end of path looks very strange for me. Is this normal? Or this is bug in Qt?
My Linux is Ubuntu.
Qt version is 4.8.1.
This is a bug in Qt (see bug report). However, it happens only if you didn't set your app's name and organization name. You should set them using QApplication::setApplicationName and QApplication::setOrganizationName.
The chop solution you've accepted earlier is bad for two reasons. The first, if this bug is fixed, your code could be broken. Who knows how many slashed will be here in the next version (maybe 0). I'd suggest to use the following to remove double slash:
QString s = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
s = QDir(s).absolutePath();
But it's more important that the /home/user/.local/share/data/ location is still invalid. You need to set application and organization names if you want to get proper location. Simple removing trailing slash doesn't fix anything, it's just a dirty hack.
I know it's an old question but QDesktopService::dataLocation have the following structure <user data location>/<application name>/.
Under linux, the user data location is $HOME/.local/share/data/.
The application name is set via the QCoreApplication::setApplicationName() method, I guess you do not set it, which explains why you have two trailing slashes.
No its not only you its same on here. you just need to chop the last character
QString s = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
s.chop(1);

Resources