I've got a legacy application that creates an email message with an attachment. The code uses the MAPI interface to create the message. This code has worked for quite some time.
When the application is run on a Windows 7 64 bit machine, the call to MAPILogon fails with a generic error code.
Is there an incompatibility with MAPI and Win7 64? Or is there some COM issue that I am not aware of?
It looks like the problem depends on which API calls you are using.
Calls to MAPISendMail should work without a problem.
For all other MAPI method and function calls to work in a MAPI application, the bitness (32 or 64) of the MAPI application must be the same as the bitness of the MAPI subsystem on the computer that the application is targeted to run on.
In general, a 32-bit MAPI application must not run on a 64-bit platform (64-bit Outlook on 64-bit Windows) without first being rebuilt as a 64-bit application.
For a more detailed explination, see the MSDN page on Building MAPI Applications on 32-Bit and 64-Bit Platforms
I experienced something like this with a legacy application using Crystal Reports 8.5. The CR report viewer has an "Export" button which brings up a dialog which lets you pick a "Destination", one of which is "Microsoft Mail (MAPI)". Exporting to MAPI was failing on Windows 7.
Apparently the problem was due to Microsoft dropping support for "Simple MAPI" in Windows 7.
We were able to resolve the problem with this hotfix from Microsoft:
http://support.microsoft.com/kb/980681
Here's some other discussion which might be helpful for anyone with a similar problem:
http://social.msdn.microsoft.com/Forums/en/windowscompatibility/thread/ff8c9af5-faca-4e53-b6eb-121e0061170f
https://forums.sdn.sap.com/thread.jspa?messageID=9028744
Try this
#echo off
REM NOTE: The MAPI32.dll must be included in the same directory as this patchfile!!
REM NOTE: change the username to corresponding if you're not on a domain remove #domain
takeown /f c:\windows\system32\mapi32.dll
cacls c:\windows\system32\mapi32.dll /G administrator#domain:F
ren c:\windows\system32\mapi32.dll c:\windows\system32\mapi32.dll.ORIGINAL
copy mapi32.dll c:\windows\system32\mapi32.dll
if NOT '%PROCESSOR_ARCHITECTURE%'=='AMD64' goto END
takeown /f c:\windows\sysWOW64\mapi32.dll
cacls c:\windows\sysWOW64\mapi32.dll /G administrator#domain:F
ren c:\windows\sysWOW64\mapi32.dll c:\windows\sysWOW64\mapi32.dll.ORIGINAL
copy mapi32.dll c:\windows\sysWOW64\mapi32.dll
:END
not sure specifically in regards to MAPI, but can be if its done in .NET
Related
Context
We are using NSIS 3.05 with Unicode true (this is important later).
We need to check if a certain process is running, let's call it "processToFind.exe".
In order to do that, we have been using nsProcess Plugin, which is set up correctly, found and integrated just fine.
We include Plugins from our git repository like this:
!addincludedir "C:\pathToRepo\NSIS\Include"
!addplugindir "C:\pathToRepo\NSIS\Plugins"
where pathToRepo is of course a valid path. We also tried using the default Plugin Directories (NSIS-Dir\Plugins\x86-unicode) to no avail (see below).
Documentation says, nsProcess (v 1.6) does suppport unicode. That's why we chose to use it.
NSIS UNICODE support (just rename nsProcessW.dll into nsProcess.dll)
When setting Unicode false or leaving the setting out (so default is ansi), it is working fine, too. ( = running processes found, not running processes not found )
The Installer is 32 bit, we are running on 64 bit Windows 10 machines.
Code
${nsProcess::FindProcess} "procexp.exe" $R0
MessageBox MB_OK "procexp: [$R0]"
which is defined in nsProcess.nsh (provided by plugin, not own code)
!define nsProcess::FindProcess `!insertmacro nsProcess::FindProcess`
!macro nsProcess::FindProcess _FILE _ERR
nsProcess::_FindProcess /NOUNLOAD `${_FILE}`
Pop ${_ERR}
!macroend
Problem
When having set Unicode true , nsProcess will always return 603 ("Process was not currently running").
That's the same, regardless if we try to find 32-bit or 64-bit processes.
That would be expected for 64-bit processes (they cannot be found from 32-bit installers, which is ok for us).
But I do expect it to find 32-bit processes.
Alternatives already explored:
Going through the list found at Check whether your application is running ...
Processes Plugin : Seems outdated, only sourcecode found.
"FindProcess.nsh" : Naming collision, didn't work, neither. Same symptoms.
DDE Server / Win32 Sync / Registry: Not an option.
"tasklist" command: Same symptoms. When executed in cmd, it works but not from installer.
nsExec::ExecToStack '"%SystemRoot%\System32\tasklist" /NH /FI "IMAGENAME eq ${processName}" | "%SystemRoot%\System32\find" /I "${processName}"' always returns "error". (* it's clear now why, see edit below)
"FindProcDLL" Plugin : skipped because
As of NSIS 2.46 this plugin no longer works...
Seemingly related Stackoverflow Questions explored:
NSIS : NsProcess UnExpected Output
Solution was to remove Unicode=true, which I cannot do.
NSIS- FindProc always returns 1
Uses FindProcDLL
NSIS - check if process exists (nsProcess not working)
Error was "Plugin not found" , which we do not have.
I am sure, we are making some "stupid" mistake since I cannot bring myself to believing we are the only ones with that requirement. So, any hints, suggestions and alternatives that are not listed above (or corrections to the above) are welcomed.
Edit
We totally messed up the tasklist call. As #Anders pointed out in comment: nsExec does not support pipes and on top of that, the syntax was also messed up.
Does official example work for you? It works on my machine.
Try this:
0) Delete all nsProcess.dll files (in NSIS, in your include folders, everywhere)
1) Remove line !addplugindir "C:\pathToRepo\NSIS\Plugins" from your script to use plugins in NSIS directories
2) Copy file nsProcessW.dll into **c:\Program Files (x86)\NSIS\Plugins\x86-unicode**
3) Rename file c:\Program Files (x86)\NSIS\Plugins\x86-unicode\nsProcessW.dll -> nsProcess.dll
4) Compile your script with Unicode true
I believe there is some file mismatch. To understand NSIS plugins structure see NSIS - check if process exists (nsProcess not working) .
I'm still using ANSI because I'm using some other plugins that don't have a Unicode variant, so nsProcess works for me, and I'm not sure how to answer your main question.
However, re: the tasklist command alternative you listed, the syntax isn't quite right. You're missing a closing quote after "IMAGENAME eq ${processName}["] and an opening quote before ["]${processName}" in the pipe to find.exe.
Also FYI note that if you use %SystemRoot%\System32\, a 32-bit process will be redirected to C:\Windows\SysWOW64\, and some programs have no 32-bit equivalent (e.g., pnputil). In this case, it doesn't really matter, but in any event to get around this, you should use $WINDIR\SysNative instead. You can also use ${DisableX64FSRedirection} from x64.nsh, but there are apparently some potential pitfalls there.
EDIT: Ah yes, and there's the issue with pipe and ExecToStack mentioned by Anders in the comments to the original question, requiring the call to be prefixed with cmd.exe /C
I'm pretty new to powershell integration in Jenkins and my scripts won't run because (I believe) I need powershell to be executed in 64 bit. Running:
[Environment]::Is64BitProcess
in my execution sequence yields false an then a cmdlet that I use (Get-WindowsFeature) is shown as not recognized as a cmdlet, etc. Any way to execute 64 bit powershell scripts?
Thanks!
Environment
Jenkins on Windows (mine happens to run as a service)
plus Powershell plugin (for running Powershell scripts as "build steps")
Jenkins will typically call upon the correct version of powershell.exe. However, the executor/slave process must be running a 64-bit JRE so that PowerShell can also operate in 64-bit mode.
A simple tester project with the following Powershell script can show the above 32-bit vs 64-bit nature:
$env:Path # Path will have the right Powershell available
[intptr]::size # outputs: 4 = 32-bit, 8 = 64-bit
Stop-WebAppPool FOOBAR # fails when 32-bit, succeeds when 64-bit
Console output example (extra blank lines for clarity):
[Powershell Test] $ powershell.exe -NonInteractive -ExecutionPolicy ByPass "& 'C:\Windows\TEMP\hudson123456789.ps1'"
C:\Windows\system32;C:\Windows;C:\Windows\System32\WindowsPowerShell\v1.0\
4
Stop-WebAppPool : Retrieving the COM class factory for component with CLSID
{688EEEE5-6A7E-422F-B2E1-6AF00DC944A6} failed due to the following error:
80040154 Class not registered (Exception from HRESULT: 0x80040154
(REGDB_E_CLASSNOTREG)).
At C:\Windows\TEMP\hudson123456789.ps1:7 char:1
Solution
tl;dr... Install 64-bit JRE, and configure Jenkins to be 64-bit.
I used chocolatey to install a fairly recent JRE, via "Administrator" PowerShell:
First, install chocolatey:
iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))
Looked for the latest version available https://chocolatey.org/packages?q=java (chocolatey has multiple packages for the same thing, often not kept fully up to date).
Then, install JRE (using the one with the higher JRE number):
choco install -y javaruntime
Or:
choco install -y jre8
Finally, I edited my jenkins.xml configuration so that it would run using the 64-bit JRE instead of the built-in JRE.
Changed:
<executable>%BASE%\jre\bin\java</executable>
To (set the path as appropriate for your instance):
<executable>C:\Program Files\Java\jre1.8.0_66\bin\java</executable>
This one should be an "always fresh" symlink (handled by system updates) that ought to allow your Jenkins instance to survive Restart and Update events:
<executable>C:\ProgramData\Oracle\Java\javapath\java.exe</executable>
Then I restarted Jenkins. Powershell execution woke up to the might of 64-bits. Note: I am using a single Jenkins instance that does double duty as the "server" and "execution slave" at the same time. For fully autonomous slaves, I would suppose doing whatever to get the slave-agents processes in 64-bit mode would result in a similar success.
Full automation? According to the chocolatey "jre8" package documentation, using command line switches, it's even be possible to force fixed destination paths for JRE, and exclude 32-bit and/or 64-bit editions, if fully automated non-interactive steps are needed. https://chocolatey.org/packages/jre8
I am not familiar with Jenkins, but it seems like it's a 32 bit process itself.
Can you specify the location of the PowerShell executable? If so, try to use this path:
C:\Windows\SysNative\WindowsPowerShell\v1.0\powershell.exe
If you can't do that, then you might be able to do it in code in your "execution sequence" with Invoke-Command:
Invoke-Command -ComputerName . -ScriptBlock { [Environment]::Is64BitProcess }
All the code in the scriptblock will be run in a separate 64 bit process and the results will be serialized and returned.
Explanations
Paths
On a 32 bit Windows OS, the system folder is C:\Windows\System32.
On a 64 bit Windows OS, the 64 bit system folder is also C:\Windows\System32. But the system folder for 32 bit processes on a 64 bit Windows installation is in fact C:\Windows\SysWOW64.
For compatibility, a 32 bit process on a 64 bit OS will have any calls to C:\Windows\System32 transparently redirected to C:\Windows\SysWOW64, unbeknownst to the process.
To enable a 32 bit process to reference the real System32 on a 64 bit OS, you can you use C:\Windows\SysNative.
Since PowerShell has a 32 bit and a 64 bit version, and it lives inside the system folders, you need to use the above rules to reference the correct executable depending on whether you're calling it from a 64 or 32 bit process.
The typical scenario (you want to call the version of the same bitness) is easiest (just call powershell.exe or reference it via System32), but it gets hairy if you want to reference the other version.
Invoke-Command Method
The Invoke-Command cmdlet lets you run code, typically on another computer, but you can run it on the same computer as well. This will spawn a completely separate process, and any output gets serialized and sent back to the calling process.
The caveat to this method is that you must enable PowerShell remoting on the machine, via Enable-PSRemoting or Group Policy (shameless self plug).
The default profile (Microsoft.PowerShell) that you connect to on a 64 bit machine will be a 64 bit version of PowerShell, regardless of the OS of the caller.
Incidentally, if you wanted to use Invoke-Command to connect to a 32 bit version, you could do so by explicitly specifying the profile Microsoft.PowerShell32.
OK, so the answer was pretty simple, yet maddening all at once. Basically, the module(s) didn't exist in both of the Powershell paths (x86 and x64), so copying the modules over to the 32-bit powershell environment fixed the issue.
further suggestions:
check path of 32bit-JRE, remove path or uninstall 32bit-JRE --
also swapping path-position with 64bit-JRE might work
check path(s) of PowerShell, remove path of 32bit PowerShell
(..\SysWOW64\..) and add the other one to the path (..\System32\..)
This worked for me!
I am working with Installshield 2014 and 2011. I'm using major upgrades and automated build scripts to handle the build. InstallShield is the stand alone build ver. for both.
Now everything worked fine with Installshield 2011 on windows 2003 servers. I could use the automation interface to open a project, change the product code (for the major upgrade) then save it right before building the installer.
The code for such is in a vbs file as such:
Dim oISM, oGUID
Set oGUID = CreateObject("InstallShield.GUID")
Set oISM = CreateObject("IswiAuto17.ISWiProject")
oISM.OpenProject strInstallShieldProjectFile
oISM.ProductCode = "{" & oGUID.CreateGUID( ) & "}"
oISM.SaveProject : oISM.CloseProject : set oISM = Nothing
Now we've upgraded to windows 2012 servers and InstallShield 2014. I've double checked and according to InstallShield the only change needed is the ver number (17 changes to 21).
But now nothing works. If I take the code out and put it in it's own vbs file for testing and run it, I get this:
ActiveX component can't create object: 'InstallShield.GUID'
Looking on google I see that's from running in 64 bit mode.... but I'm not. I'm running a cmd prompt in 32 bit mode.
http://helpnet.flexerasoftware.com/installshield18helplib/AutomationInterface64Bit.htm
I tried calling the script with:
%WINDIR%\SYSWOW64\cmd.exe /c cscript
as suggested here:
How do I run a VBScript in 32-bit mode on a 64-bit machine?
and other places. This did not work as I got the same error.
I tried removing that line as I'm sure I can create a guid another way, and reran it.
Then I got this when it tries to create the project:
Unknown runtime error: 'CreateObject'
Once again google came up and I checked:
https://community.flexerasoftware.com/showthread.php?189788-Automation-error
and couple others. I tried ensuring the dll was registered using the regsvr32 and it said it was successful. But after rerunning, it gave the same error.
I tried directly coping the command from the InstallShield documentation to ensure no spelling mistakes but again same error.
I even tried switching the case of the "sw" as mentioned here:
Installshield Automation is failing while running vbscript with error unable to create object
Again though, same error.
I also tried switching to powershell as powershell is much easier to debug and read.
The powershell code is simple and is as follows:
$oIsm = new-object -comobject IswiAuto21.ISWiProject
$oISM.OpenProject("$file")
$oISM.ProductCode = "{" + [guid]::NewGuid() + "}"
$oISM.SaveProject(); $oISM.CloseProject(); $oISM = $null
But this also does not work despite these saying it should:
https://community.flexerasoftware.com/showthread.php?190769-Automation-using-Powershell
http://blogs.flexerasoftware.com/installtalk/2011/01/getting-started-with-installshield-automation-and-powershell.html
When I use the 32 bit powershell I get this error:
new-object : Creating an instance of the COM component with CLSID {78D393F9-76E3-438C-9CAB-6664EF5FE1F2} from the IClassFactory failed due to the following error:
800a801d Exception from HRESULT: 0x800A801D.
If I run solely the vbs without a cmd prompt I also see the error of 800A801D in a pop up box.
How can I fix this? I'd like to use powershell but a vbs fix would help as well at this point. I have tried everything I can think of and google says I'm doing it correctly (32 bit powershell/cmd, registering the dll, creating the object, etc).
Did you install the automation interface? Typically it's an optional feature that's set to absent when you install InstallShield.
Typically the HRESULT should tell you what's wrong, or be so generic that it doesn't help. In this case, it's a bit of an enigma as I haven't found its definition anywhere. The leading 0x800A... indicates FACILITY_CONTROL and the trailing ...801d happens to match the tail of TYPE_E_LIBNOTREGISTERED (0x8002801D), but I don't know whether that's meaningful. Unfortunately FACILITY_CONTROL is defined by the control that issues the error, and that's not clear here.
Let's try to figure out what's wrong. My bet is on COM registration. If you want, you can skip to a likely fix by running regsvr32 C:\...\System\ISWiAutomation21.dll.
So let's follow what CreateObject("IswiAuto21.ISWiProject") will do. First it has to look up the ProgID:
C:\>reg query HKCR\ISWiAuto21.ISWiProject\Clsid
HKEY_CLASSES_ROOT\ISWiAuto21.ISWiProject\Clsid
(Default) REG_SZ {78D393F9-76E3-438C-9CAB-6664EF5FE1F2}
Then it has to look up the CLSID, and in this case, its InprocServer32 key:
C:\>reg query HKCR\Clsid\{78D393F9-76E3-438C-9CAB-6664EF5FE1F2}\InprocServer32
HKEY_CLASSES_ROOT\Clsid\{78D393F9-76E3-438C-9CAB-6664EF5FE1F2}\InprocServer32
(Default) REG_SZ C:\...\ISWiAutomation21.dll
ThreadingModel REG_SZ Apartment
If either of these are missing, it will be unable to find the COM server. In addition, the TypeLib subkey and the Type Library it references are both important:
C:\>reg query HKCR\Clsid\{78D393F9-76E3-438C-9CAB-6664EF5FE1F2}\Typelib
HKEY_CLASSES_ROOT\Clsid\{78D393F9-76E3-438C-9CAB-6664EF5FE1F2}\Typelib
(Default) REG_SZ {92278CC1-987E-4A01-940C-47DCADF27496}
C:\>reg query HKCR\Typelib\{92278CC1-987E-4A01-940C-47DCADF27496}\1.1\0\win32
HKEY_CLASSES_ROOT\Typelib\{92278CC1-987E-4A01-940C-47DCADF27496}\1.1\0\win32
(Default) REG_SZ C:\...\ISWiAutomation21.dll
If any of this information is missing, it will have to be repaired. The COM Server itself may need to probe several additional IDs at this point, so there's a chance that even if this subset is okay, there are others that are missing or corrupted. Self-registering the COM server should fix this. So should running the installation's repair.
Note that all of these queries were done using the 32-bit command C:\Windows\SysWow64\reg.exe, or you can peruse the registry visually with C:\Windows\SysWow64\regedit.exe.
wmic process get /format:csv
What is wrong with this command in Windows 7?
I get:
Invalid XSL format (or) file name.
It's a bug in the wmic command. It's been suggested to copy XSL files into the %WINDIR%\system32 (or equivalent if 64 bit.) However, the command below works just as well without the need to copy files:
wmic process get ProcessId,Description,CommandLine,ExecutablePath,ParentProcessId /format:"%WINDIR%\System32\wbem\en-us\csv"
Of course, the "en-us" will be different for different locales.
If you want to redirect output to a file add a switch /output:"your filename here" before the process keyword
This is a bug in Windows 7 and Windows Server 2008 (also R2) WMIC. When you use (for example) Dutch regional settings in an English Windows installation, WMIC searches for the xsl files inside C:\Windows\System32\wbem\nl-NL, instead of C:\Windows\System32\wbem\en-US where they are.
Workarounds:
Copy or move the C:\Windows\system32\wbem\en-US\*.xsl files up into the C:\Windows\system32\wbem\ folder.
Change your regional settings to match your Windows language version, log out and back in.
Specify the full path: WMIC process get /format:"%WINDIR%\System32\wbem\en-US\csv".
This is a Windows 7 wmic bug. Change the International setings to English (United States), reboot and test.
I'm trying to install a custom build software on Windows Server 2008R2, 2008 and 2003. The software needs the "Desktop-Experience" feature from Windows to be installed.
I know I can check with servermanagercmd.exe (even though it's kind of cumbersome) in 2003 and 2008 - unfortunately, this does no longer work in 2008R2 (64bit) from inside an NSIS installer - it does work if I just run the command. Called from the installer, I'm getting a "servermanagercmd.exe is not recognized as an internal or external command, operable program or batch file."-error, even if I'm setting the working directory to c:\windows\system32 (yes, on a 64 bit machine, but there's no servermanagercmd.exe in sysWOW64).
Here's the line of code inside NSIS:
nsExec::ExecToStack 'servermanagercmd.exe -query | findstr "Desktop-Experience"'
In 2008R2, I thought the situation would actually improve, as PowerShell is now installed by default. However, when trying to get the information, I need to first load the ServerManager module inside PowerShell - but this module is not available for reading for Trusted Installer . So I'm facing the same situation again: If I'm running my powershell command from a command line, it works, but not from inside the NSIS installer.
Again, here's the line of code inside NSIS:
nsExec::ExecToStack 'powershell.exe "& "Import-Module ServerManager"'
The three(!) (double)quotation marks are actually correct.
So, does anybody know of a way to check whether Desktop-Experience is installed (and install it if not) in Windows Server 2008R2 from inside an NSIS installer? The solution does not need to work on Server2003 or 2008, because the string parsing from servermanagercmd.exe works there.
Are you using the macros in x64.nsh to turn off WOW64 redirection? (Or use "$windir\sysnative\servermanagercmd.exe")