Friday, 20 January 2012

MFC "encountered an improper argument" message

Hi there,

The story:

My MFC application "Schedule" that I work in 2 years ago faced by a very strange bug, the application is built using VC++, VS2008 on vista platform and configured to target vista platform by assigning WINVER=0x0600, _WIN32_WINNT=0x0600, _WIN32_WINDOWS=0x0410.

It runs perfectly on whatever machine running WinXP/Vista, other O.S.s are not available to test on. An overseas customer claimed a bug when she tried to save documents, her machine was HP-dv6000 with WinXP installed. I tolled her to upgrade the machine up to WinXP-SP3, but she upgraded up to Windows7 and the bug still exist.

The Bug is such a message says "encountered an improper argument", it emerged when she tried to save/open a file.

I googled every where but nobody has solution or a resolution, even in 2009 Microsoft tolled somebody that this issue is solved in VS2010, others talk about resource conflictions according to windows upgrades.

After long time I decided to investigate, where I spent 12 hours of digging into MFC source code and files, and then discovered the problem.

It was the following statement that throws exception because of an invalided resource ID.

ENSURE(title.LoadString(nIDSTitle = bReplace ? AFX_IDS_SAVEFILE : AFX_IDS_SAVEFILECOPY));

"title" is a CString object that has to displayed in title bar of CFileDialog, it then be loaded first from a string resource AFX_IDS_SAVEFILE or AFX_IDS_SAVEFILECOPY which are not exist at the machine of the customer.

I successfully simulated the same bug on my own machine using the following lines of code.

CString temp;

ENSURE(temp.LoadString(0xF012));// 0xF012 is invalide

What is ENSURE()?

#define ENSURE(cond) ENSURE_THROW(cond, ::AfxThrowInvalidArgException() )

The following paragraph describes what is the macro ENSURE, I cut this paragraph from MSN and past it here.

The purpose of these macros is to improve the validation of parameters. The macros prevent further processing of incorrect parameters in your code. Unlike the ASSERT macros, the ENSURE macros throw an exception in addition to generating an assertion.

The macros behave in two ways, according to the project configuration. The macros call ASSERT and then throw an exception if the assertion fails. Thus, in Debug configurations (that is, where _DEBUG is defined) the macros produce an assertion and exception while in Release configurations, the macros produce only the exception (ASSERT does not evaluate the expression in Release configurations).

The macro ENSURE_ARG acts like the ENSURE macro.

To solve this bug I made two steps, First: I replaced CWinAPP::OnFileOpen using the following code:

//---------------------------------------------------------------------

void CScheduleApp::OnMyFileOpen()

{

//manual open using CFileDialog

CString strDocFileName = _T("");

CFileDialog *pDlg;

pDlg = new CFileDialog (TRUE,_T("yps"),strDocFileName,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,

_T("File (*.yps)|*.yps|All Files (*.*)|*.*||"),NULL);

//

m_strCurFolder = m_strCurFolder.IsEmpty() ? GetParentFolder():m_strCurFolder;

pDlg->m_ofn.lpstrInitialDir = m_strCurFolder.GetBuffer(MAX_PATH);

pDlg->m_ofn.lpstrTitle = _T("فتح");

if(pDlg->DoModal()==IDOK)

{

strDocFileName = pDlg->GetPathName();

//the next line is optained from the following mfc source file

//C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\docmgr.cpp

AfxGetApp()->OpenDocumentFile(strDocFileName);

}

m_strCurFolder.ReleaseBuffer();

delete pDlg;

//Keep track of obtained folder as default for next open operation

m_strCurFolder = strDocFileName.IsEmpty() ? m_strCurFolder:

(strDocFileName.IsEmpty() ? _T(""):strDocFileName.Left(strDocFileName.ReverseFind('\\')+1));

//AfxMessageBox(m_strCurFolder);

theApp.WriteString(_T("CurUserFolder"),m_strCurFolder);

}

//---------------------------------------------------------------------

