custom clipboard format

Forums for specific tips, techniques and example code
ConvertFromOldNGs
Posts: 5321
Joined: Wed Aug 05, 2009 5:19 pm

custom clipboard format

Postby ConvertFromOldNGs » Fri Aug 07, 2009 2:58 pm

by John Munro >> Wed, 19 Dec 2007 16:41:22 GMT

I want to use a custom clipboard format so that application specific data can be copied to the clipboard from one instance of our application and pasted into another instance.

The data that's copied will make no sense to any other application, so using a custom format (rather than just Text) will allow other applications to ignore it.

The only clipboard support in Jade seems to be app.copyStringToClipboard etc. so in order to use a custom format I've had to use external functions.

The registerClipboardFormat, openClipboard etc. external functions all seem to work, but I'm having problems with the fact that to send the data to the clipboard I have to use globalAlloc, copyMemory etc. and I'm very weak with those.

My test method is getting an error 3 (Caught an unexpected C++ exception) at the stage of copying the data to the globally allocated buffer.

The test method is on a button click event because the documentation I read said that you need a real hwnd for openClipboard to work properly.

Can anyone help?

One odd thing is that RootSchema's _globalAlloc has the parameters as size and flags, but MSDN has them the other way around.

Also this is in 6.1 which is why I'm using Integer instead of MemoryAddress.

btnCopy_click(btn: Button input) updating;

constants
GMEM_MOVEABLE : Integer = 2;

vars
iClipFormat, iHandle, iPtr, iSize : Integer;
bClose : Boolean;
binData : Binary;
begin

iClipFormat := call registerClipboardFormat("CustomFormatTest");

if iClipFormat = 0 then
write "could not register clipboard format";

return;
endif;

if not call openClipboard(hwnd) then
write "could not open clipboard";

return;
endif;

bClose := true;

if not call emptyClipboard then
write "could not empty clipboard";

return;
endif;

binData := "<test>".Binary;
iSize := binData.length;

iHandle := call _globalAlloc(GMEM_MOVEABLE, iSize);
if iHandle = 0 then
write "could not allocate buffer";

return;
endif;

iPtr := call _globalLock(iHandle);
if iPtr = 0 then
write "could not lock handle";

return;
endif;

call copyMemory(iPtr, binData.bufferAddress, iSize);

call _globalUnlock(iHandle); // ensure this always happens

if call setClipboardData(iClipFormat, iHandle) = 0 then
write "could not set clipboard data";

return;
endif;

epilog
if bClose then
if not call closeClipboard then
write "could not close clipboard";
endif;
endif;

end;

ConvertFromOldNGs
Posts: 5321
Joined: Wed Aug 05, 2009 5:19 pm

Re: custom clipboard format

Postby ConvertFromOldNGs » Fri Aug 07, 2009 2:58 pm

by John Munro >> Wed, 19 Dec 2007 19:21:10 GMT

OK I think I know why this doesn't work - according to the documentation on Binary::bufferAddress, the address is only valid on the app server, and the clipboard api calls are happening on the presentation client.

Now the question is, how to I get the memory address of a string or binary on the presentation client?

ConvertFromOldNGs
Posts: 5321
Joined: Wed Aug 05, 2009 5:19 pm

Re: custom clipboard format

Postby ConvertFromOldNGs » Fri Aug 07, 2009 2:58 pm

by Torrie Moore >> Wed, 19 Dec 2007 20:51:14 GMT

Hi John

You should look at the Passing by Value or Reference section in the Jade Developers Reference. To pass the memory address, you simply need to define the external function so that it passes by reference. If the external function will update the contents of the string or binary, then you need to include a length in your external function definition.

I'm not familar with the clipboard functions but here's another windows API that we use to get the description of a file type. The API definition is DWORD_PTR SHGetFileInfo(
LPCTSTR pszPath,
DWORD dwFileAttributes,
SHFILEINFO *psfi,
UINT cbFileInfo,
UINT uFlags
);

Where the psfi is a a binary structure. We use a binary for this in Jade. Our external function definition is

shGetFileInfo(

psPath : String;
piAttributes : Integer;
pbShellInfo : Binary[352] output; // output as windows is writing to this binary.
piStructSize : Integer; // Set to 352 - Length of struct being passed to the OS to populate.
piFlags : Integer

) : Integer is SHGetFileInfoA in shell32;

When calling this function Jade will allocate a 352 byte structure and pass the memory address (reference) to the API function, we don't need to explicitly pass the buffer address.

A workspace that uses this function is

vars
oFileOpenDialog : CMDFileOpen;
pbiShellInfo : Binary;
iPos : Integer;
begin

