Calling ExportDocumnet in a Thread

PDF-XChange Viewer SDK for Developer's
(ActiveX and Simple DLL Versions)

Moderators: PDF-XChange Support, Daniel - PDF-XChange, Chris - PDF-XChange, Sean - PDF-XChange, Vasyl - PDF-XChange, Ivan - Tracker Software, Stefan - PDF-XChange

jeffp
User
Posts: 923
Joined: Wed Sep 30, 2009 6:53 pm

Calling ExportDocumnet in a Thread

Post by jeffp »

In the ActiveX Viewer, I'm trying to call the procedure below which contains a call to SetProperty and ExportDocument. The procedure is fine if I run it in the main thread. However, I have a need to call the procedure in a separate thread. When called in a separate thread, it crashes on the first SetProperty call.

As part of my application, I need to generate thumbnail images of each page inside a thread.

What are the threading isssues with the ActiveX Veiwer?

Code: Select all

procedure TPDFViewerAX.SaveDocumentPageAsBitmap(ADocID, APage: Integer;
  AFileName: String; ADPI: Integer = 300);
var
  AName, AFolder: String;
begin
  if not IsValidDocID(ADocID) then exit;

  if (ADPI = 0) then ADPI := 300;
  ADPI := Max(100, Min(500, ADPI));

  AFolder := ExtractFilePath(AFileName);
  AName := ExtractFileName(AFilename);

  FController.SetProperty('Export.Image.Type', 'BMP', 0);
  FController.SetProperty('Export.Image.Mode', 'EachToOneImage', 0);
  FController.SetProperty('Export.Image.RangeType', 'Exact', 0);
  FController.SetProperty('Export.Image.RangeText', IntToStr(APage), 0);
  FController.SetProperty('Export.Image.RangeReverse', 0, 0);
  FController.SetProperty('Export.Image.Resolution', ADPI, 0);
  FController.SetProperty('Export.Image.FolderName', AFolder, 0);
  FController.SetProperty('Export.Image.FileName', AName, 0);

  try FController.ExportDocument(ADocID, PXCVA_NoUI); except end;
end;
jeffp
User
Posts: 923
Joined: Wed Sep 30, 2009 6:53 pm

Re: Calling ExportDocumnet in a Thread

Post by jeffp »

Do you need a better explanation of my issue?
ugradedeveloper
User
Posts: 223
Joined: Wed Aug 22, 2007 4:40 pm

Re: Calling ExportDocument in a Thread

Post by ugradedeveloper »

Manipulation of UI (user interface) elements needs to be done from the main thread. This is not an issue specific to PDF XChange Viewer, it is true whenever you are dealing with a screen element or form of any kind.

There are functions for allowing the code execution at any point to be passed off to the main thread. In Microsoft Visual Studio there is a class of "Invoke" methods for this purpose. What development environment are you using?

Lewis
jeffp
User
Posts: 923
Joined: Wed Sep 30, 2009 6:53 pm

Re: Calling ExportDocumnet in a Thread

Post by jeffp »

I am using Delphi and would really appreciate some direction here. This is an important part of our applications.

Background: We are embedding the ActiveX viewer inside our application and it works great. However, we have an additional "Work with Pages" view in our application in which we just show the Thumbnails of each pdf page and then offer a wide variety of page manipulations procedures within the same pdf document and between pdf documents. For this veiw to work, I need to display thumbnail images of of the pdf documents that are already opened in the ActiveX viewer. I am displaying these images in our own list control for this purpose.

It works best if I can generate the thumbnail images of these pages inside a thread so there is not bottleneck with the main ActiveX viewer.

Is there a way to do this in Delphi? Alternatively, is there a way to grab the thumbnail images you are already producing in the ActiveX viewer?
ugradedeveloper
User
Posts: 223
Joined: Wed Aug 22, 2007 4:40 pm

Re: Calling ExportDocumnet in a Thread

Post by ugradedeveloper »

Afraid I don't know anything about Delphi.

Are you using PDF-XChange on the "Work with Pages" view at all? It sounds like you're not. So, why do you need to access the ActiveX viewer from those threads?

Lewis
jeffp
User
Posts: 923
Joined: Wed Sep 30, 2009 6:53 pm

Re: Calling ExportDocumnet in a Thread

Post by jeffp »

I need to access the ActiveX viewer from the "Work with Pages" threads in order to generate Thumbnail images from the PDF document that the ActiveX viewer has load.

How does the ActiveX viewer create its thumbnail images that are displayed in the Pages Layout? Does it only create them when they are in view?

Is there a way for me to access these thumbnail images rather than recreating them on my own?
User avatar
Vasyl - PDF-XChange
Site Admin
Posts: 2448
Joined: Thu Jun 30, 2005 4:11 pm

Re: Calling ExportDocumnet in a Thread

Post by Vasyl - PDF-XChange »

Hi, jeffp

For your case(pages-thumbnails generation in the separate thread) you may:
1. Create separate thread ;)
2. Create hidden form with embedded our ActiveX in this thread and use this local ActiveX.

That is:

Code: Select all