Second: I override CDocumment::DoSave() funtion to prevent it from calling AfxGetApp()->DoPromptFileName that uses the buggy resource, here is the code:

//---------------------------------------------------------------------

BOOL CScheduleDoc::DoSave(LPCTSTR lpszPathName, BOOL bReplace)

{

CString newName = lpszPathName;

if (newName.IsEmpty())

{

CDocTemplate* pTemplate = GetDocTemplate();

ASSERT(pTemplate != NULL);

newName = m_strPathName;

if (bReplace && newName.IsEmpty())

{

newName = m_strTitle;

// check for dubious filename

int iBad = newName.FindOneOf(_T(":/\\"));

if (iBad != -1)

newName.ReleaseBuffer(iBad);

// append the default suffix if there is one

CString strExt;

if (pTemplate->GetDocString(strExt, CDocTemplate::filterExt) &&

!strExt.IsEmpty())

{

ASSERT(strExt[0] == '.');

int iStart = 0;

newName += strExt.Tokenize(_T(";"), iStart);

}

}

//Replace the bug lines with a new technique

//if (!AfxGetApp()->DoPromptFileName(newName,

// bReplace ? AFX_IDS_SAVEFILE : AFX_IDS_SAVEFILECOPY,

// OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, FALSE, pTemplate))

// return FALSE; // don't even attempt to save

if(!MyDoPromptFileName(newName,bReplace))

return false;

}

CWaitCursor wait;

if (!OnSaveDocument(newName))

{

if (lpszPathName == NULL)

{

// be sure to delete the file

TRY

{

CFile::Remove(newName);

}

CATCH_ALL(e)

{

//the normal place for the following Macro is in mfc\stdafx.h

//I bring it here becuase it is used only here and I have no plan to use it anywhere

#define DELETE_EXCEPTION(e) do { if(e) { e->Delete(); } } while (0)

//

TRACE(traceAppMsg, 0, "Warning: failed to delete file after failed SaveAs.\n");

DELETE_EXCEPTION(e);

}

END_CATCH_ALL

}

return FALSE;

}

// reset the title and change the document name

if (bReplace)

SetPathName(newName);

return TRUE; // success

}

BOOL CScheduleDoc::MyDoPromptFileName(CString& fileName, bool bReplace)

{

CFileDialog *pDlg;

pDlg = new CFileDialog (FALSE,_T("yps"),fileName,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,

_T("Timetable File (*.yps)|*.yps|All Files (*.*)|*.*||"),NULL);

CString title = bReplace ? _T("حفظ جدول الحصص"):_T("حفظ جدول الحصص في ملف آخر");

pDlg->m_ofn.lpstrTitle = title;

if(pDlg->DoModal()!=IDOK)

return FALSE;

fileName=pDlg->GetPathName();

return TRUE;

}

//---------------------------------------------------------------------

Thursday, 30 June 2011

C# access webservice from behind proxy

I was trying to use C# .NET desktop application to access a webservice from my office, the web-service is behind a proxy firewall, I was annoyed by seeing the following error message

"- The request failed with HTTP status 407: Proxy Authentication Required"

By googling I found a solution that enables me to disable proxy "http://stackoverflow.com/questions/2131933/http-407-proxy-authentication-error-when-calling-a-web-service"

To disable the proxy, in the App.config file add the following configuration

<system.net>
<defaultProxy enabled="false" useDefaultCredentials="false">
<proxy/>
<bypasslist/>
<module/>
</defaultProxy>
</system.net>

To enable the proxy and to use the default proxy settings(specified in IE) add this configuration in your App.config

<system.net>
<defaultProxy enabled="true" useDefaultCredentials="true">
<proxy/>
<bypasslist/>
<module/>
</defaultProxy>
</system.net>

Monday, 30 May 2011

Godaddy Email problem with hosted applications

My web application hosted on Godaddy can't send email messages after being uploaded there. But it works normally and can send email messages from my local machine. I tried many variations for SMTP configuration as follows but no-way for success:

