Archive: Copying 64-bit DLL to SYSDIR on W7-64


Copying 64-bit DLL to SYSDIR on W7-64
I'm trying to install both a Win32 and Win64 version of a DLL into SYSDIR on a Windows 7 64-bit machine. The 32-bit works, but the 64-bit doesn't.

I'm using x64.nsh and the test code below (compiled on a 32-bit XP machine). The file MyDLL64.dll is NOT installed even though it displays as being copied and no error is detected. The file MyDLL32.dll shows up in both C:\Windows\System32 and in C:\Windows\SysWOW64, but seems to be the same file because if you delete one, the other goes too (as expected). A complete search of the system shows no MyDLL64.dll file anywhere at all.

This is a simple DLL with no registration required, so simple file copy is sufficient. I don't need the complexity of InstallLib (I've tried that - it gives the same behaviour anyway).

Any suggestions as to what I'm doing wrong, or a workaround?


!include x64.nsh
outfile testwin64dll.exe
RequestExecutionLevel admin
Section Test
${If} ${RunningX64}
MessageBox MB_OK "Running on X64"
${Else}
MessageBox MB_OK "Running on (32-bit) x86"
${EndIf}
DetailPrint "${__TIMESTAMP__}"

SetOutPath $SYSDIR

; 32-bit install:
${EnableX64FSRedirection}
File MyDLL32.dll # extracts to C:\Windows\SysWOW64 -- OK
IfErrors 0 +2
DetailPrint "Failed to copy MyDLL32.dll"

; 64-bit install:
${DisableX64FSRedirection}
File MyDLL64.dll # extracts to C:\Windows\System32 -- NO IT DOESN'T!
IfErrors 0 +2
DetailPrint "Failed to copy MyDLL64.dll"

SectionEnd

Strange, I compiled the code and it copied MyDLL32.dll to syswow64 and MyDLL64.dll to system32 with no copies. Using 2.46.

Though a couple of things.. NSIS has built-in to throw an error message if the file can't be copied. So that part is probably not needed.

You ${EnableX64FSRedirection} after ${DisableX64FSRedirection}, because the installers are 32-bit they go into the 32-bit folders already (Program Files (x86), SysWOW64, etc) unless you have 64-bit files you need to disable redirection and enable it again when you're done.

SetOutPath "$SYSDIR"

${If} ${RunningX64}
  ${DisableX64FSRedirection}
  File MyDLL64.dll
  ${EnableX64FSRedirection}
${EndIf}


I tried your simpler example and the same thing happened - it said it had copied, didn't throw an error, but the file wasn't there.

However, the first time I did it I forgot the SetOutPath $SYSDIR line and it copied MyDLL64.dll into C:\, so the problem must be with System32 itself.

Is there some protection setting in W7 that stops DLL's being copied into System32? Something like Windows File Protection in reverse.

It's a brand new W7 system straight out of the box with UAC at default level.


A bit more research and what do we find: the Wow64EnableWow64FsRedirection Function used by x64.nsh has problems and "may not work reliably when there are nested calls. Therefore, this function has been replaced by the Wow64DisableWow64FsRedirection and Wow64RevertWow64FsRedirection functions." See MSDN ref aa365744(VS.85).aspx

http://msdn.microsoft.com/en-us/libr...8VS.85%29.aspx

Perhaps x64.nsh may need a little touch up. I'll experiment with it tomorrow if I can find the time.


I'm not sure about that, but I have noticed odd things about file manipulation in Win 7. Like un/installers or regular programs being unable to remove/overwrite files. Like if I uninstall Qt it leaves phantom files behind, can't be deleted no matter what. Or I am unable to install Steam because it couldn't overwrite files.

All MS had to tell me was a canned "you might have a virus" reply.

I also have a DX redist installer and as far I could tell there were no problems with 64-bit files.


Still no luck. I've tried two further experiments (code below) and I've tried turning off UAC, and rebooting between calls.

The first experiment is to check the return value from Wow64EnableWow64FsRedirection (it should be true)


!include x64.nsh
outfile testwin64dllraw-old.exe
RequestExecutionLevel admin
Section Test
DetailPrint "${__TIMESTAMP__}"

SetOutPath "$SYSDIR"

${If} ${RunningX64}
StrCpy $0 0
StrCpy $1 0
System::Call kernel32::Wow64EnableWow64FsRedirection(i0) i.r1
DetailPrint "Enable(FALSE) returns $1"
File MyDLL64.dll
System::Call kernel32::Wow64EnableWow64FsRedirection(i1) i.r1
DetailPrint "Enable(TRUE) returns $1"
${EndIf}

SectionEnd


Both calls return false indicating that the call failed (or I've got the System::Call syntax wrong!). But NSIS thinks it's copied the file OK.

Likewise, this code using the new recommended functions also returns false in both cases.


!include x64.nsh
outfile testwin64dllraw.exe
RequestExecutionLevel admin
Section Test
DetailPrint "${__TIMESTAMP__}"

SetOutPath "$SYSDIR"

${If} ${RunningX64}
StrCpy $0 0
StrCpy $1 0
System::Call kernel32::Wow64DisableWow64FsRedirection(*i.r0) i.r1
DetailPrint "Disable returns $1"
DetailPrint "OldValue=$0"
File MyDLL64.dll
System::Call kernel32::Wow64RevertWow64FsRedirection(i.r0) i.r1
DetailPrint "Revert returns $1"
${EndIf}

SectionEnd


If the calls are failing then it could explain the behaviour of NSIS appearing to copy the 64-bit DLL to System32 but Windows is actually sending it of to NUL-land.

The paranoid might suspect yet another ploy to encourage us to migrate to their bl*sted Windows Installer. If I've made a mistake in the System::Call syntax or if someone would like to suggest another test, I'd be happy to try it.

Meanwhile I'll try and work out some weasel words for my app documentation for X64 users.

Mmm, yes, it was working after all. A lesson learnt: if you really hate the useless Windows Explorer that comes with W7, then don't use a _32-bit_ explorer substitute or file-search program. These don't "see" the proper Windows\System32 directory. They are re-directed automatically by WoW64 to the 32-bit view, Hence the duplicate behaviour described above and the apparent lack of copying.