Friday, June 24, 2022

Outlook 2013 MAPI not working but Outlook (Office 365) works fine

I have a 32-bit Windows Forms application that uses PInvoke to call the MAPI methods to generate emails with attachments.  Its been working for years without issue.  

I then got the request to support the 64-bit version of Outlook.  As a 32-bit application can't use MAPI for a 64-bit mail client I ended up creating a simple 64-bit executable that is launched from the 32-bit application.  

All was well, or so I thought, as my application could now send emails using both the 32-bit and 64-bit versions of Outlook Office 365.  As the months went on we started to get complaints from customers that the email feature was broken with Outlook 2013.  Groan!

Behavior

When attempting to call MAPI with Outlook 2013 as the default mail client, the MAPILogon method would fail with return code 3 (MAPI_E_LOGON_FAILURE/MAPI_E_LOGIN_FAILURE).  No logs or explanations that I could find.  After a lot of research and testing I finally found the root cause.

Calling MAPI on a background worker thread

When supporting the 64-bit Outlook, I decided to task off the operation because I'm impatient.

 Task.Run(() =>
            {
                if (!SendMail32(recipient, subject, body, attachments))
                {
                    SendMail64(recipient, subject, body, attachments);
                }
            });

The in process method, SendMail32, calls the MAPI methods directly and failed when Outlook 2013 was the default mail provider.  Removing the Task.Run resolved the issue for the 32-bit version of Outlook.  My theory is that the MAPI calls have to be made on the main UI thread so that the default mail profile can be found/used.  I don't know why this isn't an issue with Office 365.

Single threaded apartment model

Another thing I learned was that if you want to create a console application that can launch the email client with MAPI, you need to use the STAThread attribute, otherwise you get the same logon failure return code.

class Program
    {
        [STAThread]
        static int Main(string[] args)

Conclusion

This was a frustrating issue and I'm not sure why the latest version of Outlook doesn't need these changes but at least its working now.  Thankfully Outlook 2013 goes out of support in 2023 so that will be one less thing to worry about ;)

Thursday, March 5, 2020