1- This configuration is working from my local machine

· SMTP: smtp.mydomain.com

· Port: 25

· SSL: not enabled

· user: webmaster@mydomain.com

· password: **********

2- This configuration is not working

· SMTP: smtpout.secureserver.net

· Port: 25 or 80 or 3535 or 587

· SSL: not enabled

· Cedential user: webmaster@mydomain.com

· Cedential password: **********

3- This configuration is not working

· SMTP: smtp.secureserver.net

· Port: 25 or 80 or 3535 or 587

· SSL: not enabled

· Cedential user: webmaster@mydomain.com

· Cedential password: **********

I found the solution, and it was so old problem, since 2005, I found it in the following link:

http://forums.asp.net/t/939893.aspx/1?Problem+with+System+Net+Mail+on+GoDaddy

The problem is that SMTP-server is not smtpout.secureserver.net as Godaddy tells me. But It is relay-hosting.secureserver.net that nobody tells me at all. There is no need for user name or password, relay is open for 1000 message per day for hosted applications.

jQuery simplemodal plugin typeError: 'tagName' is null or not an object.

Many thanks for Eric's effort he made to create the great simple modal jQuery plugin.

http://www.ericmmartin.com/projects/simplemodal-demos/

I found a bug then fixed it, the bug is in $.modal.impl.create function , I think it is not new for you, where you mentioned the solution when you commented to use 'form' instead 'body' for the property appendTo.

First: the comment have to be modified to become {use '#aspnetForm'} instead of {use 'form'}
Second: in line number 344, there is still hard coding problem of the word 'body', as follows.

// add styling and attributes to the data
// append to body to get correct dimensions, then move to wrap
s.d.data = data
.attr('id', data.attr('id') || s.o.dataId)
.addClass('simplemodal-data')
.css($.extend(s.o.dataCss, {
display: 'none'
}))
.appendTo('body');


I replaced the hard coded word with s.o.appendTo object such like {.appendTo(s.o.appendTo);}, and everything goes right.


Monday, 28 March 2011

Firefox problem with iframe

|
|..primery.aspx
|..rootpage.aspx
|..|-l1
     |-l2
       |-l3
         |..test.htm
|

