1. Christopher Craft
  2. PowerBuilder
  3. Wednesday, 24 May 2023 17:16 PM UTC

PB 2022 1900

We recently changed our email from MAPI to OLE in order to support the 64-bit outlook with our 32-bit PB application.  This works great but I am now trying to figure out how I might be able to support the drag and drop email feature from Arthur ( https://www.catsoft.ch/#download ) which requires the bitness to be the same. I know one option would be to compile a 64-bit version of our application but this will require a lot of testing as well as we would need to make sure any other 3rd party software we use has a 64-bit version too. 

Is there a way to do this using something else in order to support this?

And as an important side note - the 'New Outlook' (beta) version does not support drag and drop at all. MS says they plan to support it but who knows when that will be.

Chris Craft

Who is viewing this page
Accepted Answer
Christopher Craft Accepted Answer Pending Moderation
  1. Monday, 31 July 2023 21:55 PM UTC
  2. PowerBuilder
  3. # Permalink

Thank you Miguel for sharing your code that allowed me to come up with what I needed.  And thank you Arthur for always responding to my questions regarding your DLL that made this all possible.

This solution uses Outlook OLE and RegisterDropTargetInfo from dddll.dll.  This approach will tell the DLL to only send a notification that emails were dropped.  Once notified it then uses OLE to grab all the selected email items and processes them. This solution works for 32 or 64 bit environments.

Anyway, I attached a modified PBL with my changes (PB 2022 1900). I didn't include the DLL. Please visit About Us - CATsoft Development GmbH and download his Drag and Drop example to get it.  I hope it helps someone down the road.

Thanks again Arthur and Miguel - you guys are great!

Chris Craft

Attachments (1)
Comment
  1. Miguel Leeuwe
  2. Tuesday, 1 August 2023 02:24 AM UTC
So glad you got it working as digging through my code wasn't easy !

Thanks also for the sample application. it would look really good on CodeXchange :)

regards.
  1. Helpful
  1. Christopher Craft
  2. Tuesday, 1 August 2023 20:58 PM UTC
That is a good idea Miguel - I probably need to get Arthurs approval though to include his DLL.
  1. Helpful 1
  1. Miguel Leeuwe
  2. Tuesday, 1 August 2023 21:40 PM UTC
Just ask him. There should a contact form on the catsoft web site if I remember well. I don't think he'll mind, as it's good advertisement for Catsoft!

regards
  1. Helpful
There are no comments made yet.
Miguel Leeuwe Accepted Answer Pending Moderation
  1. Wednesday, 24 May 2023 18:20 PM UTC
  2. PowerBuilder
  3. # 1

Here's my code in the u_dw Other() event:

 

CHOOSE CASE message.number
	CASE WM_MOUSEWHEEL
		// v1 and v2, mjl, 13/04/20: Since win8 and w10 totally ignore the mouse settings when working remotely, I've re-introduced the code to scroll:
		// First check the user isn't "zooming" by using CTRL+mouseWheel:
		IF KeyDown( keyControl!) then
			RETURN 0
		END IF
		// v1 and v2, mjl, 19/05/20: shouldn't scroll when there's only one row:
		if this.rowcount() = 1 then
			message.processed = true // has to be the last command before doing the RETURN 0
			RETURN 0
		end if

		CONSTANT uint SPI_GETWHEELSCROLLLINES = 104
		CONSTANT Long WM_VSCROLL = 277
		CONSTANT Long SB_LINEDOWN = 1
		CONSTANT Long SB_LINEUP = 0
		
		int li_WheelMouseLine, li_index
		int li_lines

		// Function boolean SystemParametersInfoW(uint wActon, uint wParam, REF int pvParam, uint fUpdateProfile) Library "USER32.DLL"
		SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, ref li_WheelMouseLine, 0)
		li_lines = IntHigh(wParam) / 120
		this.SetRedraw(false)
		IF li_lines > 0 THEN
			FOR li_index = 1 TO li_WheelMouseLine
				Send(Handle(THIS), WM_VSCROLL, SB_LINEUP,0)
			NEXT
		ELSE
			FOR li_index = 1 TO li_WheelMouseLine
				Send(Handle(THIS), WM_VSCROLL, SB_LINEDOWN,0)
			NEXT
		END IF
		this.SetRedraw(true) // has to be before setting message.processed = true, if not it makes the message.processed = true to NOT work
		message.processed = true // has to be the last command before doing the RETURN 0
		RETURN 0