freenas.local not working (can't ping or access web UI)

All of a sudden, http://freenas.local stopped working however, the IP address still worked.

ping would respond like this:

ping freenas.local

Pinging freenas.local [92.242.140.21] with 32 bytes of data:
Request timed out.
Request timed out.
Request timed out.
Request timed out.

What's that IP address? Nothing on my network...

tracert shows this:

tracert freenas.local

Tracing route to freenas.local [92.242.140.21]
over a maximum of 30 hops:

  1     1 ms     1 ms     1 ms  HughesRouter004 [10.190.87.249]
  2     1 ms     1 ms     1 ms  192.168.1.1
  3    14 ms     8 ms     8 ms  unallocated.barefruit.co.uk [92.242.140.21]


Apparently this is my ISP's (Verizon FIOS) DNS server doing this...

The fix:  I updated my router settings to use google's DNS servers 8.8.8.8 and 8.8.4.4

Wednesday, November 13, 2019

InstallShield Basic MSI missing Icon in Control Panel's "Programs and Features"

I ran into an issue when creating my latest Basic MSI installer project.  For some reason, my installer always showed the default Icon in the "Programs and Features" list.



The General configuration tab of the installer project has a simple setting to specify the icon to be displayed.



This can either be an ICO file or an EXE that contains an icon resource.

The specified icon is converted into the file ARPPRODUCTICON.exe that gets installed into "C:\Windows\Installer\{}" which is then used by the "Programs and Features" control panel.  Seems simple enough but didn't work.

It turns out, that InstallShield doesn't like spaces in the ICO file name.  Removed the spaces and normality was restored.

Friday, August 3, 2018

InstallShield prerequiste "Appears to have failed" but actually worked.

I've been developing some basic MSI installation setup.exe packages that I wanted to include in a parent installer using the built in prerequisite mechanism.

Easy enough, or so I thought
  1. Create the .prq with conditions and command lines
  2. Add the .prq files to the SetupPrerequites folder
  3. Add prerequisites to the parent install project
  4. Run!
Argh! The installation appears to have failed.  Continue with the installation?

But wait, the installation didn't fail.  In fact it hadn't even finished when the error occurs.

Hmm.

Turns out, the registry setting used in the condition didn't exist at the time that the outer installer checked the value to see if the prerequisite completed successfully.

But why?  Turns out the Setup.exe was returning before the MSI was finished.  OK.

lets use the /w option

/w
Basic MSI, InstallScript MSI
For a Basic MSI project, the /w option forces Setup.exe to wait until the installation is complete before exiting.
Note: If you are using the /w option in a batch file, you may want to precede the entire Setup.exe command-line option with start /WAIT. A properly formatted example of this usage is as follows:
start /WAIT setup.exe /w

Perfect!  Right? Nope :( still not waiting.

Now what?  Lets try /clone_wait.

InstallScript
This parameter indicates that the original setup should wait for the cloned setup process to complete before exiting.

But that doesn't apply to Basic MSI projects or does it.  At this point I'll try anything.

Guess what, it worked.  Now the prerequisites install as they should.

Command that worked, for me.
cmdline="/w /clone_wait /v/qr" cmdlinesilent="/w /clone_wait /vqr"

FYI:  I'm using InstallShield 2015.

Tuesday, May 9, 2017

Installshield IsCmdBld - ISDEV : fatal error -6199: Internal build error

So I've been using the InstallShield command line build utility with Jenkins successfully for many years now but hit a weird error today.

Historically I've used InstallScript MSI projects but decided to use the Basic MSI for my latest project as they seem to handle silent installs better (No answer file needed).  I created the project and configured Jenkins with a tried and trusted "Execute Windows batch" build step with a command similar to:

IsCmdBld.exe -p "%workspace%\MyInstaller.ism" -r "Default" -c COMP -a "Main" 

Only to be confronted with the generic error:
 
ISDEV : fatal error -6199: Internal build error


After some fruitless Google searches and some choice words I discovered that if the InstallShield project file was set to XML instead of the default "Binary" the error mysteriously went away. 

Hope that saves someone some time.

FYI:  Another tip I learned was to only allow one Jenkins executor to run on my installer build system.  If more than one ISCmdBld runs concurrently random errors occurred due to InstallShield fighting itself over shared files.

Friday, September 14, 2012

Running .Net 3.5 MSTest unit tests with Gallio.

Like all projects of a certain size there comes a time when there is a desire to have a dash board to quickly see the current state of affairs. 

For the dash board there is a growing open source solution called Sonar (http://www.sonarsource.org/) that is able to run all manner of plugins.  Perfect!

One of the supported plugins for .Net projects is another open source project called Gallio (http://www.gallio.org/).  Gallio has the ability to run all manner of unit test frameworks (MSTest, NUnit ,etc.) under a common API.  Nice!

One small gotcha:  Out of the box Gallio won't run .Net 3.5 unit test projects :(

The errors that were encountered were:

  • Mixed mode assembly is built against version 'v2.0.50727'
  • This method explicitly uses CAS policy, which has been obsoleted by ... please use the NetFx40_LegacySecurityPolicy configuration switch.
  • The plugin enable condition was not satisfied. Please note that this is the intended behavior for plugins that must be hosted inside third party applications in order to work. Enable condition: '${process:DEVENV.EXE} or ${process:VSTESTHOST.EXE} or ${process:QTAGENT.EXE} or ${process:QTAGENT32.EXE} or ${process:QTDCAGENT.EXE} or ${process:QTDCAGENT32.EXE} or {process:MSTEST.EXE}'
After much researching I found the solution.

Enable the 2008 Test Runner Plugin

By default the “Visual Studio 2008 Integration Shell” and “Visual Studio 2008 Test Runner plugin” are disable due to a failing prerequisite check.
To enable the plugins remove the “enableCondition” attribute and its value from the following files:

C:\Program Files\Gallio\bin\VisualStudio\v9.0\
  • Gallio.VisualStudio.Tip90.plugin
  • Gallio.VisualStudio.Shell90.plugin 

Enable Testing of unit tests authored in .Net 3.5

The command line utility “Gallio.Echo.exe” is a .Net 4.0 application that Sonar uses to run the unit tests.  This application needs to be configured to allow .Net 3.5 policies.

Update Gallio.Echo.exe.config to enable the testing of .Net 3.5 unit tests.

1).  Update the "runtime" configuration section to include the element: <NetFx40_LegacySecurityPolicy enabled="true"/>.
Example:
<runtime>
    <!-- Don't kill application on first uncaught exception.
         We don't want the test runner to terminate itself unexpectedly
         without reporting the test failure associated with that exception. -->
    <legacyUnhandledExceptionPolicy enabled="1" />

    <!-- Enable loading assemblies over the network in .Net 4.0 -->
    <loadFromRemoteSources enabled="true" />

    <NetFx40_LegacySecurityPolicy enabled="true"/>
  </runtime>

2).  Update the "startup" configuration section to include the attribute useLegacyV2RuntimeActivationPolicy="true"
Example:
<startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0.30319" />
    <supportedRuntime version="v2.0.50727" />
  </startup>

   
Now Sonar is running all of the unit test projects, providing test and code coverage reports.  Life is good!

Monday, December 19, 2011

Using Firebird ISQL to create embedded database files

ISQL is a command line tool that enables the execution of SQL statements either interactively or by input script file.

I was struggling to get ISQL to work with my Firebird Embedded database files until I stumbled upon a little nugget of information in one of my many google searches.

The problem was that ISQL wasn't using the embedded client! Doh!

The fix was simple! To get ISQL working the way I needed it to all I had to do was:
  • Copy isql.exe into the Firebird embedded directory.
  • Rename fbembed.dll to fbclient.dll
Now I can create and connect to embedded database files using the ISQL command line tool.

isql.exe" -q -i myDatabase.sql

where the file myDatabase.sql contains:
CREATE DATABASE 'TEST.FDB'
USER 'SYSDBA' PASSWORD 'masterkey'
PAGE_SIZE 8192
DEFAULT CHARACTER SET NONE;

CREATE ROLE RDB$ADMIN;

CREATE TABLE MYTABLE(
ID INTEGER NOT NULL,
NAME VARCHAR(500) NOT NULL
);

ALTER TABLE MYTABLE
ADD CONSTRAINT PK_MYTABLE_1
PRIMARY KEY (ID);

COMMIT;

Why did I want to do this?
My want was driven by a desire to have my build server create/modify database files for our product install. Treating the database creation scripts like code negates the need for a "Golden" database file that no one, other than myself, knows how to create.