Post by Fabio Siciliano on Aug 27, 2020 16:08:13 GMT -5
Hello Everybody,
Here I have a very big and troublesome mystery for you... I wrote a fully working sample program (see below) to send an email with attachments... the problem is (and I swear it is a very big nightmare for me because I worked on it very hard and usuccessfully for a week), if I use EXACTLY THE SAME CODE in a larger program, the MAPISendMail call fails with a simply terrifying "Runtime error: Protection Violation" message (a clue is that if no attachments are present, it works also in a larger program)!
Okay, below you can find my sample program, which alone works very fine.
And now, below you can find the error messages from the "error.log" file I get when using the above code as a part of a larger program:
BTW, my OS is Windows 10 Home, my mail client is Outlook of Microsoft Office 365 and my LB version is 4.5.1
Thank you in advance and best regards.
Fabio
Here I have a very big and troublesome mystery for you... I wrote a fully working sample program (see below) to send an email with attachments... the problem is (and I swear it is a very big nightmare for me because I worked on it very hard and usuccessfully for a week), if I use EXACTLY THE SAME CODE in a larger program, the MAPISendMail call fails with a simply terrifying "Runtime error: Protection Violation" message (a clue is that if no attachments are present, it works also in a larger program)!
Okay, below you can find my sample program, which alone works very fine.
nomainwin
dim hRecipNames(0) : dim hRecipAddresses(0)
dim hPathNames(0) : dim hFileNames(0)
global nul$, cr$, cr2$ : nul$ = chr$(0) : cr$ = chr$(13) : cr2$ = cr$; cr$
global appName$, appVerRel$, myApp$
appName$ = "mySendMailExample" : appVer = 1 : appRel = 0
appVerRel$ = str$(appVer) + "." + str$(appRel)
myApp$ = appName$ + " " + appVerRel$
global caption$ : caption$ = myApp$ + cr$
global supportLabel$ : supportLabel$ = "Ashtar Sheran (Private)"
global supportEmail$, supportEmailDefault$ : supportEmailDefault$ = "email@ashtarsheran.us"
global email.subject$, email.text$, email.recipients$, email.attachments$
'** MAPI CONSTANTS
global MAPI.ORIG, MAPI.TO, MAPI.CC, MAPI.BCC
MAPI.ORIG = 0 : MAPI.TO = 1 : MAPI.CC = 2 : MAPI.BCC = 3
global MAPI.LOGON.UI, MAPI.NEW.SESSION, MAPI.DIALOG, MAPI.USE.DEFAULT, MAPI.PASSWORD.UI
MAPI.LOGON.UI = hexdec("1") : MAPI.NEW.SESSION = hexdec("2") : MAPI.DIALOG = hexdec("8") : MAPI.USE.DEFAULT = hexdec("40") : MAPI.PASSWORD.UI = hexdec("20000")
'** MAPI Send Mail result values:
global _
SUCCESS.SUCCESS, MAPI.USER.ABORT, _
MAPI.E.FAILURE, MAPI.E.LOGIN.FAILURE, _
MAPI.E.DISK.FULL, MAPI.E.INSUFFICIENT.MEMORY, _
MAPI.E.ACCESS.DENIED, MAPI.E.TOO.MANY.SESSIONS, _
MAPI.E.TOO.MANY.FILES, MAPI.E.TOO.MANY.RECIPIENTS, _
MAPI.E.ATTACHMENT.NOT.FOUND, MAPI.E.ATTACHMENT.OPEN.FAILURE, _
MAPI.E.ATTACHMENT.WRITE.FAILURE, MAPI.E.UNKNOWN.RECIPIENT, _
MAPI.E.BAD.RECIPTYPE, MAPI.E.NO.MESSAGES, _
MAPI.E.INVALID.MESSAGE, MAPI.E.TEXT.TOO.LARGE, _
MAPI.E.INVALID.SESSION, MAPI.E.TYPE.NOT.SUPPORTED, _
MAPI.E.AMBIGUOUS.RECIPIENT, MAPI.E.MESSAGE.IN.USE, _
MAPI.E.NETWORK.FAILURE, MAPI.E.INVALID.EDITFIELDS, _
MAPI.E.INVALID.RECIPS, MAPI.E.NOT.SUPPORTED
SUCCESS.SUCCESS = 0 : MAPI.USER.ABORT = 1
MAPI.E.FAILURE = 2 : MAPI.E.LOGIN.FAILURE = 3
MAPI.E.DISK.FULL = 4 : MAPI.E.INSUFFICIENT.MEMORY = 5
MAPI.E.ACCESS.DENIED = 6 : MAPI.E.TOO.MANY.SESSIONS = 8
MAPI.E.TOO.MANY.FILES = 9 : MAPI.E.TOO.MANY.RECIPIENTS = 10
MAPI.E.ATTACHMENT.NOT.FOUND = 11 : MAPI.E.ATTACHMENT.OPEN.FAILURE = 12
MAPI.E.ATTACHMENT.WRITE.FAILURE = 13 : MAPI.E.UNKNOWN.RECIPIENT = 14
MAPI.E.BAD.RECIPTYPE = 15 : MAPI.E.NO.MESSAGES = 16
MAPI.E.INVALID.MESSAGE = 17 : MAPI.E.TEXT.TOO.LARGE = 18
MAPI.E.INVALID.SESSION = 19 : MAPI.E.TYPE.NOT.SUPPORTED = 20
MAPI.E.AMBIGUOUS.RECIPIENT = 21 : MAPI.E.MESSAGE.IN.USE = 22
MAPI.E.NETWORK.FAILURE = 23 : MAPI.E.INVALID.EDITFIELDS = 24
MAPI.E.INVALID.RECIPS = 25 : MAPI.E.NOT.SUPPORTED = 26
'** MAPI Structures:
struct MAPIRecip, _
Reserved as ulong, _
RecipClass as ulong, _
Name$ as char[4], _
Address$ as char[4], _
EIDSize as ulong, _
EntryID$ as ptr
struct NameS, Name$ as char[64]
struct AddressS, Address$ as char[254]
struct MAPIFile, _
Reserved as ulong, _
flags as ulong, _
Position as ulong, _
PathName$ as char[4], _
FileName$ as char[4], _
FileType$ as ptr
struct PathNameS, PathName$ as char[260]
struct FileNameS, FileName$ as char[257]
struct MAPIMessage, _
Reserved as ulong, _
Subject$ as ptr, _
NoteText$ as ptr, _
MessageType$ as ptr, _
DateReceived$ as ptr, _
ConversationID$ as ptr, _
flags as ulong, _
Originator as long, _
RecipCount as ulong, _
MAPIRecip as long, _
FileCount as long, _
MAPIFile as long
supportEmail$ = supportEmailDefault$ : reason = 1
if reason then
select case reason
case 1 : email.subject$ = myApp$ + " - BUG REPORT"
case 2 : email.subject$ = myApp$ + " - SUGGESTIONS"
case 3 : email.subject$ = myApp$ + " - OTHER"
end select
email.text$ = "WARNING: PLEASE, WRITE ME IN ENGLISH OR ITALIAN ONLY AND " _
; "DO NOT CHANGE THE SUBJECT OF THIS E-MAIL, THANK YOU."; cr2$ _
; "--- (WRITE YOUR MESSAGE BELOW) ---" _
; cr2$; cr2$ _
; "--- (END OF MESSAGE) ---"
email.recipients$ = "4;"; str$(MAPI.TO); ";"; supportLabel$; ";"; "SMTP:"; supportEmail$; ";" _
; str$(MAPI.CC); ";"; "PIPPO"; ";"; "SMTP:"; "pippus@topolinia.us"; ";" _
; str$(MAPI.CC); ";"; "PAPERINIK"; ";"; "SMTP:"; "paperinik@paperopoli.us"; ";" _
; str$(MAPI.BCC); ";"; "PLUTO"; ";"; "SMTP:"; "pluto@topolinia.us"
email.attachments$ = "4;"; DefaultDir$; "\AttachmentsToSend\myFrame.ini"; ";" _
; DefaultDir$; "\AttachmentsToSend\myFrame.rpt"; ";" _
; DefaultDir$; "\AttachmentsToSend\dummjerz.lng"; ";" _
; DefaultDir$; "\AttachmentsToSend\myFrame structs.txt"
call sendMail
end if
end
[sendMail]
sub sendMail
MAPIMessage.Subject$.struct = email.subject$; nul$
MAPIMessage.NoteText$.struct = email.text$; nul$
if email.recipients$ <> "" then
recipients = val(email.recipients$) : redim hRecipNames(recipients) : redim hRecipAddresses(recipients)
sizeofMAPIRecip = len(MAPIRecip.struct) ' size of the structure
memRecipBlockSize = recipients * sizeofMAPIRecip ' amount of memory needed
hRecipArray = GlobalAlloc(memRecipBlockSize) ' needed memory allocation (returns handler)
ptrRecipArray = GlobalLock(hRecipArray) ' pointer to the first byte (address) of the memory block
index = 0 : y = 0
for x = 1 to recipients
MAPIRecip.RecipClass.struct = val(word$(email.recipients$, (x + 1 + y), ";"))
NameS.Name$.struct = word$(email.recipients$, (x + 2 + y), ";")
size = len(NameS.struct) : h = GlobalAlloc(size) : dest = GlobalLock(h) : hRecipNames(x) = h
calldll #kernel32, "RtlMoveMemory", dest as long, NameS as ptr, size as long, r as void
MAPIRecip.Name$.struct = ptr2chr$(dest)
AddressS.Address$.struct = word$(email.recipients$, (x + 3 + y), ";")
size = len(AddressS.struct) : h = GlobalAlloc(size) : dest = GlobalLock(h) : hRecipAddresses(x) = h
calldll #kernel32, "RtlMoveMemory", dest as long, AddressS as ptr, size as long, r as void
MAPIRecip.Address$.struct = ptr2chr$(dest)
'********* calculate the destination as an offset from the first byte
size = sizeofMAPIRecip : dest = ptrRecipArray + (index * size)
'********* put the structure into memory:
calldll #kernel32, "RtlMoveMemory", dest as long, MAPIRecip as ptr, size as long, r as void
index = index + 1
y = y + 2
next
MAPIMessage.RecipCount.struct = index
MAPIMessage.MAPIRecip.struct = ptrRecipArray
end if
if email.attachments$ <> "" then
attachments = val(email.attachments$) : redim hPathNames(attachments) : redim hFileNames(attachments)
sizeofMAPIFile = len(MAPIFile.struct) ' size of the structure
memFileBlockSize = attachments * sizeofMAPIFile ' amount of memory needed
hFileArray = GlobalAlloc(memFileBlockSize) ' needed memory allocation (returns handler)
ptrFileArray = GlobalLock(hFileArray) ' pointer to the first byte (address) of the memory block
index = 0
for x = 1 to attachments
'********* BEWARE: this setting is mandatory! If you try to attach more than one attachment at the same position,
'********* the API MAPISendMail will fail!
MAPIFile.Position.struct = x
attachment$ = word$(email.attachments$, (x + 1), ";")
'--------> MSDN: "Pointer to the fully qualified path of the attached file. This path should include the disk drive letter and directory name."
PathNameS.PathName$.struct = attachment$
size = len(PathNameS.struct) : h = GlobalAlloc(size) : dest = GlobalLock(h) : hPathNames(x) = h
calldll #kernel32, "RtlMoveMemory", dest as long, PathNameS as ptr, size as long, r as void
MAPIFile.PathName$.struct = ptr2chr$(dest)
'--------> MSDN: "Pointer to the attachment filename seen by the recipient"
FileNameS.FileName$.struct = mid$(attachment$, (rinstr(attachment$, "\", 0) + 1))
size = len(FileNameS.struct) : h = GlobalAlloc(size) : dest = GlobalLock(h) : hFileNames(x) = h
calldll #kernel32, "RtlMoveMemory", dest as long, FileNameS as ptr, size as long, r as void
MAPIFile.FileName$.struct = ptr2chr$(dest)
'********* calculate the destination as an offset from the first byte
size = sizeofMAPIFile : dest = ptrFileArray + (index * size)
'********* put the structure into memory:
calldll #kernel32, "RtlMoveMemory", dest as long, MAPIFile as ptr, size as long, r as void
index = index + 1
next
MAPIMessage.FileCount.struct = index
MAPIMessage.MAPIFile.struct = ptrFileArray
end if
open "mapi32" for dll as #mapi32
flags = MAPI.USE.DEFAULT or MAPI.LOGON.UI or MAPI.NEW.SESSION or MAPI.DIALOG or MAPI.PASSWORD.UI
calldll #mapi32, "MAPISendMail", 0 as long, 0 as ulong, MAPIMessage as struct, flags as ulong, 0 as ulong, r as ulong
select case r
case SUCCESS.SUCCESS : error$ = "SUCCESS_SUCCESS"
case MAPI.USER.ABORT : error$ = "MAPI_USER_ABORT"
case MAPI.E.FAILURE : error$ = "MAPI_E_FAILURE"
case MAPI.E.LOGIN.FAILURE : error$ = "MAPI_E_LOGIN_FAILURE"
case MAPI.E.DISK.FULL : error$ = "MAPI_E_DISK_FULL"
case MAPI.E.INSUFFICIENT.MEMORY : error$ = "MAPI_E_INSUFFICIENT_MEMORY"
case MAPI.E.ACCESS.DENIED : error$ = "MAPI_E_ACCESS_DENIED"
case MAPI.E.TOO.MANY.SESSIONS : error$ = "MAPI_E_TOO_MANY_SESSIONS"
case MAPI.E.TOO.MANY.FILES : error$ = "MAPI_E_TOO_MANY_FILES"
case MAPI.E.TOO.MANY.RECIPIENTS : error$ = "MAPI_E_TOO_MANY_RECIPIENTS"
case MAPI.E.ATTACHMENT.NOT.FOUND : error$ = "MAPI_E_ATTACHMENT_NOT_FOUND"
case MAPI.E.ATTACHMENT.OPEN.FAILURE : error$ = "MAPI_E_ATTACHMENT_OPEN_FAILURE"
case MAPI.E.ATTACHMENT.WRITE.FAILURE : error$ = "MAPI_E_ATTACHMENT_WRITE_FAILURE"
case MAPI.E.UNKNOWN.RECIPIENT : error$ = "MAPI_E_UNKNOWN_RECIPIENT"
case MAPI.E.BAD.RECIPTYPE : error$ = "MAPI_E_BAD_RECIPTYPE"
case MAPI.E.NO.MESSAGES : error$ = "MAPI_E_NO_MESSAGES"
case MAPI.E.INVALID.MESSAGE : error$ = "MAPI_E_INVALID_MESSAGE"
case MAPI.E.TEXT.TOO.LARGE : error$ = "MAPI_E_TEXT_TOO_LARGE"
case MAPI.E.INVALID.SESSION : error$ = "MAPI_E_INVALID_SESSION"
case MAPI.E.TYPE.NOT.SUPPORTED : error$ = "MAPI_E_TYPE_NOT_SUPPORTED"
case MAPI.E.AMBIGUOUS.RECIPIENT : error$ = "MAPI_E_AMBIGUOUS_RECIPIENT"
case MAPI.E.MESSAGE.IN.USE : error$ = "MAPI_E_MESSAGE_IN_USE"
case MAPI.E.NETWORK.FAILURE : error$ = "MAPI_E_NETWORK_FAILURE"
case MAPI.E.INVALID.EDITFIELDS : error$ = "MAPI_E_INVALID_EDITFIELDS"
case MAPI.E.INVALID.RECIPS : error$ = "MAPI_E_INVALID_RECIPS"
case MAPI.E.NOT.SUPPORTED : error$ = "MAPI_E_NOT_SUPPORTED"
end select
select case r
case SUCCESS.SUCCESS
message$ = ">>> "; translate$("e-Mail SENT SUCCESSFULLY"); " <<<"
case MAPI.USER.ABORT, MAPI.E.LOGIN.FAILURE
message$ = "*** "; translate$("ACTION CANCELLED"); " ***"
case else
translateAsIs = 1
message$ = translate$("ERROR: e-Mail not sent - MAPISendMail Return Code"); ": "; error$; " ("; str$(r); ")"
translateAsIs = 0
end select
notice caption$ + message$
close #mapi32
'** call this for every memory block allocated. Use the appropriate memory handle.
for x = 1 to recipients
r = GlobalFree(hRecipNames(x)) : r = GlobalFree(hRecipAddresses(x))
next x
for x = 1 to attachments
r = GlobalFree(hPathNames(x)) : r = GlobalFree(hFileNames(x))
next x
r = GlobalFree(hRecipArray) : r = GlobalFree(hFileArray)
end sub
function GlobalAlloc(dwBytes)
'** returns the handle of the newly allocated memory object.
'** the return value is NULL if fail.
calldll #kernel32, "GlobalAlloc", _GMEM_MOVEABLE as long, dwBytes as ulong, GlobalAlloc as long
end function
function GlobalLock(hMem)
'** returns a pointer to the first byte of the memory block.
'** the return value is NULL if fail.
calldll #kernel32, "GlobalLock", hMem as long, GlobalLock as long
end function
function GlobalFree(hMem)
calldll #kernel32, "GlobalFree", hMem as long, GlobalFree as long
end function
function ptr2chr$(ptr)
dec = ptr : bin = bin(dec) : bin$ = str$(bin) : bin$ = fillZeroLeft$(bin$,32)
for x = 1 to 32
if x mod 8 = 0 then
y = x - 7 : z = x / 8 : byte(z) = val(mid$(bin$,y,8))
end if
next
for x = 1 to 4
byte = byte(x) : asciiDec = dec(byte) : char$ = chr$(asciiDec)
string$ = char$ + string$ ' (*) see below!
next
ptr2chr$ = string$
' (*) Pointers MUST be saved as BIG ENDIAN (reversed numbers) otherwise will be unreadable as strings starting with NULL;
' example: decimal pointer 12345678 --> binary 00000000101111000110000101001110 --> ascii 0 188 97 78 --> hex 00 BC 61 4E;
' the resulting string must be saved as 4E 61 BC 00 otherwise it would be considered as an empty string due to the first NULL!
' Fabio Siciliano, 4/01/2009.
end function
function bin(n)
n = int(abs(n))
if n = 0 then exit function
b = 2 : m$ = "" : m$ = str$(n) : a$ = ""
i = 1
while i <> 0
i = int(n / b) : r = n - i * b
if r >= 10 then a$ = chr$(65 + (r - 10)) + a$ else a$ = str$(r) + a$
n = i
wend
bin = val(a$)
end function
function dec(n)
n$ = str$(n) : ln = len(n$) : exp = ln
for x = 1 to ln
exp = exp - 1 : dec = dec + (val(mid$(n$,x,1)) * (2 ^ exp))
next
end function
function fillZeroLeft$(n$, l)
ln = len(n$)
if ln < l then
z = l - ln
for x = 1 to z
n$ = "0" + n$
next
end if
fillZeroLeft$ = n$
end function
function rinstr(a$, b$, n)
y = len(a$)
if n then y = y - (n - 1)
l = len(b$)
for x = y to 1 step -1
if mid$(a$, x, l) = b$ then exit for
next
rinstr = x
end function
function translate$(text$)
translate$ = text$
end function
And now, below you can find the error messages from the "error.log" file I get when using the above code as a part of a larger program:
Error log timestamp Thursday 27/08/20 22:23:50
Runtime error: Protection Violation
Error(Exception)>>defaultAction
Error(Exception)>>activateHandler: <anUndefinedObject>
Error(Exception)>>handle
Error(Exception)>>signal
Error class(Exception class)>>signal: <'Protection Violation'>
BasicProgram(Object)>>error: <'Protection Violation'>
BasicProgram>>terminateRun: <anError>
[] in BasicProgram>>errorHandlerBlock
ExceptionHandler>>evaluateResponseBlock: <aBlockClosure> for: <anError>
[] in ExceptionHandler>>handle:
ProtectedFrameMarker(BlockClosure)>>setUnwind: <aBlockClosure>
BlockClosure>>invisibleEnsure: <aBlockClosure>
ExceptionHandler>>handle: <anError>
ExceptionHandler>>findHandler: <anError>
Error(Exception)>>activateHandler: <anExceptionHandler>
Error(Exception)>>handle
Error(Exception)>>signal
Error class(Exception class)>>signal: <'Protection Violation'>
Process class(Object)>>error: <'Protection Violation'>
Process class>>protectionViolationInterrupt
Process class(Object)>>perform: <'protectionViolationI...'>
BasicProgram(Object)>>vmInterrupt: <'protectionViolationI...'>
BasicProgram(Object)>>error: <'Dynamic Link Library...'>
DynamicLinkLibrary class>>program: <aBasicProgram> primitiveCall: <aDynamicLinkLibrary> proc: <'MAPISendMail '> arguments: <anArray> types: <anArray> returns: <11>
DynamicLinkLibrary>>program: <aBasicProgram> call: <'MAPISendMail'> arguments: <anArray> types: <anArray> returns: <#ulongReturn>
CalldllCommand>>value
[] in BasicProgram>>begin
ExceptionHandler>>evaluateProtectedBlock: <aBlockClosure>
[] in ExceptionHandler>>activateDuring:
ProtectedFrameMarker(BlockClosure)>>setUnwind: <aBlockClosure>
BlockClosure>>invisibleEnsure: <aBlockClosure>
ExceptionHandler>>activateDuring: <aBlockClosure>
ExceptionHandler class>>handle: <anError class> with: <aBlockClosure> during: <aBlockClosure>
BlockClosure>>on: <anError class> do: <aBlockClosure>
BasicProgram>>begin
BasicProgram>>run
[] in BasicSourcePane>>run
BasicCompiler class>>compileFromString: <'''*******************...'> notify: <aBasicSourcePane> ifSuccess: <aBlockClosure>
BasicSourcePane>>run
BasicSourceWindow>>run
BasicEditorModel>>run: <aToolbarButton>
BasicEditorModel(Object)>>perform: <#run:> with: <aToolbarButton>
ToolbarButton>>triggerClickedEvent
Message>>perform
NotificationManager>>runPendingEvents
NotificationManager>>runEventLoop
Message>>perform
Message>>evaluate
Process>>safelyEvaluate: <aMessage>
Process>>evaluate: <aMessage>
BTW, my OS is Windows 10 Home, my mail client is Outlook of Microsoft Office 365 and my LB version is 4.5.1
Thank you in advance and best regards.
Fabio