END CHOOSE


CHOOSE CASE wparam
	
	CASE WM_OUTLOOK_DROP // email dropped from Outlook?

		// ib_nOther is being set in key event:
		if ib_noOther then
			post setpointer(arrow!)
			message.processed = true
			return 0
		end if

		if not ib_allowDropFromExplorer then
			return 0
		end if

		// avoid reminders to popup during this process:
		// we will assign is_openWindow only if it's not already being set by some other window, or this same window previously:
		boolean lb_reset
		if gnv_app.is_open_responseWindow = "" then
			lb_reset = true
			gnv_app.is_open_responsewindow = this.classname()
		end if
		
		// if this is the first file dropped, we get a count of selected emails in Outlook (and set the application to front)
		if iul_dropped_files = 0 then 
			// it's the first file being dropped:
			// bring the application to front
			n_funcs lnv
			lnv.POST of_application_to_front()

			// use ole to determine the number of selected files:
			try
				oleobject lole_outlook_app
				lole_outlook_app = create oleobject
				setpointer(hourglass!)
				If lole_outlook_app.ConnectToNewObject("Outlook.Application") <> 0 Then
					gnv_app.inv_error.of_Message( "cannot_log_onto_mail" ) 
					gnv_app.of_debug("Outlook: cannot connect to outlook.application - constructor")
					if lb_reset then
						gnv_app.is_open_responseWindow = ""
					end if
					return  0 // v2, mjl, 07/07/20: instead of return without a value
				End If
				il_selected_outlook_count = lole_outlook_app.ActiveExplorer.Selection.Count

				string ls_dir, ls_renamedDir
				
				if gnv_app.ii_officeBitness = 64 then
					// v3, mjl, 25/05/21: due to office 64 bit issues we now use OLE to get the selected emails:
					// store all of the dropped / selected files:
					oleobject lole_item, lole_saveAs, lole_nameSpace
					//string ls_body, ls_msg, ls_from, ls_to, ls_cc, ls_bcc, ls_name
					string ls_subject, ls_fName, ls_entryID, is_empty[]
					int li_rc
					ulong ll_i
					
					this.is_dropped_fileGUIDS = is_empty
					
					FOR ll_i = 1 to il_selected_outlook_count
						lole_item = lole_outlook_app.ActiveExplorer.Selection.item(ll_i)
						li_rc = lole_item.class