I have HTML page (i.e. test.htm) in a website say (http://172.16.16.20), the page is deeply located into a 3rd level folder, to access the page you have to write the URL as follows (http:/172.16.16.20/l1/l2/l3/test.htm), test.htm has iframe element with src="/rootpage.aspx" like following:
..
<ifram src="/rootpage.aspx"></iframe>
..

The "rootpage.aspx" with another page named "primary.aspx" are located in the root folder of the website. And primary.aspx looks like the following:

...
<iframe src="/rootpage.aspx"></iframe>
...

If you open primery.aspx , it is normal to expect to see iframe of tset.htm that contain iframe of rootpage.aspx. That is true for all browsers except Firefox. Unfortunately, Firefox will give the following error:

The page cannot be displayed
You have attempted to execute a CGI, ISAPI, or other executable program from a directory that does not allow programs to be executed.
Please try the following:
* Contact the Web site administrator if you believe this directory should allow execute access.
HTTP Error 403.1 - Forbidden: Execute access is denied.
Internet Information Services (IIS)
Technical Information (for support personnel)

I go to IIS&gt;&gt;website&gt;&gt;Properties&gt;&gt;HomeDirectory&gt;&gt;ApplicationSettings&gt;&gt;ExecutePermissions and make it Scripts and Executables. After that Firefox gave me the next error:

Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /l1/l2/l3/rootpage.aspx
Version Information: Microsoft .NET Framework Version:2.0.50727.3053; ASP.NET Version:2.0.50727.3053

From the last error message I understand that Firefox iframe.src property behaves differently than other browsers, I put "/" in front of the page name to tell the browser to go to root folder, but Firefox believes that root is relative to iframe context not browser context.

To solve the problem I modifed src="/rootpage.aspx" to become src="../../../rootpage.aspx"

Now everything goes right.


Sunday, 26 December 2010

old "dbo" database owner prevents service broker from working properly - SQL 2005

I have cloned a virtual copy of Win2003 server that has SQL2005 already installed. The new server is planned to be disconnected from the domain of the original server and run separately.

 

In SQL2005 I dropped all databases and restored my database that has service broker already enabled, the restored database was running very well on another server inside my old domain "AWQAF", this database also has a notification service running on top of a message queue called "messageQueue".

 

Service broker then didn't working as supposed or as it should to work like.

 

I tried to check the status of the service broker using the following statement:

SELECT is_broker_enabled FROM sys.databases WHERE name = 'AfaqCMS';

 

It gives me 0 result, a mean of service broker is disabled.

 

So, I tried to enable service broker using the following statement:

ALTER DATABASE [AfaqCMS] SET NEW_BROKER WITH ROLLBACK IMMEDIATE;

 

By trying to SEND/RECIVE messages using the following statements, I got dialog created without messages transmission:

DECLARE @NotificationDialog uniqueidentifier;

SET QUOTED_IDENTIFIER ON;

BEGIN DIALOG CONVERSATION @NotificationDialog

FROM SERVICE ChangeNotifications

TO SERVICE 'ChangeNotifications'

ON CONTRACT [http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]

WITH ENCRYPTION = OFF;

SEND

ON CONVERSATION @NotificationDialog

MESSAGE TYPE [http://schemas.microsoft.com/SQL/Notifications/QueryNotification] (N'CommentHits');

SELECT @NotificationDialog;

RECEIVE * FROM ChangeMessagesQueue ;

 

By checking transmission queue of the system I found some errors around the original owner of the restored database.

SELECT * FROM sys.transmission_queue

 

A filed called "transmission_status" is containing the following exception:

An exception occurred while enqueueing a message in the target queue.

Error: 15404, State: 11.

Could not obtain information about Windows NT group/user 'AWQAF\adm_walghool', error code 0x534.

 

By deleting 'AWQAF\adm_walghool' from all locations it can be existed in, I got another status:

An exception occurred while enqueueing a message in the target queue.

Error: 15517, State: 1.

Cannot execute as the database principal because the principal "dbo" does not exist,

this type of principal cannot be impersonated, or you do not have permission.

 

Now I realized that it is the database owner that prevents service broker from working properly, So I run the following statement to get every things working successfully again:

ALTER AUTHORIZATION ON DATABASE::[AfaqCMS] TO [SA]

 

Anthother statement can be used also:

 

USE AfaqCMS

GO

EXEC dbo.sp_changedbowner @loginame = N'zakauser', @map = false

 

 

 

 

Monday, 2 August 2010

What is the difference between ISO 9660, Joliet and UDF?

CD-ROM File Systems

An ISO 9660 file system is a standard CD-ROM file system. Full ISO format requires all upper case characters or numbers, no spaces, very limited special characters, and no more than 30 characters in the name.

Joliet is the name of an extension to the ISO 9660 file system. Joliet format permits 64-character file names with lower-case alpha and other relaxed restrictions. It also relaxes the ISO requirement for directory nesting to no more than eight levels. It doesn't hurt to include the Joliet Directory if the names conform.

UDF is a hybrid filesystem that uses both UDF and ISO 9660. Also called a UDF bridge, it was commonly used until Microsoft incorporated support for UDF in its operating system. UDF permits 127 16-bit Unicode characters, or 254 8-bit Unicode characters. If any character in any name is not in the list of legal 8-bit Unicode characters, all names will be represented in 16-bit Unicode.

However Joliet is no longer needed since the ISO 9660 standard has been extended in 3 different levels:
Level 1: Filename cannot be longer than 8 chars , Filename extention cannot be longer than 3 chars.
Level 2: Filename can be up to 255 chars long.
Level 3: Same as level 2 but files can be written in multiple extents (-> Packet writing).


Normally a Mac can read both ISO 9660 and Joliet CDs.