// thread function
procedure ThreadProc(...)
begin
...
localForm := TFormN.create(nil); // create hidden form with embedded our AX, local for this thread 
TFormN.SaveDocumentPageAsBitmap(...)
...
end
// create page-thumbnail
procedure TFormN.SaveDocumentPageAsBitmap(....)
begin
...
FController.SetProperty('Export.Image.Type', 'BMP', 0);
...
try FController.ExportDocument(..., PXCVA_Sync | PXCVA_NoUI); except end;
end
Exists faster(and best) way for pages thumbnails generation: you may use our PDF-XChange Viewer Simple SDK for this.

Best
Regards.
PDF-XChange Co. LTD (Project Developer)

Please archive any files posted to a ZIP, 7z or RAR file or they will be removed and not posted.
jeffp
User
Posts: 923
Joined: Wed Sep 30, 2009 6:53 pm

Re: Calling ExportDocumnet in a Thread

Post by jeffp »

I need to use the same ActiveX control I created in the main thread since it already has the loaded PDF documents. Can this be done? Also, I'm getting an AV when I try to create the hidden form in the Thread. Do you have a full code sample of what you are suggesting?

Thanks.
User avatar
Vasyl - PDF-XChange
Site Admin
Posts: 2448
Joined: Thu Jun 30, 2005 4:11 pm

Re: Calling ExportDocumnet in a Thread

Post by Vasyl - PDF-XChange »

Ok.
If you need to use the same ActiveX control - you should use standard COM API for marshal/unmarshal IPDFXCview interface from main to another thread(s):
CoMarshalInterThreadInterfaceInStream // for marshal pointer to IPDFXCview interface into a stream object
CoGetInterfaceAndReleaseStream // for obtain IPDFXCview pointer, adapted for other thread
Sorry, but I'm not Delphi-expert, I can demonstrate this method by C++(+ATL) only, code parts:

Code: Select all

// in Main thread, start other thread:
CComPtr<IPDFXCview> m_spView; // main ActiveX, embedded on the main form
LONG m_nCurDoc;
...
IStream* m_pMarshStream = NULL;
...
HRESULT hr = ::CoMarshalInterThreadInterfaceInStream(IID_IPDFXCview, m_spView.p, &m_pMarshStream);
DWORD dwThreadID = 0;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, BuidThumbnailProc, (LPVOID)this, 0, (unsigned*)&dwThreadID);
//
// thread function
static UINT WINAPI BuidThumbnailProc(LPVOID lpvParam)
{
	::CoInitializeEx(NULL, 0);
	// we cannot use the m_spView here, because each call throw standard com-exception with code 0x8001010e(The application called an interface that was marshalled for a different thread)
	CComPtr<IPDFXCview> spLocalView = NULL;
	HRESULT hr = ::CoGetInterfaceAndReleaseStream(m_pMarshStream, IID_IPDFXCview, (void**)&spLocalView);
	ATLASSERT(SUCCEEDED(hr));
	if (spLocalView == NULL)
		return 0;
	CComVariant val(L"BMP");
	hr = spLocalView->SetProperty(CComBSTR(L"Export.Image.Type").m_str, val, 0);
	...
	CComVariant d1, d2;
	hr = spLocalView->DoDocumentVerb(m_nCurDoc, NULL, CComBSTR(L"Export").m_str, d1, &d2, PXCVA_NoUI | PXCVA_Sync);
	ATLASSERT(SUCCEEDED(hr));
	...
	::CoUninitialize();
	return 0;
}
HTH
PDF-XChange Co. LTD (Project Developer)

Please archive any files posted to a ZIP, 7z or RAR file or they will be removed and not posted.
jeffp
User
Posts: 923
Joined: Wed Sep 30, 2009 6:53 pm

Re: Calling ExportDocumnet in a Thread

Post by jeffp »

I finally got it to work in Delphi. Thanks for your help and patience.

One follow up: Because I'm creating a thumbnail image for each page in the PDF document, I'll be calling the marshaling procedures for each page. My thought is to use an array of pointers (one for each page in the document). It appears that the output of CoMarshalInterThreadInterfaceInStream is just a pointer. As such, do I need to worry about the internal memory getting to big if the PDF has 100s of pages and I create a pointer in my array for each page using CoMarshalInterThreadInterfaceInStream?

--Jeff
User avatar
Vasyl - PDF-XChange
Site Admin
Posts: 2448
Joined: Thu Jun 30, 2005 4:11 pm

Re: Calling ExportDocumnet in a Thread

Post by Vasyl - PDF-XChange »

Hi, jeffp.
One follow up: Because I'm creating a thumbnail image for each page in the PDF document, I'll be calling the marshaling procedures for each page. My thought is to use an array of pointers (one for each page in the document).
No, you shouldn't to marshal interface-pointer for each page separately, only once for each additional thread.
The new marshaled pointer can be used many times in this additional thread.
---
I think - start of a new thread for each page separately - can strongly reduce system performance.
The best solution for this case - pool of the thumbnail-generation-threads(can be one thread only).
Each thumbnail-generation-thread works with common thread-protected list of tasks.
Each object-task contains the information: the document, page, thumb. size, dest. filename etc.
It is classic solution for this case..

Also, exists one nuance: the main ActiveX will be blocked for usage during each thumbnail-creation moment.

HTH
PDF-XChange Co. LTD (Project Developer)

Please archive any files posted to a ZIP, 7z or RAR file or they will be removed and not posted.