//						datetime ldtdate
	
						CHOOSE CASE li_rc
	//						CASE 26 //appointment
	//							ls_body = lole_item.body
	//							ls_msg += '~r~n Appointment No: ' + string(ll_i) + ' of ' + string(il_selected_outlook_count) + '~r~n' + ls_body
	//							// lots of other stuff could be here
	//						CASE 40 // contact
	//							ls_body = lole_item.body
	//							ls_msg += '~r~n Contact No: ' + string(ll_i) + ' of ' + string(il_selected_outlook_count) + '~r~n' + ls_body
	
							CASE 43 // mail
								is_dropped_fileGUIDS[ll_i] = lole_item.EntryID
								// we will only reset if is_openWindow was not already some other window
								if lb_reset then
									gnv_app.is_open_responseWindow = ""
								end if
								  
	//						CASE 48 // task
	//							ls_subject = lole_item.subject
	//							ls_to = lole_item.owner
	//							ls_body = lole_item.body
	//							ls_msg = '~r~nSubject: ' + ls_subject + '~r~nOwner: ' + ls_to + '~r~nBody: ' + ls_body
	//							ls_msg += '~r~n Task No: ' + string(ll_i) + ' of ' + string(il_selected_outlook_count) + '~r~n' + ls_msg
								
						END CHOOSE
						if isvalid(lole_item) then
							DESTROY lole_item
						end if
					NEXT
				end if
				
			catch ( runtimeError runtErro)
				// do nothing
				if isvalid(lole_outlook_app) then
					lole_outlook_app.disconnectobject( )
					destroy lole_outlook_app
					if lb_reset then
						gnv_app.is_open_responseWindow = ""
					end if
					return 0
				end if
			finally
				if isvalid(lole_outlook_app) then
					lole_outlook_app.disconnectobject()
					destroy lole_outlook_app
				end if
			end try
			
		end if
		
		if gnv_app.ii_officeBitness = 32 then
			// Called when email Messages are dropped
			string			ls_Message, ls_Files, ls_Header
			string			ls_Pre, ls_fileName
			s_finddata	lstr_FindData
			integer		li_Pos
			long			ll_Handle
			
			setpointer(hourglass!)
			
			ls_Message = String( lparam, "address" )
			li_Pos = Pos( ls_Message, "~r~n" )
			IF li_Pos > 0 THEN
				//ls_Header = Mid( ls_Message, li_Pos + 2 )
				ls_Message = Left( ls_Message, li_Pos - 1 )
				//ls_Header = "~r~nHeader:~r~n" + ls_Header
			END IF
			
			ls_Pre = Left( ls_Message, LastPos( ls_Message, "." ) - 1)
			ls_Dir = Left( ls_Message, LastPos( ls_Message, "\" ) - 1)
			
			// Check whether there are attachments available
			ll_Handle = inv_platform.FindFirstFile(ls_Pre + "*.*", lstr_FindData)
			If ll_Handle < 1 Then 
				if lb_reset then
					gnv_app.is_open_responseWindow = ""
				end if
				message.processed = true
				Return 0
			end if
		end if
		
		iul_dropped_files ++
		
		if gnv_app.ii_officeBitness = 32 then
			Do
				//ls_Files = ls_Files + "~r~n" + lstr_FindData.ch_filename
				ls_fileName = lstr_FindData.ch_filename
				if lower(right(ls_fileName, 4)) = ".msg" then
					exit
				end if
			Loop Until Not  inv_platform.FindNextFile(ll_Handle, lstr_FindData)
			inv_platform.FindClose(ll_Handle)
	
			ls_renamedDir = ls_dir + "-"+ string(iul_dropped_files)
			
			// we might have to shorten the filename before renaming the folder
			if len(ls_renamedDir + "\" + ls_filename) > 255 then
				int li_chopOff
				string ls_newFileName
				li_chopOff = len(ls_renamedDir + "\" + ls_filename) - 255 + 4 // plus 4 to cut off ".msg"
				ls_newFileName = mid(ls_fileName, 1, len(ls_fileName) - li_chopOff) + ".msg"
				if fileMove(ls_dir + "\" + ls_fileName, ls_dir + "\" + ls_newFileName) <> 1 then
					if lb_reset then
						gnv_app.is_open_responseWindow = ""
					end if
					message.processed = true
					return -1
				end if
				ls_fileName = ls_newFileName
			end if
			
			// rename the folder:
			if filemove(ls_dir, ls_renamedDir) <> 1 then
				if lb_reset then
					gnv_app.is_open_responseWindow = ""
				end if
				message.processed = true
				return 0
			end if
			is_dropped_fileNames[iul_dropped_files] = ls_renamedDir + "\"  + ls_fileName
		end if
		
		// we will only reset if is_openWindow was not already some other window
		if lb_reset then
			gnv_app.is_open_responseWindow = ""
		end if

		if gnv_app.ii_officeBitness = 32 then
			// the folder will be deleted in ue_postdropOutlookFiles
			is_delete_directories[iul_dropped_files] = ls_renamedDir
		end if
		
		if iul_dropped_files = il_selected_outlook_count then
			// this was the last file selected in outlook
			this.event post ue_dropoutlookfiles( )
		end if
		
		setpointer(hourglass!)

//		post MessageBox( "Message dropped" , "Files located in " + ls_Dir + "~r~nFiles:" + ls_Files + ls_Header)
		RETURN 0
END CHOOSE

RETURN 0

Some things are not relevant to the current problem. Have a look at "ii_officeBitness". If you need more information you can contact me on LinkedIn (Miguel Leeuwe).

This code is just to give you an idea. "is_dropped_fileGUIDS" has been filled in the Other() event of the dw.

I have a nvo to deal with the dropped files which has a function "of_dropped_outlookFiles()":

// adw
// as_notetype
// as_customer
long ll_i, ll_max
boolean lb_reset
n_filesys ln_fsys
int li_file_len

// avoid reminders to popup during this process:
// we will assign is_openWindow only if it's not already being set by some other window, or this same window previously:
if gnv_app.is_open_responseWindow = "" then
	gnv_app.is_open_responseWindow = this.classname()
	lb_reset = true
end if
		
// only filled when gnv_app.ii_officeBitness = 64:
if Upperbound(adw.is_dropped_fileGUIDS) > 0 then
	

	// -------------------------------------------------------------------------------------------------------------------------------
	// dropping process has finished, we can now first delete all the drop.msg files that were saved by the dllddll.dll when on 64 bit:
	// -------------------------------------------------------------------------------------------------------------------------------
	// get the list of files and directories from the %temp% windows folder:
	string ls_name[], ls_archDir, ls_tempDir, ls_path, ls_fullname, ls_fileName, ls_filetype
	DateTime ldt_write[], ldt_modified
	Boolean lb_subdir[]
	Double ld_size[]
	long ll_filesize, ll_cnt, ll_sortType
	
	ls_tempDir = gnv_app.is_win_temp_dir
	ll_max = ln_fsys.of_getfiles(ls_tempDir, False, ls_name, ld_size, ldt_write, lb_subdir)
	If ll_max = -1 Then
		MessageBox("Error", "There is no disk in drive " + ls_tempDir, Exclamation!)
	Else
		For ll_cnt = 1 To ll_max
			If lb_subdir[ll_cnt] Then
				// it's a directory and what we are looking for:
				ll_sorttype = 0
				ll_filesize = 0
				ls_fullname = ls_tempDir + ls_name[ll_cnt]
				
				// check if it's a today's folder:
				if not left(ls_name[ll_cnt], 8) = string(today(), 'yyyymmdd') then
					continue
				end if
				
				// check if the folder contains a single file named "drop.msg", if so delete:
				string ls_name2[]
				boolean lb_subdir2[]
				DateTime ldt_write2[]
				Double ld_size2[]
				if ln_fsys.of_getfiles(ls_fullname, False, ls_name2, ld_size2, ldt_write2, lb_subdir2) = 1 then
					if not lb_subdir2[1] then
						// check if there's a single file called "drop.msg" in it:
						if not lower(ls_name2[1]) = "drop.msg" then
							continue
						end if
						// delete the folder and anything in it:
						if ln_fSys.of_delete_directory( ls_fullname ) = -1 then
							Messagebox("Error deleting temp folder", "Failed to delete the folder " + ls_fullname)
							return -1
						end if
					end if
				end if
			End If
		Next
	end if

	
	// ------------------------------------------------------------------------------------------------
	// now we need to generate all the CORRECT information from the stored GUIDS (see u_dw.other event):
	// ------------------------------------------------------------------------------------------------
	oleobject lole_item, lole_saveAs, lole_nameSpace
	//string ls_body, ls_msg, ls_from, ls_to, ls_cc, ls_bcc, ls_name
	string ls_subject, ls_fName, ls_entryID, is_empty[]
	int li_rc
	oleobject lole_outlook_app
	oleobject loleNameSpace
	try
		lole_outlook_app = create oleobject
		setpointer(hourglass!)
		If lole_outlook_app.ConnectToNewObject("Outlook.Application") <> 0 Then
			gnv_app.inv_error.of_Message( "cannot_log_onto_mail" ) 
			gnv_app.of_debug("Outlook: cannot connect to outlook.application - constructor")
			if lb_reset then
				gnv_app.is_open_responseWindow = ""
			end if
			return  -1 // v2, mjl, 07/07/20: instead of return without a value
		End If
		
		loleNameSpace = lole_outlook_app.GetNameSpace("MAPI")
		string ls_dir
		// store all of the dropped / selected files:
		FOR ll_i = 1 to Upperbound(adw.is_dropped_fileGUIDS)

			// v3, mjl, 25/05/21: due to office 64 bit issues we now use OLE to get the selected emails:
			lole_item = loleNameSpace.GetItemFromID(adw.is_dropped_fileGUIDS[ll_i])
			ls_subject = lole_item.subject
			if isnull(ls_subject) then ls_subject = ""
			ls_subject = trim(ls_subject)
			if ls_subject = "" then
				ls_subject = "Untitled" // same as when on 32 bit
			end if
			ls_dir = gnv_app.is_win_temp_dir + string(today(), 'yyyymmddhhmmssfff') + '-' + string(ll_i) // 2021/05/26 08:35:43.0042-1 
			if not directoryExists(ls_dir) then
				createDirectory(ls_dir)
			end if
	
			//file names cannot contain any of these characters: |\/:*?"<>
			// W1, mjl, 24/03/23: we now have a function to replace the invalid characters:
			f_replaceInvalidCharactersFileName(ref ls_subject, "_")
			
			// check how many characters are left for the subject before reaching windows max. length of 255:
			// (in reality the limit would be 260 (unless you're on a very old windows, but table field is limited to 255 anyway).
			if len(ls_Dir + "\" + ls_subject + ".msg") > 255 then
				li_file_len = 255 - len(ls_Dir + "\" + ".msg")
				ls_subject = mid(ls_subject, 1, li_file_len)
			end if
			
			ls_fName = ls_Dir + "\" + ls_subject + ".msg"
	
			lole_item.SaveAs(ls_fName, 3) // iolMsg = 3
			
			adw.is_dropped_fileNames[ll_i] = ls_fName
			adw.is_delete_directories[ll_i] = ls_Dir

		NEXT
			
	catch ( runtimeError runtErro)
		// do nothing
		if isvalid(lole_outlook_app) then
			lole_outlook_app.disconnectobject( )
			destroy lole_outlook_app
			if lb_reset then
				gnv_app.is_open_responseWindow = ""
			end if
			return -1
		end if
	finally
		lole_outlook_app.disconnectobject( )
		if isvalid(lole_item) then
			destroy lole_item
		end if
		if isvalid(loleNameSpace) then
			destroy loleNameSpace
		end if
		destroy lole_outlook_app
	end try
	
end if

// v2, mjl, 20/04/20:
string ls_errors[], ls_note
string ls_item_id, ls_customer, ls_destination, ls_file
long ll_selectedRows[], ll_maxRows, ll_oleref_id[]
integer li_ret 

ll_maxRows = adw.of_getselectedrownumbers(ref ll_selectedRows)
if ll_maxRows = 0 then
	adw.event POST ue_postDropFiles()	
	//messagebox('Information', 'You have to select at least one row', information!)
	// v5, mjl, use w_message instead of messagebox(), so the window will be brought to front:
	gnv_app.inv_error.of_setstyle(gnv_app.inv_error.PFCWINDOW)
	gnv_app.inv_error.of_message('select_at_least_one_row')
	gnv_app.inv_error.of_setstyle(gnv_app.inv_error.DEFAULT)
	if lb_reset then
		gnv_app.is_open_responseWindow = ""
	end if
	return 0
end if

if as_noteType <> 'QN' then // only if it's not a query note:
	w_master lw
	adw.of_getParentWindow(lw)
	Open(w_select_attach_category, lw)
	is_attach_type = message.stringparm
	if is_attach_type = '[cancelled]' then
		adw.event POST ue_postDropFiles()
		if lb_reset then
			gnv_app.is_open_responseWindow = ""
		end if
		return 0
	end if
end if

adw.event POST ue_postDropFiles()

ls_archDir = gnv_app.is_archivedir
if right(ls_archDir, 1) <> '\' then
	ls_archDir += '\'
end if

// insert all needed OLE_PRINTDET records.
for ll_i = 1 to long(adw.iul_dropped_files)
	setpointer(hourglass!)
	INSERT into ole_printdet (ascii_file, template, ole_type) // JRW 06/07/01 
	VALUES (NULL,NULL, NULL ); // JRW 06/07/01
	
	if SQLCA.SQLCODE <> 0 then
		ls_errors[1] = string( SQLCA.SQLCode )
		ls_errors[2] = string( SQLCA.SQLDBCODE )
		ls_errors[3] = SQLCA.SQLERRTEXT
		gnv_app.inv_error.of_message( "database_error", ls_errors[] )
		SQLCA.of_rollback()
		adw.event POST ue_postDropFiles()
		if lb_reset then
			gnv_app.is_open_responseWindow = ""
		end if
		return -1
	end if	
	

	// Get the sequence number from the table so we can create the appropriate
	// rows in the stored procedure and assign ascii values to the ole_template
	ll_oleref_id[ll_i] = SQLCA.of_get_seqnumber( "OLE_PRINTDET_SEQ", "CURR" )
	if ll_oleref_id[ll_i] < 1 then
		// let's try again with a delay:
		yield()
		sleep(2)
		ll_oleref_id[ll_i] = SQLCA.of_get_seqnumber( "OLE_PRINTDET_SEQ", "CURR" )
		if SQLCA.SQLCODE <> 0 then
			ls_errors[1] = string( sqlca.SQLcode )
			ls_errors[2] = string( sqlca.SQLdbcode )
			ls_errors[3] = sqlca.SQLErrText
			SQLCA.of_rollback()
			gnv_app.inv_error.of_message( "database_error", ls_errors[] )
			adw.event POST ue_postDropFiles()
			if lb_reset then
				gnv_app.is_open_responseWindow = ""
			end if
			return -1
		end if		
		if ll_oleref_id[ll_i] < 1 then
			ls_errors[1] = "OLE_PRINTDET_SEQ"
			gnv_app.inv_error.of_message( "cannot_read_seq", ls_errors[] )
			SQLCA.of_rollback()
			adw.event POST ue_postDropFiles()
			if lb_reset then
				gnv_app.is_open_responseWindow = ""
			end if
			return -1
		end if
	end if

	ls_file = mid(adw.is_dropped_fileNames[ll_i], lastPos(adw.is_dropped_fileNames[ll_i], '\') + 1)
	ls_destination = ls_archDir + string(ll_oleref_id[ll_i]) + "_" + ls_file // v3, mjl, 01/03/21: was string(ll_oleref_id)
	// we might have to shorten the filename before renaming the folder
	if len(ls_destination) > 255 then
		int li_chopOff
		li_chopOff = len(ls_destination) - 255 + 4 // plus 4 to cut off ".msg"
		ls_destination = mid(ls_destination, 1, len(ls_destination) - li_chopOff) + ".msg"
	end if

	li_ret = FileCopy( adw.is_dropped_fileNames[ll_i], ls_destination, TRUE)
	if li_ret = -1 then
		SQLCA.of_rollback()
		Messagebox("Error", 'Error while copying from source file:~r~n"' + adw.is_dropped_fileNames[ll_i] + '".', StopSign!)
		adw.event POST ue_postDropFiles()
		return -1
	elseif li_ret = -2 then
		SQLCA.of_rollback()
		Messagebox("Error", 'Error while copying to destination file: "' + ls_destination + '".', StopSign!)
		adw.event POST ue_postDropFiles()
		return -1
	end if
	
	adw.is_dropped_fileNames[ll_i] = ls_destination
	ls_note += ls_destination + "~r~n"
	
	setpointer(hourglass!)
	update ole_printdet
		set ascii_file = :ls_destination,
			 ole_type = 'U',
			 active = 'Y'
	WHERE oleref_id = :ll_oleref_id[ll_i];
	
	if SQLCA.SQLCODE <> 0 then
		ls_errors[1] = string( sqlca.SQLcode )
		ls_errors[2] = string( sqlca.SQLdbcode )
		ls_errors[3] = sqlca.SQLErrText
		SQLCA.of_rollback()
		gnv_app.inv_error.of_message( "database_error", ls_errors[] )
		adw.event POST ue_postDropFiles()
		return -1
	end if		

next 

// insert a note for each selected row:
setnull(ls_item_id)
string ls_assoc_ind
boolean lb_assoc_ind
long ll_qry_id
setnull(ll_qry_id)

for ll_i = 1 to ll_maxRows
	//insert a note
	
	// all need the customer
	if adw.dataobject = "d_trans_list" then
		ls_customer = adw.object.item_customer[ll_selectedRows[ll_i]]
	else
		ls_customer = adw.object.customer[ll_selectedRows[ll_i]]
	end if
	setnull(ll_qry_id)
	setnull(ls_item_id)
	choose case as_noteType
		case 'TN'
			if adw.dataobject = "d_trans_list" then
				ls_item_id = adw.object.item_trans[ll_selectedRows[ll_i]]
				adw.object.trans_attach[ll_selectedRows[ll_i]] = 'Y'
			else
				ls_item_id = adw.object.item_no[ll_selectedRows[ll_i]]
			end if
//		case 'CN' // already set, so commented.
//			ls_customer = adw.object.customer[ll_selectedRows[ll_i]]
		case 'QN'
			if adw.dataobject = "d_work_list" then
				ll_qry_id = adw.object.master_id[ll_selectedRows[ll_i]]
				ls_assoc_ind = adw.object.master_assocind[ll_selectedRows[ll_i]]
			else
				ll_qry_id = adw.object.qry_id[ll_selectedRows[ll_i]]
				ls_assoc_ind = adw.object.assoc_ind[ll_selectedRows[ll_i]]
			end if

			lb_assoc_ind = false
			if ls_assoc_ind = 'Y' then
				lb_assoc_ind = true
				// associated to a transaction, we have to fill both "customer" and "item_no" in cc_notehdr
				if adw.dataobject = "d_work_list" then
					ls_item_id = adw.object.master_transno[ll_selectedRows[ll_i]]
				elseif adw.dataobject = 'd_ic_query' then
					ls_item_id = adw.object.transaction_no[ll_selectedRows[ll_i]]
				else
					ls_item_id = adw.object.qry_transno[ll_selectedRows[ll_i]]
				end if
			end if
	end choose
	
	if this.of_dropped_Notes(ls_item_id, ls_customer, ll_qry_id, lb_assoc_ind, ls_note, ll_oleref_id, adw, as_noteType) = -1 then
		adw.event POST ue_postDropFiles()
		return -1 // rollback has already been done
	end if
next

string ls_errorParm[]
choose case as_noteType
	case 'TN'
		if adw.iul_dropped_files = 1 then
			// '1 E-mail has been attached for %S %S'
			ls_errorParm[1] = string(ll_maxRows)
			ls_errorParm[2] = "transaction(s)."
			gnv_app.inv_error.of_message('attach_email', ls_errorParm)
		else
			// '%S E-mails have been attached for %S %S',
			ls_errorParm[1] = string(adw.iul_dropped_files)
			ls_errorParm[2] = string(ll_maxRows)
			ls_errorParm[3] = "transaction(s)."
			gnv_app.inv_error.of_message('attach_emails', ls_errorParm)
		end if
	case 'CN'
		if adw.iul_dropped_files = 1 then
			// '1 E-mail has been attached for %S %S'
			ls_errorParm[1] = string(ll_maxRows)
			ls_errorParm[2] = "customer(s)."
			gnv_app.inv_error.of_message('attach_email', ls_errorParm)
		else
			// '%S E-mails have been attached for %S %S',
			ls_errorParm[1] = string(adw.iul_dropped_files)
			ls_errorParm[2] = string(ll_maxRows)
			ls_errorParm[3] = "customer(s)."
			gnv_app.inv_error.of_message('attach_emails', ls_errorParm)
		end if
	case 'QN'
		if adw.iul_dropped_files = 1 then
			// '1 E-mail has been attached for %S %S'
			ls_errorParm[1] = string(ll_maxRows)
			ls_errorParm[2] = "query/queries."
			gnv_app.inv_error.of_message('attach_email', ls_errorParm)
		else
			// '%S E-mails have been attached for %S %S',
			ls_errorParm[1] = string(adw.iul_dropped_files)
			ls_errorParm[2] = string(ll_maxRows)
			ls_errorParm[3] = "query/queries."
			gnv_app.inv_error.of_message('attach_emails', ls_errorParm)
		end if
end choose


sqlca.of_commit()
adw.event POST ue_postDropFiles()

return 1
Comment
  1. Miguel Leeuwe
  2. Friday, 26 May 2023 02:24 AM UTC
Ok, yes, I'm sorry but it's not easy to extract all of the necessary code in a limited amount of time. Let me know if you need any help.
  1. Helpful
  1. John Fauss
  2. Friday, 26 May 2023 13:41 PM UTC
@Miguel - I have two questions for you related to the above code excerpts:

1. What is the numeric value of WM_OUTLOOK_DROP? I know that WM_MOUSEWHEEL = 522.

2. Where did you find the C/C++ typedef for WM_OUTLOOK_DROP documented/listed?

Great work, by the way!
  1. Helpful
  1. Miguel Leeuwe
  2. Friday, 26 May 2023 14:00 PM UTC
Hi John,

1. 111

2. I'm not sure if I just debugged the Other event to figure it out or if I found it somewhere. I coded this like 3 years ago I think.

3. When typing a value of 'o', the OtherO event is ALSO triggered with WM_OUTLOOK_DROP !!! So what I'm doing in the u_dw's key event is this:

if key = keyo! then

// do not process the key (if it's an 'o' it'll trigger the 'other()' event with a value of 111 which is equal to the WM_OUTLOOK_DROP value !!!

ib_noOther = true

return 1

end if



Looking at this right now, the "return 1" doesn't seem to make much sense when typing an 'o'. You'd say you'd want that key to BE processed, even though you have set the ib_noOther to true (which is then checked in the other event to immediately return if I remember well). Can't really remember, but everything seems to be working well for me. Maybe I should just get the sample of the outlook dropdown and try to adapt that to what's needed. My code is all over the place.

  1. Helpful
There are no comments made yet.
Miguel Leeuwe Accepted Answer Pending Moderation
  1. Wednesday, 24 May 2023 17:52 PM UTC
  2. PowerBuilder
  3. # 2

We found this same problem. Our application is 32 bit, but there's a mix of 32/64 bit office amongst our users.

I've done kind of a hack, and use OLE when it fails. (To be honest, it would be better to use that approach for all situations).

Give me some time and I'll try to figure out where and how I'm doing this in my code.

regards.

Comment
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.