create oFileOpenDialog transient;
oFileOpenDialog.dialogTitle := "Select document to import";
oFileOpenDialog.fileMustExist := true;
oFileOpenDialog.filter := "All supported files types (*.doc, *.docx, *.pub, *.pdf, *.xls, *.xlsx, *.bmp, *.ico, *.wmf, *.cur, *.tif, *.jpg, *.png,
*.gif )|*.pub;*.doc;*.docx;*.pdf;*.xls;*.xlsx;*.bmp;*.ico;*.wmf;*.cur;*.tif;*.jpg;*.png;*.gif|Picture files *.bmp, *.ico, *.wmf, *.cur, *.tif, *.jpg, *.png,
*.gif )|*.bmp;*.ico;*.wmf;*.cur;*.tif;*.jpg;*.png;*.gif|Adobe PDF Files (*.pdf)|*.pdf|Microsoft Word Documents (*.doc)|*.doc|Microsoft Publisher Documents (*.pub)|*.pub|All Files (*.*)|*.*";

oFileOpenDialog.filterIndex := 1;
oFileOpenDialog.pathMustExist := true;
oFileOpenDialog.readOnly := true;
oFileOpenDialog.shareAware := false;
oFileOpenDialog.validate := true;

if oFileOpenDialog.open() = 0 then
if call shGetFileInfo( oFileOpenDialog.fileName, #80, pbiShellInfo, 352, #400.bitOr(#200).bitOr(#10) ) = 0 then
write "File Type = Unknown";
else
// Got a file name
iPos := 1;
write "File Type = " & pbiShellInfo[273:80].String.scanUntil( #0.Character, iPos );
endif;
endif;
epilog
delete oFileOpenDialog;
end;


I don't know how you've defined the copyMemory function but assuming it is an external function I would define it like

copyMemory(
piDest : Integer; // Handle to an allocated memory buffer (use _globalAlloc)
pbSource : Binary; // The Jade binary that will be copied to the buffer
length : Integer // The number of bytes to copy.
) : Integer is CopyMemory in xxxxx;

Your line of code that copies the memory would then be

call copyMemory(iPtr, binData, iSize);

Torrie

ConvertFromOldNGs
Posts: 5321
Joined: Wed Aug 05, 2009 5:19 pm

Re: custom clipboard format

Postby ConvertFromOldNGs » Fri Aug 07, 2009 2:58 pm

by John Munro >> Wed, 19 Dec 2007 21:06:48 GMT

Wow thanks, that works beautifully, except for when I'm doing a paste. In that case I need to copy memory from an address to a Jade Binary, and output parameters must be fixed-size. Is there any way around that?

My external function for this step is

copyMemoryToBinary(pBin_Dest : Binary[256] output; pI_Source, pI_Length : Integer) is RtlMoveMemory in kernel32;

but it puts an artificial limit on the amount of data I can copy

ConvertFromOldNGs
Posts: 5321
Joined: Wed Aug 05, 2009 5:19 pm

Re: custom clipboard format

Postby ConvertFromOldNGs » Fri Aug 07, 2009 2:58 pm

by John Munro >> Wed, 19 Dec 2007 21:14:48 GMT

I tried

copyMemoryToBinary(pBin_Dest : Binary[Max_Integer] output; pI_Source : Integer; pI_Length : Integer) is RtlMoveMemory in kernel32;

but I get "Out of resources for operation" :)

ConvertFromOldNGs
Posts: 5321
Joined: Wed Aug 05, 2009 5:19 pm

Re: custom clipboard format

Postby ConvertFromOldNGs » Fri Aug 07, 2009 2:58 pm

by Torrie Moore >> Thu, 20 Dec 2007 20:36:31 GMT

No there isn't. Jade has to know how much memory to allocate before calling the external function. You could create a number of external functions with different sized binary parameters.

Have you tried a loop, i.e. copy 256 bytes at a time and advance the pointer to the next 256 byte block.

vars
biTemp : Binary;
biResult : Binary;
iBytesLeftToCopy : Integer;
iBytesToCopyThisTime : Integer;
pI_Source : Integer;begin


...

while iBytesLeftToCopy > 0 do
iBytesToCopyThisTime := 256.min( iBytesLeftToCopy);
call copyMemoryToBinary( bTemp, pI_Source, iBytesToCopyThisTime ); biResult := biResult & biTemp;
pI_Source := pI_Source + iBytesToCopyThisTime;
iBytesLeftToCopy := iBytesLeftToCopy - iBytesToCopyThisTime;
endwhile;

...

Torrie

ConvertFromOldNGs
Posts: 5321
Joined: Wed Aug 05, 2009 5:19 pm

Re: custom clipboard format

Postby ConvertFromOldNGs » Fri Aug 07, 2009 2:58 pm

by John Munro >> Thu, 20 Dec 2007 21:15:28 GMT

Good idea, thanks


Return to “Tips and Techniques”

Who is online

Users browsing this forum: No registered users and 14 guests