Twain_DSM  1.0
apps.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * TWAIN Data Source Manager version 2.1
3  * Manages image acquisition data sources used by a machine.
4  * Copyright © 2007 TWAIN Working Group:
5  * Adobe Systems Incorporated,AnyDoc Software Inc., Eastman Kodak Company,
6  * Fujitsu Computer Products of America, JFL Peripheral Solutions Inc.,
7  * Ricoh Corporation, and Xerox Corporation.
8  * All rights reserved.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24  * Contact the TWAIN Working Group by emailing the Technical Subcommittee at
25  * twainwg@twain.org or mailing us at 13090 Hwy 9, Suite 3, Boulder Creek, CA 95006.
26  *
27  ***************************************************************************/
28 
36 #include "dsm.h"
37 
38 
39 
44 typedef struct
45 {
47  TW_HANDLE pHandle;
48  DSENTRYPROC DS_Entry;
49  char szPath[FILENAME_MAX];
51  TW_BOOL bCallbackPending;
54 } DS_INFO;
55 
56 
57 
67 typedef struct {
68  long Id;
69  TW_VERSION Version;
70  TW_UINT16 ProtocolMajor;
71  TW_UINT16 ProtocolMinor;
72  long SupportedGroups;
73  TW_STR32 Manufacturer;
74  TW_STR32 ProductFamily;
75  TW_STR32 ProductName;
77 typedef union {
78  TW_IDENTITY twidentity;
79  TW_IDENTITY_LINUX64 twidentitylinux64;
81 
82 
83 
87 typedef struct
88 {
89  TW_UINT16 NumFiles;
90  DS_INFO DSInfo[MAX_NUM_DS];
91 } DS_LIST;
92 
93 
94 
101 typedef struct
102 {
104  TW_INT16 ConditionCode;
107  HWND hwnd;
108 } APP_INFO;
109 
113 class CAppList
114 {
115 private:
117  TWID_T m_count;
119 public:
120 
126  {
127  m_count=0;
128  m_pList=NULL;
129  }
130 
136  {
137  if(m_pList)
138  {
139  free(m_pList);
140  }
141  }
142 
147  TWID_T size(){return m_count;}
148 
155  APP_INFO& operator[](TWID_T AppId)
156  {
157  if(AppId>=m_count)
158  {
159  APP_INFO * pNewList=(APP_INFO *)realloc(m_pList,sizeof(APP_INFO)*(AppId+1));
160  if(pNewList==NULL)
161  {
162  kLOG((kLOGERR,"realloc of m_pList failed AppId = %d",AppId));
163  return m_pList[0];
164  }
165  m_pList = pNewList;
166  memset(&m_pList[m_count],0,sizeof(APP_INFO)*(AppId+1-m_count));
167  m_count = AppId+1;
168  }
169 
170  return m_pList[AppId];
171  }
172 
179  bool Erase(TWID_T AppId)
180  {
181  if((AppId==0) || (AppId>=m_count))
182  {
183  kLOG((kLOGERR,"AppId = %d is invalid",AppId));
184  return false;
185  }
186  if(AppId==(m_count-1))
187  {
188  m_count--;
189  for(TWID_T i=m_count-1; i>0;i--)
190  {
191  if(m_pList[i].identity.Id)
192  {
193  break;
194  }
195  m_count--;
196  }
197  APP_INFO * pNewList=(APP_INFO *)realloc(m_pList,sizeof(APP_INFO)*m_count);
198  if(pNewList==NULL)
199  {
200  kLOG((kLOGERR,"realloc of m_pList failed AppId = %d",AppId));
201  return false;
202  }
203  m_pList = pNewList;
204  }
205  else
206  {
207  memset(&m_pList[AppId],0,sizeof(APP_INFO));
208  }
209  return true;
210  }
211 
216  bool Clear()
217  {
218  APP_INFO * pNewList=(APP_INFO *)realloc(m_pList,sizeof(APP_INFO));
219  if(pNewList==NULL)
220  {
221  memset(&m_pList[1],0,sizeof(APP_INFO)*(m_count-1));
222  kLOG((kLOGERR,"realloc of m_pList failed"));
223  return false;
224  }
225  m_count=1;
226  m_pList = pNewList;
227  return true;
228  }
229 };
230 
241 {
242  public:
243 
248  {
249  memset(&pod,0,sizeof(_pod));
250  }
251 
261  int scanDSDir(char *_szAbsPath,
262  TW_IDENTITY *_pAppId);
263 
269  const char *StringFromCC(const TW_UINT16 cc);
270 
279  TW_INT16 LoadDS(TW_IDENTITY *_pAppId,
280  char *_pPath,
281  TWID_T _DsId,
282  bool _boolKeepOpen);
283 
289  void AppSetConditionCode(TW_IDENTITY *_pAppId,
290  TW_UINT16 _ConditionCode);
291 
292  public:
293  // If you add a class in future, declare it here and not in
294  // the pod, or the memset in the constructor will ruin your
295  // day...
296 
301  struct _pod
302  {
303  TW_UINT16 m_conditioncode;
304  } pod;
307 };
308 
309 
310 
315 {
317  if (!m_ptwndsmappsimpl)
318  {
319  kLOG((kLOGERR,"new of CTwnDsmAppsImpl failed..."));
320  }
321 }
322 
323 
324 
329 {
330  if (m_ptwndsmappsimpl)
331  {
332  // We should not have to go through the list of Apps at this point and
333  // close them. The application should close any open DSs and then Close
334  // the DSM which should take care of this. But just in case, we will
335  // clean up any DS left open.
336  for (TWID_T i = 1; i < m_ptwndsmappsimpl->m_AppInfo.size(); i++)
337  {
338  if( m_ptwndsmappsimpl->m_AppInfo[i].identity.Id
339  && dsmState_Open != m_ptwndsmappsimpl->m_AppInfo[i].CurrentState )
340  {
341  kLOG((kLOGINFO,"The Application, \"%0.32s\", has left the DSM in an open state when it was unloaded!",
342  m_ptwndsmappsimpl->m_AppInfo[i].identity.ProductName));
343 
344  RemoveApp(&m_ptwndsmappsimpl->m_AppInfo[i].identity);
345  }
346  }
347  delete m_ptwndsmappsimpl;
348  m_ptwndsmappsimpl = 0;
349  }
350 }
351 
352 
353 
364 TW_UINT16 CTwnDsmApps::AddApp(TW_IDENTITY *_pAppId,
365  TW_MEMREF _MemRef)
366 {
367  TWID_T ii;
368  char szDsm[FILENAME_MAX];
369 
370  // Validate...
371  if (_pAppId->ProductName[0] == 0)
372  {
373  kLOG((kLOGERR,"AppId.ProductName is empty"));
374  AppSetConditionCode(0,TWCC_BADVALUE);
375  return TWRC_FAILURE;
376  }
377 
378  // Initialize...
379  ii = 0;
380  memset(szDsm,0,sizeof(szDsm));
381 
382  // Log the entry...
383  kLOG((kLOGINFO,"Application: \"%0.32s\"", _pAppId->Manufacturer));
384  kLOG((kLOGINFO," \"%0.32s\"", _pAppId->ProductFamily));
385  kLOG((kLOGINFO," \"%0.32s\" version: %u.%u", _pAppId->ProductName, _pAppId->Version.MajorNum, _pAppId->Version.MinorNum));
386  kLOG((kLOGINFO," TWAIN %u.%u", _pAppId->ProtocolMajor, _pAppId->ProtocolMinor));
387 
388  // An application is identified by the name and handle
389  // Check to see if this app has already been opened, and
390  // if so, treat it as a sequence error, because this app
391  // is already open...
392  for (ii = 1; ii < m_ptwndsmappsimpl->m_AppInfo.size(); ii++)
393  {
394  if ( !strncmp((char*)m_ptwndsmappsimpl->m_AppInfo[ii].identity.ProductName,(char*)_pAppId->ProductName,sizeof(TW_STR32))
395  && m_ptwndsmappsimpl->m_AppInfo[ii].hwnd == (HWND)(_MemRef?*(HWND*)_MemRef:0) )
396  {
397  kLOG((kLOGERR,"A successful MSG_OPENDSM was already done for %s...",_pAppId->ProductName));
398  AppSetConditionCode(0,TWCC_SEQERROR);
399  return TWRC_FAILURE;
400  }
401  }
402 
403  //Go through the list and find an empty location
404  // Already tested that there is enough room to fit
405  for (ii=1; ii < m_ptwndsmappsimpl->m_AppInfo.size(); ii++)
406  {
407  if (!m_ptwndsmappsimpl->m_AppInfo[ii].identity.Id)
408  {
409  break;
410  }
411  }
412  // The application ID is equal to array index it resides in.
413  // We just let the 0-index stay empty...
414  _pAppId->Id = (TWIDDEST_T)ii;
415  _pAppId->SupportedGroups |= DF_DSM2;
416  m_ptwndsmappsimpl->m_AppInfo[ii].identity = *_pAppId;
417  m_ptwndsmappsimpl->m_AppInfo[ii].hwnd = (HWND)(_MemRef?*(HWND*)_MemRef:0);
418  m_ptwndsmappsimpl->m_AppInfo[ii].pDSList = (DS_LIST*)calloc(sizeof(DS_LIST)+1,1);
419  if (!m_ptwndsmappsimpl->m_AppInfo[ii].pDSList)
420  {
421  kLOG((kLOGERR,"calloc failed for %s...",_pAppId->ProductName));
422  AppSetConditionCode(0,TWCC_LOWMEMORY);
423  return TWRC_FAILURE;
424  }
425 
426  // Work out the full path to our drivers (if needed)...
427  #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
428  (void)::GetWindowsDirectory(szDsm,sizeof(szDsm));
429  SSTRCAT(szDsm,sizeof(szDsm),"\\");
430  SSTRCAT(szDsm,sizeof(szDsm),kTWAIN_DS_DIR);
431  #elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP)
432  SSTRCPY(szDsm,sizeof(szDsm),kTWAIN_DS_DIR);
433  #else
434  #error Sorry, we do not recognize this system...
435  #endif
436 
437  // Move DSM to state 3 for this app...
438  m_ptwndsmappsimpl->m_AppInfo[ii].CurrentState = dsmState_Open;
439 
440  // Recursively navigate the TWAIN datasource dir looking for data sources.
441  // Ignor error continue with what we found even if it is nothing
442  m_ptwndsmappsimpl->scanDSDir(szDsm,_pAppId);
443 
444  // Maybe one of many DS failed but we still found some.
445  AppSetConditionCode(_pAppId, TWCC_SUCCESS);
446 
447  // at this point we can safely add our flag to the caller's
448  // application id, but don't bother to do it unless they put
449  // their flag in there first...
450  if (_pAppId->SupportedGroups & DF_APP2)
451  {
452  _pAppId->SupportedGroups |= DF_DSM2;
453  }
454 
455  // All done...
456  return TWRC_SUCCESS;
457 }
458 
459 
460 
466 {
467  int nIndex;
468  DS_INFO *pDSInfo;
469  TW_PENDINGXFERS twpendingxfers;
470  TW_USERINTERFACE twuserinterface;
471 
472  // Validate...
473  if ( ((TWID_T)_pAppId->Id ==0)
474  || ((TWID_T)_pAppId->Id > m_ptwndsmappsimpl->m_AppInfo.size()))
475  {
476  kLOG((kLOGERR,"_id is out of range...%d",(int)(TWID_T)_pAppId->Id));
477  AppSetConditionCode(0,TWCC_BADVALUE);
478  return TWRC_FAILURE;
479  }
480 
481  // To close the DSM we must be open. I don't really like this
482  // piece of code. To my way of thinking a close should always
483  // succeed, even if there are mice in the DVD drive and the
484  // monitor is on fire. The notion of a failure message during
485  // a close is annoying. But there might be a good reason for
486  // this I'm not aware of...
487  if (dsmState_Open != m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].CurrentState)
488  {
489  kLOG((kLOGINFO,"%0.32s not open.",(char*)_pAppId->ProductName));
490  AppSetConditionCode(0,TWCC_SEQERROR);
491  return TWRC_FAILURE;
492  }
493 
494  // Get rid of our list of drivers...
495  if (m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList)
496  {
497  // Check all the driver slots, if we find an open slot, shotgun it
498  // with the sequence of close out commands and shut it down. This
499  // really isn't something we should have to do, but it makes us
500  // more robust...
501  for (nIndex = 1;
502  nIndex < m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->NumFiles;
503  nIndex++)
504  {
505  pDSInfo = &m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[nIndex];
506  if (pDSInfo->DS_Entry)
507  {
508  kLOG((kLOGERR,"MSG_CLOSEDSM called with drivers still open."));
509  kLOG((kLOGINFO,"The application should not be doing this."));
510  kLOG((kLOGINFO,"The DSM is going to try to gracefully shutdown the drivers..."));
511 
512  memset(&twpendingxfers,0,sizeof(twpendingxfers));
513  memset(&twuserinterface,0,sizeof(twuserinterface));
514 
515  pDSInfo->DS_Entry(_pAppId,DG_CONTROL,DAT_PENDINGXFERS,MSG_ENDXFER,(TW_MEMREF)&twpendingxfers);
516  pDSInfo->DS_Entry(_pAppId,DG_CONTROL,DAT_PENDINGXFERS,MSG_RESET,(TW_MEMREF)&twpendingxfers);
517  pDSInfo->DS_Entry(_pAppId,DG_CONTROL,DAT_USERINTERFACE,MSG_DISABLEDS,(TW_MEMREF)&twuserinterface);
518  pDSInfo->DS_Entry(_pAppId,DG_CONTROL,DAT_IDENTITY,MSG_CLOSEDS,(TW_MEMREF)&pDSInfo->Identity);
519  UnloadDS(_pAppId,nIndex);
520  }
521  }
522 
523  // Okay, we can blow away the memory now...
524  free(m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList);
525  m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList = NULL;
526  }
527  //Free AppInfo for this App
528  m_ptwndsmappsimpl->m_AppInfo.Erase((TWID_T)_pAppId->Id);
529 
530 
531  // All done...
532  return TWRC_SUCCESS;
533 }
534 
535 
536 
542 {
543  if (!_pAppId)
544  {
545  kLOG((kLOGERR,"_pAppId is null..."));
546  return false;
547  }
548  else if ((TWID_T)_pAppId->Id >= m_ptwndsmappsimpl->m_AppInfo.size())
549  {
550  kLOG((kLOGERR,"invalid App ID...%d",(int)(TWID_T)_pAppId->Id));
551  return false;
552  }
553  return true;
554 }
555 
556 
562 {
563  if(!AppValidateId(_pAppId))
564  {
565  return false;
566  }
567  else
568  {
569  if (!_pDSId)
570  {
571  kLOG((kLOGERR,"_pDSId is null..."));
572  return false;
573  }
574  else if ((TWID_T)_pDSId->Id >= MAX_NUM_DS)
575  {
576  kLOG((kLOGERR,"invalid DS ID...%d",(int)(TWID_T)_pDSId->Id));
577  return false;
578  }
579  else if (!m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList)
580  {
581  kLOG((kLOGERR,"List of DS for app is invalid"));
582  return false;
583  }
584  else if ((TWID_T)_pDSId->Id > m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->NumFiles)
585  {
586  kLOG((kLOGERR,"The DS ID for app is not valid"));
587  return false;
588  }
589  }
590  return true;
591 }
592 
593 
599 {
600  if (AppValidateId(_pAppId))
601  {
602  return &m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].identity;
603  }
604  kLOG((kLOGERR,"bad _pAppId..."));
605  return NULL;
606 }
607 
608 
609 
620 {
621  TW_UINT16 conditioncode;
622 
623  // Return the application specific value...
624  if (AppValidateId(_pAppId))
625  {
626  conditioncode = m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].ConditionCode;
627  m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].ConditionCode = TWCC_SUCCESS;
628  m_ptwndsmappsimpl->pod.m_conditioncode = TWCC_SUCCESS;
629  return conditioncode;
630  }
631  // Uh-oh, we have no app, so return the global value...
632  else
633  {
634  conditioncode = m_ptwndsmappsimpl->pod.m_conditioncode;
635  m_ptwndsmappsimpl->pod.m_conditioncode = TWCC_SUCCESS;
636  return conditioncode;
637  }
638 }
639 
640 
641 
642 /*
643 * Set the condition code.
644 * The same rules apply here as they do for AppGetConditionCode.
645 * This is the interface function...
646 */
648  TW_UINT16 _ConditionCode)
649 {
650  return m_ptwndsmappsimpl->AppSetConditionCode(_pAppId,_ConditionCode);
651 }
652 
653 
654 
661  TW_UINT16 _ConditionCode)
662 {
663  // We have no application identity to work with...
664  if ( (0 == _pAppId)
665  || (0 == (TWID_T)_pAppId->Id)
666  || (0 == m_AppInfo[(TWID_T)_pAppId->Id].identity.Id))
667  {
668  pod.m_conditioncode = _ConditionCode;
669  }
670 
671  // This is where we normally expect to be...
672  else
673  {
674  m_AppInfo[(TWID_T)_pAppId->Id].ConditionCode = _ConditionCode;
675  }
676 
677  // Make a note of this in the log...
678  if (_ConditionCode != TWCC_SUCCESS)
679  {
680  kLOG((kLOGINFO,"Condition Code: %s",StringFromCC(_ConditionCode)));
681  }
682 
683  // All done...
684  return;
685 }
686 
687 
689 {
690  // Initialize to PreSession and update it if we find an application that is further along.
691  DSM_State CurrentState = dsmState_PreSession;
692 
693  for (TWID_T AppID = 1; AppID<m_ptwndsmappsimpl->m_AppInfo.size(); AppID++)
694  {
695  if(m_ptwndsmappsimpl->m_AppInfo[AppID].CurrentState > CurrentState)
696  {
697  CurrentState = m_ptwndsmappsimpl->m_AppInfo[AppID].CurrentState;
698  }
699  }
700  return CurrentState;
701 }
702 
711 {
712  // Return the application specific state...
713  if (AppValidateId(_pAppId))
714  {
715  return m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].CurrentState;
716  }
717  // Otherwise we must be in state 2. Good luck ever getting state 1
718  // out of the DSM... :)
719  else
720  {
721  return dsmState_Loaded;
722  }
723 }
724 
730 {
731  return m_ptwndsmappsimpl->m_AppInfo.size();
732 }
733 
734 
735 
741 {
742  // Return the hwnd...
743  if (AppValidateId(_pAppId))
744  {
745  return m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].hwnd;
746  }
747  // Otherwise return a null...
748  else
749  {
750  return 0;
751  }
752 }
753 
754 
755 
763 {
764  // Return the number of drivers we found...
765  if ( AppValidateId(_pAppId)
766  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList)
767  {
768  return m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->NumFiles;
769  }
770  // Not a lot of choice, the value has to be zero...
771  else
772  {
773  return 0;
774  }
775 }
776 
777 
778 
786  TWID_T _DsId)
787 {
788  // Return a pointer to the driver's identity...
789  if ( AppValidateId(_pAppId)
790  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
791  && (_DsId < MAX_NUM_DS))
792  {
793  return &m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].Identity;
794  }
795  // Something is toasted, so return NULL...
796  else
797  {
798  kLOG((kLOGERR,"Returning NULL from DsGetIdentity..."));
799  return NULL;
800  }
801 }
802 
803 
804 
810  TWID_T _DsId)
811 {
812  // Return a pointer to the driver's identity...
813  if ( AppValidateId(_pAppId)
814  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
815  && (_DsId < MAX_NUM_DS))
816  {
817  return m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].DS_Entry;
818  }
819  // Something is toasted, so return NULL...
820  else
821  {
822  kLOG((kLOGERR,"Returning NULL from DsGetEntryProc..."));
823  return NULL;
824  }
825 }
826 
827 
828 
835  TWID_T _DsId)
836 {
837  // Return a pointer to the driver's file path and name...
838  if ( AppValidateId(_pAppId)
839  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
840  && (_DsId < MAX_NUM_DS))
841  {
842  return m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].szPath;
843  }
844  // Something is toasted, so return NULL...
845  else
846  {
847  kLOG((kLOGERR,"Returning NULL from DsGetPath..."));
848  return NULL;
849  }
850 }
851 
852 
853 
861  TWID_T _DsId)
862 {
863  // Return a pointer to the driver's TW_CALLBACK...
864  if ( AppValidateId(_pAppId)
865  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
866  && (_DsId < MAX_NUM_DS))
867  {
868  return &m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].twcallback2;
869  }
870  // Something is toasted, so return NULL...
871  else
872  {
873  kLOG((kLOGERR,"Returning NULL from DsCallbackGet..."));
874  return NULL;
875  }
876 }
877 
878 
879 
886  TWID_T _DsId)
887 {
888  // Check the waiting flag...
889  if ( AppValidateId(_pAppId)
890  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
891  && (_DsId < MAX_NUM_DS))
892  {
893  return m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].bCallbackPending;
894  }
895  // Something is toasted, so return FALSE...
896  else
897  {
898  kLOG((kLOGERR,"Returning FALSE from DsCallbackIsWaiting..."));
899  return FALSE;
900  }
901 }
902 
903 
904 
910  TWID_T _DsId,
911  TW_BOOL _Waiting)
912 {
913  // Set the waiting flag...
914  if ( AppValidateId(_pAppId)
915  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
916  && (_DsId < MAX_NUM_DS))
917  {
918  m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].bCallbackPending = _Waiting;
919  }
920  // Something is toasted, so whine about it...
921  else
922  {
923  kLOG((kLOGERR,"Unable to properly handle DsCallbackSetWaiting..."));
924  }
925 }
926 
927 
928 
935  TWID_T _DsId)
936 {
937  // Check the waiting flag...
938  if ( AppValidateId(_pAppId)
939  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
940  && (_DsId < MAX_NUM_DS))
941  {
942  return m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].bDSProcessingMessage;
943  }
944  // Something is toasted, so return FALSE...
945  else
946  {
947  kLOG((kLOGERR,"Returning FALSE from DsIsProcessingMessage..."));
948  return FALSE;
949  }
950 }
951 
952 
953 
959  TWID_T _DsId,
960  TW_BOOL _Processing)
961 {
962  // Set the processing flag...
963  if ( AppValidateId(_pAppId)
964  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
965  && (_DsId < MAX_NUM_DS))
966  {
967  m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].bDSProcessingMessage = _Processing;
968  }
969  // Something is toasted, so whine about it...
970  else
971  {
972  kLOG((kLOGERR,"Unable to properly handle DsSetProcessingMessage..."));
973  }
974 }
975 
976 
983  TWID_T _DsId)
984 {
985  // Check the waiting flag...
986  if ( AppValidateId(_pAppId)
987  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
988  && (_DsId < MAX_NUM_DS))
989  {
990  return m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].bAppProcessingCallback;
991  }
992  // Something is toasted, so return FALSE...
993  else
994  {
995  kLOG((kLOGERR,"Returning FALSE from DsIsAppProcessingCallback..."));
996  return FALSE;
997  }
998 }
999 
1000 
1006  TWID_T _DsId,
1007  TW_BOOL _Processing)
1008 {
1009  // Set the processing flag...
1010  if ( AppValidateId(_pAppId)
1011  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
1012  && (_DsId < MAX_NUM_DS))
1013  {
1014  m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].bAppProcessingCallback = _Processing;
1015  }
1016  // Something is toasted, so whine about it...
1017  else
1018  {
1019  kLOG((kLOGERR,"Unable to properly handle DsSetAppProcessingCallback..."));
1020  }
1021 }
1022 
1023 
1027 const char *CTwnDsmAppsImpl::StringFromCC(const TW_UINT16 cc)
1028 {
1029  switch(cc)
1030  {
1031  case TWCC_SUCCESS:
1032  return "TWRC_SUCCESS";
1033  break;
1034 
1035  case TWCC_BUMMER:
1036  return "Failure due to unknown causes";
1037  break;
1038 
1039  case TWCC_LOWMEMORY:
1040  return "Not enough memory to perform operation";
1041  break;
1042 
1043  case TWCC_NODS:
1044  return "No Data Source";
1045  break;
1046 
1047  case TWCC_MAXCONNECTIONS:
1048  return "DS is connected to max possible applications";
1049  break;
1050 
1051  case TWCC_OPERATIONERROR:
1052  return "DS or DSM reported error, application shouldn't display an error";
1053  break;
1054 
1055  case TWCC_BADCAP:
1056  return "Unknown capability";
1057  break;
1058 
1059  case TWCC_BADPROTOCOL:
1060  return "Unrecognized MSG DG DAT combination";
1061  break;
1062 
1063  case TWCC_BADVALUE:
1064  return "Data parameter out of range";
1065  break;
1066 
1067  case TWCC_SEQERROR:
1068  return "DG DAT MSG out of expected sequence";
1069  break;
1070 
1071  case TWCC_BADDEST:
1072  return "Unknown destination Application/Source in DSM_Entry";
1073  break;
1074 
1075  case TWCC_CAPUNSUPPORTED:
1076  return "Capability not supported by source";
1077  break;
1078 
1079  case TWCC_CAPBADOPERATION:
1080  return "Operation not supported by capability";
1081  break;
1082 
1083  case TWCC_CAPSEQERROR:
1084  return "Capability has dependancy on other capability";
1085  break;
1086 
1087  case TWCC_DENIED:
1088  return "File System operation is denied (file is protected)";
1089  break;
1090 
1091  case TWCC_FILEEXISTS:
1092  return "Operation failed because file already exists.";
1093  break;
1094 
1095  case TWCC_FILENOTFOUND:
1096  return "File not found";
1097  break;
1098 
1099  case TWCC_NOTEMPTY:
1100  return "Operation failed because directory is not empty";
1101  break;
1102 
1103  case TWCC_PAPERJAM:
1104  return "The feeder is jammed";
1105  break;
1106 
1107  case TWCC_PAPERDOUBLEFEED:
1108  return "The feeder detected multiple pages";
1109  break;
1110 
1111  case TWCC_FILEWRITEERROR:
1112  return "Error writing the file (meant for things like disk full conditions)";
1113  break;
1114 
1115  case TWCC_CHECKDEVICEONLINE:
1116  return "The device went offline prior to or during this operation";
1117  break;
1118  }
1119 
1120  static TW_STR32 hex;
1121  SSNPRINTF((char*)hex, NCHARS(hex), 32, "TWCC 0x%04x", cc);
1122 
1123  return (char*)hex;
1124 }
1125 
1126 
1127 
1137 int CTwnDsmAppsImpl::scanDSDir(char *_szAbsPath,
1138  TW_IDENTITY *_pAppId)
1139 {
1140  // Validate...
1141  if ( !_szAbsPath
1142  || !_pAppId)
1143  {
1144  return EXIT_FAILURE;
1145  }
1146 
1147  //
1148  // Take care of VC++...
1149  //
1150  #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
1151  WIN32_FIND_DATA FileData; // Data structure describes the file found
1152  HANDLE hSearch; // Search handle returned by FindFirstFile
1153  char szABSFilename[FILENAME_MAX];
1154  BOOL bFinished = FALSE;
1155  char szPrevWorkDir[FILENAME_MAX];
1156 
1157  // Start searching for .ds files in the root directory.
1158  SSTRCPY(szABSFilename, NCHARS(szABSFilename), _szAbsPath);
1159  SSTRCAT(szABSFilename, NCHARS(szABSFilename), "\\*.ds");
1160  hSearch = FindFirstFile(szABSFilename,&FileData);
1161 
1162  // If we find something, squirrel it away and anything else we find...
1163  if (hSearch != INVALID_HANDLE_VALUE)
1164  {
1165  /* Save the current working directory: */
1166  char *szResult = _getcwd( szPrevWorkDir, sizeof(szPrevWorkDir) );
1167  if (szResult == (char*)NULL)
1168  {
1169  return EXIT_FAILURE;
1170  }
1171  int iResult = _chdir(_szAbsPath);
1172  if (iResult != 0)
1173  {
1174  return EXIT_FAILURE;
1175  }
1176 
1177  while (!bFinished)
1178  {
1179  if (SSNPRINTF(szABSFilename, NCHARS(szABSFilename), FILENAME_MAX, "%s\\%s", _szAbsPath, FileData.cFileName) > 0)
1180  {
1181  if (TWRC_SUCCESS == LoadDS(_pAppId,
1182  szABSFilename,
1183  m_AppInfo[(TWID_T)_pAppId->Id].pDSList->NumFiles+1,
1184  false))
1185  {
1186  m_AppInfo[(TWID_T)_pAppId->Id].pDSList->NumFiles++;
1187  }
1188  }
1189 
1190  if (!FindNextFile(hSearch, &FileData))
1191  {
1192  bFinished = TRUE;
1193  }
1194  }
1195 
1196  if (!FindClose (hSearch))
1197  {
1198  (void)_chdir( szPrevWorkDir );
1199  return EXIT_FAILURE;
1200  }
1201  }
1202 
1203  // Start searching sub directories.
1204  SSTRCPY(szABSFilename, NCHARS(szABSFilename), _szAbsPath);
1205  SSTRCAT(szABSFilename, NCHARS(szABSFilename), "\\*.*");
1206  hSearch = FindFirstFile(szABSFilename, &FileData);
1207  bFinished = FALSE;
1208  if (hSearch == INVALID_HANDLE_VALUE)
1209  {
1210  (void)_chdir( szPrevWorkDir );
1211  return EXIT_FAILURE;
1212  }
1213  while (!bFinished)
1214  {
1215  if ( (strcmp(".", FileData.cFileName) != 0)
1216  && (strcmp("..", FileData.cFileName) != 0)
1217  && (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
1218  {
1219  if (SSNPRINTF(szABSFilename, NCHARS(szABSFilename), FILENAME_MAX, "%s\\%s", _szAbsPath, FileData.cFileName) > 0)
1220  {
1221  scanDSDir(szABSFilename,_pAppId);
1222  }
1223  }
1224 
1225  if (!FindNextFile(hSearch, &FileData))
1226  {
1227  bFinished = TRUE;
1228  }
1229  }
1230 
1231  (void)_chdir( szPrevWorkDir );
1232 
1233  if (!FindClose (hSearch))
1234  {
1235  return EXIT_FAILURE;
1236  }
1237 
1238  return EXIT_SUCCESS;
1239 
1240 
1241 
1242  //
1243  // Take care of g++...
1244  //
1245  #elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP)
1246  #if (TWNDSM_OS == TWNDSM_OS_MACOSX)
1247 
1248  char szABSFilename[FILENAME_MAX];
1249  DIR *pdir;
1250 
1251  // Initialize...
1252  pdir = 0;
1253  memset(szABSFilename,0,sizeof(szABSFilename));
1254 
1255  // Open the directory...
1256  if ((pdir=opendir(_szAbsPath)) == 0)
1257  {
1258  perror("opendir");
1259  return EXIT_FAILURE;
1260  }
1261 
1262  struct dirent *pfile;
1263  while(errno=0, ((pfile=readdir(pdir)) != 0))
1264  {
1265  if ( (strcmp(".", pfile->d_name) == 0)
1266  || (strcmp("..", pfile->d_name) == 0) )
1267  {
1268  continue;
1269  }
1270 
1271  if (SNPRINTF(szABSFilename,FILENAME_MAX,"%s/%s",_szAbsPath,pfile->d_name) < 0)
1272  {
1273  continue;
1274  }
1275 
1276  struct stat st;
1277  if (lstat(szABSFilename, &st) < 0)
1278  {
1279  perror("lstat");
1280  continue;
1281  }
1282 
1283  if (S_ISDIR(st.st_mode) && (0 != strstr(pfile->d_name, ".ds")))
1284  {
1285  if (TWRC_SUCCESS == LoadDS(_pAppId,
1286  szABSFilename,
1287  m_AppInfo[(TWID_T)_pAppId->Id].pDSList->NumFiles+1,
1288  false))
1289  {
1290  m_AppInfo[(TWID_T)_pAppId->Id].pDSList->NumFiles++;
1291  }
1292  }
1293  }
1294 
1295  if (0 != errno)
1296  {
1297  perror("readdir");
1298  }
1299 
1300  closedir(pdir);
1301  return EXIT_SUCCESS;
1302 
1303  #else
1304 
1305  char szABSFilename[FILENAME_MAX];
1306  DIR *pdir;
1307 
1308  // Initialize...
1309  pdir = 0;
1310  memset(szABSFilename,0,sizeof(szABSFilename));
1311 
1312  // Open the directory...
1313  if ((pdir=opendir(_szAbsPath)) == 0)
1314  {
1315  perror("opendir");
1316  return EXIT_FAILURE;
1317  }
1318 
1319  struct dirent *pfile;
1320  while(errno=0, ((pfile=readdir(pdir)) != 0))
1321  {
1322  if ( (strcmp(".", pfile->d_name) == 0)
1323  || (strcmp("..", pfile->d_name) == 0) )
1324  {
1325  continue;
1326  }
1327 
1328  if (SNPRINTF(szABSFilename,FILENAME_MAX,"%s/%s",_szAbsPath,pfile->d_name) < 0)
1329  {
1330  continue;
1331  }
1332 
1333  struct stat st;
1334  if (lstat(szABSFilename, &st) < 0)
1335  {
1336  perror("lstat");
1337  continue;
1338  }
1339 
1340  if (S_ISDIR(st.st_mode))
1341  {
1342  scanDSDir(szABSFilename,_pAppId);
1343  }
1344  else if (S_ISREG(st.st_mode) && (0 != strstr(pfile->d_name, ".ds")))
1345  {
1346  if (TWRC_SUCCESS == LoadDS(_pAppId,
1347  szABSFilename,
1348  m_AppInfo[(TWID_T)_pAppId->Id].pDSList->NumFiles+1,
1349  false))
1350  {
1351  m_AppInfo[(TWID_T)_pAppId->Id].pDSList->NumFiles++;
1352  }
1353  }
1354  }
1355 
1356  if (0 != errno)
1357  {
1358  perror("readdir");
1359  }
1360 
1361  closedir(pdir);
1362  return EXIT_SUCCESS;
1363 
1364  #endif
1365 
1366  //
1367  // meh!
1368  //
1369  #else
1370  #error Sorry, we do not recognize this system...
1371  #endif
1372 }
1373 
1374 
1375 
1381  TWID_T _DsId)
1382 {
1383  // Load the specified driver...
1384  if ( AppValidateId(_pAppId)
1385  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
1386  && (_DsId < MAX_NUM_DS))
1387  {
1388  #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
1389  // Make the DS directory the current directoy while we load the DS so that any DLLs that
1390  // are loaded with the DS can be found.
1391  char *szResult;
1392  char szPrevWorkDir[FILENAME_MAX];
1393  char szWorkDir[FILENAME_MAX];
1394 
1395  SSTRCPY(szWorkDir, NCHARS(szWorkDir), m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].szPath);
1396  // strip filename from path
1397  size_t x = strlen(szWorkDir);
1398  while(x > 0)
1399  {
1400  if(PATH_SEPERATOR == szWorkDir[x-1])
1401  {
1402  szWorkDir[x-1] = 0;
1403  break;
1404  }
1405  --x;
1406  }
1407  /* Save the current working directory: */
1408  memset( szPrevWorkDir, 0, NCHARS(szPrevWorkDir) );
1409  szResult = _getcwd( szPrevWorkDir, NCHARS(szPrevWorkDir) );
1410  if (!szResult)
1411  {
1412  kLOG((kLOGERR, "_getcwd failed..."));
1413  }
1414  (void)_chdir( szWorkDir );
1415  #endif
1416 
1417  TW_INT16 result = m_ptwndsmappsimpl->LoadDS(_pAppId,
1418  m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].szPath,
1419  _DsId,
1420  true);
1421  #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
1422  if(0!=strlen(szPrevWorkDir))
1423  {
1424  (void)_chdir( szPrevWorkDir );
1425  }
1426  #endif
1427  return result;
1428  }
1429  // Something is toasted, so return LoadDS...
1430  else
1431  {
1432  kLOG((kLOGERR,"Returning TWRC_FAILURE from LoadDS..."));
1433  return TWRC_FAILURE;
1434  }
1435 }
1436 
1437 
1438 
1447  char *_pPath,
1448  TWID_T _DsId,
1449  bool _boolKeepOpen)
1450 {
1451  TW_INT16 result = TWRC_SUCCESS;
1452  DS_INFO *pDSInfo;
1453  bool hook;
1454  TW_IDENTITY_LINUX64SAFE twidentitylinux64safe;
1455  char szUseAppid[8];
1456 
1457  // Validate...
1458  if ( 0 == _pPath )
1459  {
1460  // bad path
1461  kLOG((kLOGERR,"bad path."));
1462  AppSetConditionCode(_pAppId,TWCC_OPERATIONERROR);
1463  return TWRC_FAILURE;
1464  }
1465  if ( _DsId >= MAX_NUM_DS )
1466  {
1467  // too many DS's already open
1468  kLOG((kLOGINFO,"Too many DS's already open."));
1469  AppSetConditionCode(_pAppId,TWCC_OPERATIONERROR);
1470  return TWRC_FAILURE;
1471  }
1472 
1473  // For Linux we only support the native architecture, so if
1474  // a 32-bit process tries to run on an x86_64 system we expect
1475  // it to fail. However, we can't rule out that somebody
1476  // might try to make this work. So we'll check the file...
1477  #if (TWNDSM_OS == TWNDSM_OS_LINUX)
1478  bool blSuccess = false;
1479  char szData[2048] = { 0 };
1480  snprintf(szData, sizeof(szData), "file \"%s\"", _pPath);
1481  FILE *pf = popen(szData, "r");
1482  if (pf)
1483  {
1484  szData[0] = 0;
1485  size_t sizet = fread(szData, 1, sizeof(szData), pf);
1486  szData[sizet] = 0;
1487  #if (TWNDSM_OS_64BIT == 1)
1488  blSuccess = (strstr(szData, "x86-64") != 0);
1489  #else
1490  blSuccess = (strstr(szData, "Intel 80386") != 0);
1491  #endif
1492  pclose(pf);
1493  pf = 0;
1494  }
1495  if (!blSuccess)
1496  {
1497  kLOG((kLOGINFO, "driver doesn't support architecture: %s", _pPath));
1498  AppSetConditionCode(_pAppId, TWCC_OPERATIONERROR);
1499  return TWRC_FAILURE;
1500  }
1501  #endif
1502 
1503  // Mac has universal binaries which may or may not have what we
1504  // need. For instance, we can't load an image that only has
1505  // i386 content if we're running in an x86_64 process. So we're
1506  // using file(1) to filter content...
1507  #if (TWNDSM_OS == TWNDSM_OS_MACOSX)
1508  bool blSuccess = false;
1509  char szData[2048] = { 0 };
1510  snprintf(szData, sizeof(szData), "file \"%s/Contents/MacOS/$(/usr/libexec/PlistBuddy -c 'Print CFBundleExecutable' '%s/Contents/Info.plist')\"", _pPath, _pPath);
1511  FILE *pf = popen(szData, "r");
1512  if (pf)
1513  {
1514  szData[0] = 0;
1515  size_t sizet = fread(szData, 1, sizeof(szData), pf);
1516  szData[sizet] = 0;
1517  #if (TWNDSM_OS_64BIT == 1)
1518  blSuccess = (strstr(szData, "x86_64") != 0);
1519  #else
1520  blSuccess = (strstr(szData, "i386") != 0);
1521  #endif
1522  pclose(pf);
1523  pf = 0;
1524  }
1525  if (!blSuccess)
1526  {
1527  kLOG((kLOGINFO, "driver doesn't support architecture: %s", _pPath));
1528  AppSetConditionCode(_pAppId, TWCC_OPERATIONERROR);
1529  return TWRC_FAILURE;
1530  }
1531  #endif
1532 
1533  // Initialize stuff...
1534  pDSInfo = &m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId];
1535 
1536  // Only log DS details when processing a MSG_OPENDS message
1537  if(_boolKeepOpen)
1538  {
1539  kLOG((kLOGINFO,"Datasource: \"%0.32s\"", pDSInfo->Identity.Manufacturer));
1540  kLOG((kLOGINFO," \"%0.32s\"", pDSInfo->Identity.ProductFamily));
1541  kLOG((kLOGINFO," \"%0.32s\" version: %u.%u", pDSInfo->Identity.ProductName, pDSInfo->Identity.Version.MajorNum, pDSInfo->Identity.Version.MinorNum));
1542  kLOG((kLOGINFO," TWAIN %u.%u", pDSInfo->Identity.ProtocolMajor, pDSInfo->Identity.ProtocolMinor));
1543  }
1544 
1545  // Only hook this driver if we've been asked to keep the driver
1546  // open (meaning we're processing a MSG_OPENDS) and if we see
1547  // that the driver is 1.x...(by checking the absence of DF_DS2)
1548  hook = _boolKeepOpen && !(pDSInfo->Identity.SupportedGroups & DF_DS2);
1549 
1550  // Try to load the driver... We load the driver again if we are keeping
1551  // it open. This LoadLibrary is always closed so we dont hook this time.
1552  pDSInfo->pHandle = (TW_HANDLE)LOADLIBRARY(_pPath,false,0);
1553  #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
1554  if (0 == pDSInfo->pHandle)
1555  {
1556  kLOG((kLOGERR,"Could not load library: %s",_pPath));
1557  AppSetConditionCode(_pAppId,TWCC_OPERATIONERROR);
1558  return TWRC_FAILURE;
1559  }
1560  #elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP)
1561  if (0 == pDSInfo->pHandle)
1562  {
1563  // This is a bit skanky, and not the sort of thing I really want
1564  // a user to have to see, but more info is better than less, so
1565  // hopefully someone will be able to sort out what the cryptic
1566  // message means and we can FAQ it...
1567  fprintf(stderr,">>> error loading <%s>\r\n",_pPath);
1568  fprintf(stderr,">>> %s\r\n",dlerror());
1569  fprintf(stderr,">>> please contact your scanner or driver vendor for more\r\n");
1570  fprintf(stderr,">>> help, if that doesn't help then check out the FAQ at\r\n");
1571  fprintf(stderr,">>> http://www.twain.org\r\n");
1572  kLOG((kLOGERR,"Could not load library: %s",_pPath));
1573  kLOG((kLOGERR,dlerror()));
1574  AppSetConditionCode(_pAppId,TWCC_OPERATIONERROR);
1575  return TWRC_FAILURE;
1576  }
1577  #else
1578  #error Sorry, we do not recognize this system...
1579  #endif
1580 
1581  // Try to get the entry point...
1582  pDSInfo->DS_Entry = (DSENTRYPROC)DSM_LoadFunction(pDSInfo->pHandle,"DS_Entry");
1583 
1584  if (pDSInfo->DS_Entry == 0)
1585  {
1586  #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
1587  // The WIATwain.ds does not have an entry point
1588  if (0 != strstr(_pPath, "wiatwain.ds"))
1589  {
1590  kLOG((kLOGERR, "We're deliberately skipping this file: %s", _pPath));
1591  }
1592  else
1593  {
1594  pDSInfo->DS_Entry = (DSENTRYPROC)GetProcAddress((HMODULE)pDSInfo->pHandle, MAKEINTRESOURCE(1));
1595 
1596  if (pDSInfo->DS_Entry == 0)
1597  {
1598  kLOG((kLOGINFO, "Could not find Entry 1 in DS: %s", _pPath));
1599  }
1600  }
1601  #else
1602  kLOG((kLOGERR, "Could not find DS_Entry function in DS: %s", _pPath));
1603  #endif
1604  if (pDSInfo->DS_Entry == 0)
1605  {
1606  (void)UNLOADLIBRARY(pDSInfo->pHandle, false, 0);
1607  pDSInfo->pHandle = NULL;
1608  AppSetConditionCode(_pAppId, TWCC_OPERATIONERROR);
1609  return TWRC_FAILURE;
1610  }
1611  }
1612 
1613  // Allllrighty then! So the original TWAIN_32.DLL passes in
1614  // a value of NULL for the origin. This is not documented
1615  // anywhere in the TWAIN Spec. It was decided to maintain this
1616  // behavior in TWAINDSM.DLL. All fine and well for Window and
1617  // Linux. But Mac had it's own DSM, and it didn't pass in a
1618  // NULL. So now we have a conundrum.
1619  //
1620  // I'm adding an event variable so that an application can
1621  // override stuff, but the default behavior is going to be:
1622  // Windows - NULL
1623  // Linux - _pAppId
1624  // Mac - _pAppId
1625  memset(&szUseAppid, 0, sizeof(szUseAppid));
1626  SGETENV(szUseAppid, NCHARS(szUseAppid), "TWAINDSM_USEAPPID");
1627  // No data received, set the default based on the platform...
1628  if (szUseAppid[0] != 0)
1629  {
1630  #if (TWNDSM_OS == TWNDSM_OS_WINDOWS)
1631  szUseAppid[0] = '0'; // Windows is NULL
1632  #elif (TWNDSM_OS == TWNDSM_OS_LINUX)
1633  szUseAppid[0] = '1'; // Linux is _pAppId
1634  #elif (TWNDSM_OS == TWNDSM_OS_MACOSX)
1635  szUseAppid[0] = '1'; // Linux is _pAppId
1636  #else
1637  Unsupported...
1638  #endif
1639  }
1640  // Otherwise, force the value to be '0' or '1'...
1641  else if (szUseAppid[0] != '0')
1642  {
1643  szUseAppid[0] = '1';
1644  }
1645 
1646  // Report success and squirrel away the index...
1647  kLOG((kLOGINFO, "Loaded library: %s (TWAINDSM_USEAPPID:%c)", _pPath, szUseAppid[0]));
1648  pDSInfo->Identity.Id = (TWIDDEST_T)_DsId;
1649 
1650  // Get the source to fill in the identity structure
1651  // This operation should never fail on any DS
1652  //
1653  // We need the NULL to be backwards compatible with the
1654  // older DSM. This is the only way a driver can tell if
1655  // it's being talked to directly by the DSM instead of
1656  // by the application (with the DSM as a passthru).
1657  //
1658  // Okay, this is where we make the actual call. I left
1659  // the original comments in place...
1660  memset(&twidentitylinux64safe, 0, sizeof(twidentitylinux64safe));
1661  twidentitylinux64safe.twidentity.Id = (TWIDDEST_T)_DsId;
1662  if (szUseAppid[0] == '1')
1663  {
1664  // this is what the spec calls for
1665  result = pDSInfo->DS_Entry(_pAppId, DG_CONTROL, DAT_IDENTITY, MSG_GET, (TW_MEMREF)&twidentitylinux64safe);
1666  }
1667  else
1668  {
1669  // this is out of spec, but we need it for Windows
1670  result = pDSInfo->DS_Entry(NULL, DG_CONTROL, DAT_IDENTITY, MSG_GET, (TW_MEMREF)&twidentitylinux64safe);
1671  }
1672  if (result != TWRC_SUCCESS)
1673  {
1674  (void)UNLOADLIBRARY(pDSInfo->pHandle,false,0);
1675  pDSInfo->pHandle = NULL;
1676  pDSInfo->DS_Entry = NULL;
1677  kLOG((kLOGINFO, "DG_CONTROL,DAT_IDENTITY,MSG_GET failed"));
1678  AppSetConditionCode(_pAppId,TWCC_OPERATIONERROR);
1679  return TWRC_FAILURE;
1680  }
1681 
1682  // We're going to do a sanity check on the data if we
1683  // are running on Linux as a 64-bit process. This is
1684  // because we messed up the definition of TW_INT32 and
1685  // TW_UINT32, making them 64-bit values (based on long)
1686  // rather than 32-bit values (based on int). Starting
1687  // with TWAIN 2.4 this is fixed, but we have to be able
1688  // to handle old drivers. These will be in trouble
1689  // because their Id and SupportedGroups will be 64-bit,
1690  // shifting data in the structure.
1691  //
1692  // This is a heuristic, meaning that it's possible to
1693  // get it wrong. Add as many checks as possible. All
1694  // TWAIN drivers must support DG_CONTROL and DG_IMAGE,
1695  // and we're going to validate a whole mess of protocol
1696  // versions...
1697  #if (TWNDSM_OS == TWNDSM_OS_LINUX) && (TWNDSM_OS_64BIT == 1)
1698  if ( ((twidentitylinux64safe.twidentity.SupportedGroups & (DG_CONTROL | DG_IMAGE)) == (DG_CONTROL | DG_IMAGE))
1699  && (((twidentitylinux64safe.twidentity.ProtocolMajor >= 3) && (twidentitylinux64safe.twidentity.ProtocolMinor <= 9))
1700  || ((twidentitylinux64safe.twidentity.ProtocolMajor == 2) && (twidentitylinux64safe.twidentity.ProtocolMinor >= 4) && (twidentitylinux64safe.twidentity.ProtocolMinor <= 9))
1701  || ((twidentitylinux64safe.twidentity.ProtocolMajor == 1) && (twidentitylinux64safe.twidentity.ProtocolMinor == 5))
1702  || ((twidentitylinux64safe.twidentity.ProtocolMajor == 1) && (twidentitylinux64safe.twidentity.ProtocolMinor == 6))
1703  || ((twidentitylinux64safe.twidentity.ProtocolMajor == 1) && (twidentitylinux64safe.twidentity.ProtocolMinor == 7))
1704  || ((twidentitylinux64safe.twidentity.ProtocolMajor == 1) && (twidentitylinux64safe.twidentity.ProtocolMinor == 8))
1705  || ((twidentitylinux64safe.twidentity.ProtocolMajor == 1) && (twidentitylinux64safe.twidentity.ProtocolMinor == 9))
1706  || ((twidentitylinux64safe.twidentity.ProtocolMajor == 1) && (twidentitylinux64safe.twidentity.ProtocolMinor == 91))
1707  || ((twidentitylinux64safe.twidentity.ProtocolMajor == 2) && (twidentitylinux64safe.twidentity.ProtocolMinor == 0))
1708  || ((twidentitylinux64safe.twidentity.ProtocolMajor == 2) && (twidentitylinux64safe.twidentity.ProtocolMinor == 1))
1709  || ((twidentitylinux64safe.twidentity.ProtocolMajor == 2) && (twidentitylinux64safe.twidentity.ProtocolMinor == 2))
1710  || ((twidentitylinux64safe.twidentity.ProtocolMajor == 2) && (twidentitylinux64safe.twidentity.ProtocolMinor == 3))))
1711  {
1712  // We're good, keep going...
1713  }
1714  else
1715  {
1716  (void)UNLOADLIBRARY(pDSInfo->pHandle,false,0);
1717  pDSInfo->pHandle = NULL;
1718  pDSInfo->DS_Entry = NULL;
1719  kLOG((kLOGINFO,"DG_CONTROL,DAT_IDENTITY,MSG_GET failed (rejected as old 64-bit TW_INT32/TW_UINT32)"));
1720  AppSetConditionCode(_pAppId,TWCC_OPERATIONERROR);
1721  return TWRC_FAILURE;
1722  }
1723  #endif
1724 
1725  // Okay, we can keep this TW_IDENTITY, so copy it over,
1726  // but be careful to use the TW_IDENTITY size...
1727  memcpy(&pDSInfo->Identity, &twidentitylinux64safe.twidentity, sizeof(pDSInfo->Identity));
1728 
1729  // Compare the supported groups. Note that the & is correct
1730  // because we are comparing bits...
1731  // we do not want to compare DG_CONTROL because is it supported by all
1732  if ( !( (_pAppId->SupportedGroups & DG_MASK & ~DG_CONTROL) // app supports
1733  & (pDSInfo->Identity.SupportedGroups & DG_MASK & ~DG_CONTROL) ) ) // source supports
1734  {
1735  (void)UNLOADLIBRARY(pDSInfo->pHandle,false,0);
1736  pDSInfo->pHandle = NULL;
1737  pDSInfo->DS_Entry = NULL;
1738  kLOG((kLOGINFO,"The SupportedGroups do not match."));
1739  AppSetConditionCode(_pAppId,TWCC_OPERATIONERROR);
1740  return TWRC_FAILURE;
1741  }
1742 
1743  // The DS should not modify the Id even though the spec states
1744  // that the id will not be assigned until DSM sends MSG_OPENDS to DS, and
1745  // by the way...don't do the copy of the src and dst are the same address...
1746  pDSInfo->Identity.Id = (TWIDDEST_T)_DsId;
1747  if (pDSInfo->szPath != _pPath)
1748  {
1749  SSTRNCPY(pDSInfo->szPath, NCHARS(pDSInfo->szPath),_pPath,FILENAME_MAX);
1750  }
1751 
1752  // We clear the library to avoid cluttering up the virtual address space, and
1753  // to prevent scary weirdness that can result from multiple drivers being
1754  // loaded (if the application wants to load multiple drivers, that's its risk).
1755  (void)UNLOADLIBRARY(pDSInfo->pHandle,false,0);
1756  pDSInfo->pHandle = NULL;
1757  pDSInfo->DS_Entry = NULL;
1758 
1759  // At this point you're probably scratching your head. Here's the deal.
1760  // When the DSM issues DG_CONTROL/DAT_IDENTITY/MSG_GET without an
1761  // AppIdentity structure it alerts the driver that it's being called by
1762  // the DSM and not by the application, most likely to bring up the user
1763  // selection dialog. A driver should use this information to create --
1764  // and more importantly -- to destroy its internal data structures,
1765  // because it will get no other chance to clean itself up.
1766  //
1767  // It's worth interjecting at this point that Microsoft warns against
1768  // any but the most minimal activity in DllMain, so relying on doing
1769  // the create/destroy in there is very risky. The same goes for the
1770  // __attribute(constructor)/__attribute(destructor) with GNU.
1771  //
1772  // The problem is that the DSM issues DG_CONTROL/DAT_IDENTITY/MSG_GET
1773  // just prior to DG_CONTROL/DAT_IDENTITY/MSG_OPEN. If a driver is keyed
1774  // to the AppIdentity being NULL, it'll incorrectly clean itself up.
1775  //
1776  // This means we need to unload and reload the library, to give the
1777  // driver a consistent look.
1778  if (_boolKeepOpen == true)
1779  {
1780  pDSInfo->pHandle = (TW_HANDLE)LOADLIBRARY(_pPath,hook,_DsId);
1781  #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
1782  if (0 == pDSInfo->pHandle)
1783  {
1784  kLOG((kLOGERR,"Could not load library: %s",_pPath));
1785  AppSetConditionCode(_pAppId,TWCC_OPERATIONERROR);
1786  return TWRC_FAILURE;
1787  }
1788  #elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP)
1789  if (0 == pDSInfo->pHandle)
1790  {
1791  // This is a bit skanky, and not the sort of thing I really want
1792  // a user to have to see, but more info is better than less, so
1793  // hopefully someone will be able to sort out what the cryptic
1794  // message means and we can FAQ it...
1795  fprintf(stderr,">>> error loading <%s>\r\n",_pPath);
1796  fprintf(stderr,">>> %s\r\n",dlerror());
1797  fprintf(stderr,">>> please contact your scanner or driver vendor for more\r\n");
1798  fprintf(stderr,">>> help, if that doesn't help then check out the FAQ at\r\n");
1799  fprintf(stderr,">>> http://www.twain.org\r\n");
1800  kLOG((kLOGERR,"Could not load library: %s",_pPath));
1801  kLOG((kLOGERR,dlerror()));
1802  AppSetConditionCode(_pAppId,TWCC_OPERATIONERROR);
1803  return TWRC_FAILURE;
1804  }
1805  #else
1806  #error Sorry, we do not recognize this system...
1807  #endif
1808 
1809  // Try to get the entry point...
1810  pDSInfo->DS_Entry = (DSENTRYPROC)DSM_LoadFunction(pDSInfo->pHandle,"DS_Entry");
1811  if (pDSInfo->DS_Entry == 0)
1812  {
1813  #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
1814  // The WIATwain.ds does not have an entry point
1815  if(0 != strstr(_pPath, "wiatwain.ds"))
1816  {
1817  kLOG((kLOGERR,"We're deliberately skipping this file: %s",_pPath));
1818  }
1819  else
1820  {
1821  pDSInfo->DS_Entry = (DSENTRYPROC)GetProcAddress((HMODULE)pDSInfo->pHandle, MAKEINTRESOURCE(1));
1822 
1823  if (pDSInfo->DS_Entry == 0)
1824  {
1825  kLOG((kLOGINFO,"Could not find Entry 1 in DS: %s",_pPath));
1826  }
1827  }
1828  #else
1829  kLOG((kLOGERR,"Could not find DS_Entry function in DS: %s",_pPath));
1830  #endif
1831  if (pDSInfo->DS_Entry == 0)
1832  {
1833  (void)UNLOADLIBRARY(pDSInfo->pHandle,false,0);
1834  pDSInfo->pHandle = NULL;
1835  AppSetConditionCode(_pAppId,TWCC_OPERATIONERROR);
1836  return TWRC_FAILURE;
1837  }
1838  }
1839  }
1840 
1841  // All done...
1842  return result;
1843 }
1844 
1854  TWID_T _DsId)
1855 {
1856  int retval = 0;
1857 
1858  // Unload the specified driver...
1859  if ( AppValidateId(_pAppId)
1860  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList
1861  && (_DsId < MAX_NUM_DS)
1862  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].pHandle)
1863  {
1864  // Unload the library...
1865  retval = UNLOADLIBRARY(m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].pHandle,true,_DsId);
1866 
1867  // Log if something bad happens...
1868  #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
1869  if(0 == retval)
1870  {
1871  kLOG((kLOGERR,"failed to unload datasource"));
1872  }
1873  #else
1874  if(0 != retval)
1875  {
1876  kLOG((kLOGERR,"dlclose: %s",dlerror()));
1877  }
1878  #endif
1879 
1880  m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].DS_Entry = 0;
1881  m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].pDSList->DSInfo[_DsId].pHandle = 0;
1882  }
1883 }
1884 
1885 
1886 
1894 {
1895  #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
1896  BOOL boolResult;
1897  if ( AppValidateId(_pAppId)
1898  && m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].hwnd)
1899  {
1900  // Force the parent to process a message. WM_NULL is
1901  // safe, because it's a no-op...
1902  boolResult = ::PostMessage(m_ptwndsmappsimpl->m_AppInfo[(TWID_T)_pAppId->Id].hwnd,WM_NULL,(WPARAM)0,(LPARAM)0);
1903  if (!boolResult)
1904  {
1905  kLOG((kLOGERR,"PostMessage failed..."));
1906  }
1907  }
1908  #elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP)
1909  kLOG((kLOGERR,"We shouldn't be here in AppWakeup..."));
1910  // We don't support this path on this platform, use
1911  // callbacks instead...
1912  // Make the compiler happy...
1913  void *unused = _pAppId;
1914  unused = 0;
1915  #else
1916  #error Sorry, we do not recognize this system...
1917  #endif
1918 }
dsm.h
Everything we need to make our .cpp files happy.
LOADLIBRARY
#define LOADLIBRARY(lib, hook, DSID)
Call system loadibrary function.
Definition: dsm.h:280
DS_INFO::bAppProcessingCallback
TW_BOOL bAppProcessingCallback
True if the application is still waiting for the DS to return from processing a message.
Definition: apps.cpp:53
CTwnDsmApps::AppSetConditionCode
void AppSetConditionCode(TW_IDENTITY *_pAppId, TW_UINT16 _conditioncode)
Set the condition code.
Definition: apps.cpp:647
TW_PENDINGXFERS
Definition: twain.h:543
CTwnDsmAppsImpl
Impl Class to hold list of connected applications.
Definition: apps.cpp:241
kLOGINFO
#define kLOGINFO
write info messages to LogFile.
Definition: dsm.h:485
CTwnDsmApps::DsSetProcessingMessage
void DsSetProcessingMessage(TW_IDENTITY *_pAppId, TWID_T _DsId, TW_BOOL _Processing)
Set the ProcessingMessage flag.
Definition: apps.cpp:958
CTwnDsmApps::DsGetPath
char * DsGetPath(TW_IDENTITY *_pAppId, TWID_T _DsId)
Get a pointer to the driver file path and name, which is guaranteed to be unique, even if the Product...
Definition: apps.cpp:834
APP_INFO::hwnd
HWND hwnd
the window that will monitor for events on Windows
Definition: apps.cpp:107
CTwnDsmAppsImpl::StringFromCC
const char * StringFromCC(const TW_UINT16 cc)
Translates the cc passed in into a string and returns it.
Definition: apps.cpp:1027
CTwnDsmApps::AddApp
TW_UINT16 AddApp(TW_IDENTITY *_pAppId, TW_MEMREF _MemRef)
Add an application.
Definition: apps.cpp:364
CAppList::size
TWID_T size()
Get number of allocated App slots (Last valid App ID +1)
Definition: apps.cpp:147
CTwnDsmApps::m_ptwndsmappsimpl
CTwnDsmAppsImpl * m_ptwndsmappsimpl
The implementation pointer helps with encapulation.
Definition: dsm.h:845
APP_INFO::ConditionCode
TW_INT16 ConditionCode
the apps condition code.
Definition: apps.cpp:104
CTwnDsmApps::AppValidateId
TW_BOOL AppValidateId(TW_IDENTITY *_pAppId)
Validate that an id is in range...
Definition: apps.cpp:541
SNPRINTF
#define SNPRINTF
OS abstraction macro that calls system _snprintf function.
Definition: dsm.h:292
CTwnDsmAppsImpl::scanDSDir
int scanDSDir(char *_szAbsPath, TW_IDENTITY *_pAppId)
Scan for Data Sources.
Definition: apps.cpp:1137
TW_VERSION
Definition: twain.h:434
CTwnDsmApps::DsGetIdentity
TW_IDENTITY * DsGetIdentity(TW_IDENTITY *_pAppId, TWID_T _DsId)
Get a pointer to the identity of the specified driver...
Definition: apps.cpp:785
APP_INFO
Structure to hold data about a connected application, we use DS_LIST so we don't have to allocate mem...
Definition: apps.cpp:102
SGETENV
#define SGETENV(d, z, n)
Secure Get enviroment varable.
Definition: dsm.h:404
kLOGERR
#define kLOGERR
write error messages to LogFile.
Definition: dsm.h:490
CTwnDsmApps::DsCallbackSetWaiting
void DsCallbackSetWaiting(TW_IDENTITY *_pAppId, TWID_T _DsId, TW_BOOL _Waiting)
Set the callback flag for the driver to TRUE if the callback needs to have its callback called,...
Definition: apps.cpp:909
TW_USERINTERFACE
Definition: twain.h:612
kTWAIN_DS_DIR
#define kTWAIN_DS_DIR
The path to where TWAIN Data Sources are stored on the system.
Definition: dsm.h:305
APP_INFO::identity
TW_IDENTITY identity
the application's identity.
Definition: apps.cpp:103
APP_INFO::CurrentState
DSM_State CurrentState
the current state of the DSM for this app.
Definition: apps.cpp:105
DS_INFO::DS_Entry
DSENTRYPROC DS_Entry
function pointer to the DS_Entry function – set by dlsym(...)
Definition: apps.cpp:48
CTwnDsmApps::RemoveApp
TW_UINT16 RemoveApp(TW_IDENTITY *_pAppId)
Remove an application.
Definition: apps.cpp:465
CAppList::Erase
bool Erase(TWID_T AppId)
Erase element from the array Unallocate memory if element is last one, else clear CurrentState.
Definition: apps.cpp:179
TW_IDENTITY
Definition: twain.h:443
dsmState_PreSession
@ dsmState_PreSession
Source Manager not loaded.
Definition: dsm.h:532
CTwnDsmAppsImpl::pod
struct CTwnDsmAppsImpl::_pod pod
Pieces of data for CTwnDsmAppsImpl.
CTwnDsmApps::DsCallbackIsWaiting
TW_BOOL DsCallbackIsWaiting(TW_IDENTITY *_pAppId, TWID_T _DsId)
Test if the driver has a callback pending for attention...
Definition: apps.cpp:885
DS_INFO::Identity
TW_IDENTITY Identity
Identity info for data source.
Definition: apps.cpp:46
kLOG
#define kLOG(a)
Define to write messages to LogFile.
Definition: dsm.h:496
CTwnDsmAppsImpl::_pod
We use a pod (Pieces of Data) system because it help prevents us from making dumb initialization mist...
Definition: apps.cpp:302
TW_IDENTITY_LINUX64
We have to manage the horror we created for ourselves when we defined TW_INT32/TW_UINT32 to be long i...
Definition: apps.cpp:67
TW_CALLBACK2
Definition: twain.h:308
DS_INFO
Describes everything we need to know about the Data Source over the course of the session....
Definition: apps.cpp:45
SSTRNCPY
#define SSTRNCPY(d, z, s, m)
Secure String n copy.
Definition: dsm.h:403
CAppList::m_pList
APP_INFO * m_pList
pointer to dynamicaly allocated array
Definition: apps.cpp:116
CTwnDsmApps::DsIsProcessingMessage
TW_BOOL DsIsProcessingMessage(TW_IDENTITY *_pAppId, TWID_T _DsId)
Check if the DS is still processing last message.
Definition: apps.cpp:934
CTwnDsmApps::AppValidateIds
TW_BOOL AppValidateIds(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDSId)
Validate that the App ID and DS ID are in range...
Definition: apps.cpp:561
CTwnDsmApps::AppGetConditionCode
TW_UINT16 AppGetConditionCode(TW_IDENTITY *_pAppId)
Get the condition code, then reset it internally to TWCC_SUCCESS, so you can only get it once,...
Definition: apps.cpp:619
CTwnDsmApps::DsIsAppProcessingCallback
TW_BOOL DsIsAppProcessingCallback(TW_IDENTITY *_pAppId, TWID_T _DsId)
Check if the App is still processing last callback.
Definition: apps.cpp:982
CTwnDsmApps::LoadDS
TW_INT16 LoadDS(TW_IDENTITY *_pAppId, TWID_T _DsId)
Loads a DS from disk and adds it to a global list of DS's.
Definition: apps.cpp:1380
CAppList::m_count
TWID_T m_count
number of elements of the array
Definition: apps.cpp:117
CTwnDsmAppsImpl::CTwnDsmAppsImpl
CTwnDsmAppsImpl()
Our CTwnDsmAppsImpl constructor.
Definition: apps.cpp:247
DS_LIST::NumFiles
TW_UINT16 NumFiles
Number of items in list.
Definition: apps.cpp:89
SSTRCAT
#define SSTRCAT(d, z, s)
Secure String catinate.
Definition: dsm.h:402
CAppList::CAppList
CAppList()
Default constructor allocates element 0.
Definition: apps.cpp:125
dsmState_Open
@ dsmState_Open
Source Manager is open.
Definition: dsm.h:534
DS_INFO::twcallback2
TW_CALLBACK2 twcallback2
callback structure (we're using callback2 because it's 32-bit and 64-bit safe)
Definition: apps.cpp:50
CTwnDsmApps::AppGetNumDs
TWID_T AppGetNumDs(TW_IDENTITY *_pAppId)
Get the number of drivers we found as the result of a successful call to LoadDS with _boolKeepOpen se...
Definition: apps.cpp:762
DS_INFO::pHandle
TW_HANDLE pHandle
returned by LOADLIBRARY(...)
Definition: apps.cpp:47
SSTRCPY
#define SSTRCPY(d, z, s)
Secure String copy.
Definition: dsm.h:401
CAppList::Clear
bool Clear()
Erase all elements of the array.
Definition: apps.cpp:216
CAppList::operator[]
APP_INFO & operator[](TWID_T AppId)
Get reference to element of the array.
Definition: apps.cpp:155
CTwnDsmApps::DsGetEntryProc
DSENTRYPROC DsGetEntryProc(TW_IDENTITY *_pAppId, TWID_T _DsId)
Get a pointer to the DS_Entry function of the specified driver...
Definition: apps.cpp:809
CTwnDsmApps::DsCallback2Get
TW_CALLBACK2 * DsCallback2Get(TW_IDENTITY *_pAppId, TWID_T _DsId)
Get a pointer to TW_CALLBACK structure for the specified driver...
Definition: apps.cpp:860
UNLOADLIBRARY
#define UNLOADLIBRARY(hmodule, unhook, DSID)
Call system FreeLibrary function.
Definition: dsm.h:281
CTwnDsmAppsImpl::AppSetConditionCode
void AppSetConditionCode(TW_IDENTITY *_pAppId, TW_UINT16 _ConditionCode)
Set the condition code.
Definition: apps.cpp:660
CTwnDsmAppsImpl::LoadDS
TW_INT16 LoadDS(TW_IDENTITY *_pAppId, char *_pPath, TWID_T _DsId, bool _boolKeepOpen)
Loads a DS from disk and adds it to a global list of DS's.
Definition: apps.cpp:1446
DS_INFO::bCallbackPending
TW_BOOL bCallbackPending
True if an application is old style and a callback was supposed to be made to it.
Definition: apps.cpp:51
CTwnDsmApps::~CTwnDsmApps
~CTwnDsmApps()
The CTwnDsmApps destructor.
Definition: apps.cpp:328
CTwnDsmApps::UnloadDS
void UnloadDS(TW_IDENTITY *_pAppId, TWID_T _DsId)
Unloads a DS and frees all its resources...
Definition: apps.cpp:1853
TW_IDENTITY_LINUX64SAFE
Definition: apps.cpp:77
CTwnDsmApps::DsSetAppProcessingCallback
void DsSetAppProcessingCallback(TW_IDENTITY *_pAppId, TWID_T _DsId, TW_BOOL _Processing)
Set the AppProcessingCallback flag.
Definition: apps.cpp:1005
DS_LIST
Structure to hold a list of Data Sources.
Definition: apps.cpp:88
CTwnDsmApps::AppHwnd
void * AppHwnd(TW_IDENTITY *_pAppId)
Get the hwnd sent in with the call to MSG_OPENDSM.
Definition: apps.cpp:740
CAppList::~CAppList
~CAppList()
Default destructor frees allocated resources.
Definition: apps.cpp:135
CTwnDsmApps::AppGetNumApp
TWID_T AppGetNumApp()
Get number of allocated App slots (Last valid App ID +1)
Definition: apps.cpp:729
CTwnDsmApps::AppWakeup
void AppWakeup(TW_IDENTITY *_pAppId)
Poke the application to wake it up when sending a DAT_NULL message to it...
Definition: apps.cpp:1893
CTwnDsmApps::AppGetState
DSM_State AppGetState()
Get the state of the DSM for all applications.
Definition: apps.cpp:688
CAppList
Class CAppList implements dynamic array of APP_INFO.
Definition: apps.cpp:114
APP_INFO::pDSList
DS_LIST * pDSList
Each Application has a list of DS that it discovers each time the app opens the DSM.
Definition: apps.cpp:106
PATH_SEPERATOR
#define PATH_SEPERATOR
the operating system's symble used as a path seperator
Definition: dsm.h:286
CTwnDsmApps::CTwnDsmApps
CTwnDsmApps()
The CTwnDsmApps constructor.
Definition: apps.cpp:314
CTwnDsmAppsImpl::_pod::m_conditioncode
TW_UINT16 m_conditioncode
we use this if we have no apps.
Definition: apps.cpp:303
DS_INFO::bDSProcessingMessage
TW_BOOL bDSProcessingMessage
True if the application is still waiting for the DS to return from processing a message.
Definition: apps.cpp:52
DSM_State
DSM_State
Possible States of the DSM.
Definition: dsm.h:531
DSM_LoadFunction
void * DSM_LoadFunction(void *_pHandle, const char *_pszSymbol)
This function wraps the function loading calls.
Definition: dsm.cpp:3892
CTwnDsmAppsImpl::m_AppInfo
CAppList m_AppInfo
list of applications.
Definition: apps.cpp:306
NCHARS
#define NCHARS(s)
The number of characters in a charter array.
Definition: dsm.h:285
dsmState_Loaded
@ dsmState_Loaded
Source Manager is loaded, but not open.
Definition: dsm.h:533
DS_INFO::szPath
char szPath[FILENAME_MAX]
location of the DS
Definition: apps.cpp:49
CTwnDsmApps::AppGetIdentity
TW_IDENTITY * AppGetIdentity(TW_IDENTITY *_pAppId)
Return a pointer to the application's identity.
Definition: apps.cpp:598
MAX_NUM_DS
#define MAX_NUM_DS
Maximum number of Data Sources that can be opened under one application.
Definition: dsm.h:521