zoukankan      html  css  js  c++  java
  • 笔记——文档在线阅读的解决方案(未完待续)

      目前现在很多大型的网站或是某些项目需要让用户上传的文档可以在线预览。这个目前我所了解到的有以下几种情况:

        1、pdf 在线阅读

        2、office 在线阅读

      对于pdf目前有很多解决方案了,可以参考 http://www.open-open.com/news/view/1fc3e18  ,对于office在线阅读,目前。我的办法是,先转换为PDF,然后使用pdf在线阅读的方式进行浏览。目前好像很多站点都是这么做的。

      然而,我在项目中,这类文档在线阅读方案是这样的。OFFICE --> PDF  ---> SWF --> PNG 然后用户通过预览图片的方式去查看文档。

         这样做的目的就是,可以让尽可能多的平台直接观看文档,因为任何一个平台都能很好的支持PNG图片预览,但这样做,又产生了新的问题。

      1、office 转成PDF 需要用安装office2007 + SaveAsPDFandXPS加载项 亦或是使用office 2010 。后则直接集成了这个加载项。让一个服务器安装一套office 然后功能仅仅用到的是将office转换为pdf。这个代价是比较大的。office还是不便宜的。

      2、pdf 转换为 swf ,好在目前有现成的工具。(不需要UI界面)

      3、swf 转换为 png ,目前也有现场的工具。(不需要UI界面)

      4、因为这一系列过程才能正常的转换一个文档。而这样的工具,最适合的形态是windows 服务。这样不管如何,只要用户上传了文档,我们就可以进行转换。然而,理想是美好的。当我尝试将这个过程变成服务的过程中,遇到了新的问题。windows xp之后,服务是不能直接调用Application(ExE) 的。而将office转换为pdf,其原理是打开文档,使用另存为按钮,将它保存为pdf。而service 不支持图形界面的操作。在此,笔者查尽了资料。最后在CodeProject上找到了答案。原文我就不列举了,因为懒所以没有做笔记的习惯。代码如下:

      1    public class ProcessStarter : IDisposable
      2     {
      3         #region Import Section
      4 
      5         private static uint STANDARD_RIGHTS_REQUIRED = 0x000F0000;
      6         private static uint STANDARD_RIGHTS_READ = 0x00020000;
      7         private static uint TOKEN_ASSIGN_PRIMARY = 0x0001;
      8         private static uint TOKEN_DUPLICATE = 0x0002;
      9         private static uint TOKEN_IMPERSONATE = 0x0004;
     10         private static uint TOKEN_QUERY = 0x0008;
     11         private static uint TOKEN_QUERY_SOURCE = 0x0010;
     12         private static uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
     13         private static uint TOKEN_ADJUST_GROUPS = 0x0040;
     14         private static uint TOKEN_ADJUST_DEFAULT = 0x0080;
     15         private static uint TOKEN_ADJUST_SESSIONID = 0x0100;
     16         private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
     17         private static uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID);
     18 
     19         private const uint NORMAL_PRIORITY_CLASS = 0x0020;
     20 
     21         private const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400;
     22 
     23 
     24         private const uint MAX_PATH = 260;
     25 
     26         private const uint CREATE_NO_WINDOW = 0x08000000;
     27 
     28         private const uint INFINITE = 0xFFFFFFFF;
     29 
     30         [StructLayout(LayoutKind.Sequential)]
     31         public struct SECURITY_ATTRIBUTES
     32         {
     33             public int nLength;
     34             public IntPtr lpSecurityDescriptor;
     35             public int bInheritHandle;
     36         }
     37 
     38         public enum SECURITY_IMPERSONATION_LEVEL
     39         {
     40             SecurityAnonymous,
     41             SecurityIdentification,
     42             SecurityImpersonation,
     43             SecurityDelegation
     44         }
     45 
     46         public enum TOKEN_TYPE
     47         {
     48             TokenPrimary = 1,
     49             TokenImpersonation
     50         }
     51 
     52         public enum WTS_CONNECTSTATE_CLASS
     53         {
     54             WTSActive,
     55             WTSConnected,
     56             WTSConnectQuery,
     57             WTSShadow,
     58             WTSDisconnected,
     59             WTSIdle,
     60             WTSListen,
     61             WTSReset,
     62             WTSDown,
     63             WTSInit
     64         }
     65 
     66         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
     67         public struct STARTUPINFO
     68         {
     69             public Int32 cb;
     70             public string lpReserved;
     71             public string lpDesktop;
     72             public string lpTitle;
     73             public Int32 dwX;
     74             public Int32 dwY;
     75             public Int32 dwXSize;
     76             public Int32 dwYSize;
     77             public Int32 dwXCountChars;
     78             public Int32 dwYCountChars;
     79             public Int32 dwFillAttribute;
     80             public Int32 dwFlags;
     81             public Int16 wShowWindow;
     82             public Int16 cbReserved2;
     83             public IntPtr lpReserved2;
     84             public IntPtr hStdInput;
     85             public IntPtr hStdOutput;
     86             public IntPtr hStdError;
     87         }
     88 
     89         [StructLayout(LayoutKind.Sequential)]
     90         internal struct PROCESS_INFORMATION
     91         {
     92             public IntPtr hProcess;
     93             public IntPtr hThread;
     94             public int dwProcessId;
     95             public int dwThreadId;
     96         }
     97 
     98         [StructLayout(LayoutKind.Sequential)]
     99         private struct WTS_SESSION_INFO
    100         {
    101             public Int32 SessionID;
    102 
    103             [MarshalAs(UnmanagedType.LPStr)]
    104             public String pWinStationName;
    105 
    106             public WTS_CONNECTSTATE_CLASS State;
    107         }
    108 
    109         [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    110         static extern uint WTSGetActiveConsoleSessionId();
    111 
    112         [DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    113         static extern bool WTSQueryUserToken(int sessionId, out IntPtr tokenHandle);
    114 
    115         [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    116         public extern static bool DuplicateTokenEx(IntPtr existingToken, uint desiredAccess, IntPtr tokenAttributes, SECURITY_IMPERSONATION_LEVEL impersonationLevel, TOKEN_TYPE tokenType, out IntPtr newToken);
    117 
    118         [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    119         static extern bool CreateProcessAsUser(IntPtr token, string applicationName, string commandLine, ref SECURITY_ATTRIBUTES processAttributes, ref SECURITY_ATTRIBUTES threadAttributes, bool inheritHandles, uint creationFlags, IntPtr environment, string currentDirectory, ref STARTUPINFO startupInfo, out PROCESS_INFORMATION processInformation);
    120 
    121         [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    122         static extern bool CloseHandle(IntPtr handle);
    123 
    124         [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    125         static extern int GetLastError();
    126 
    127         [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    128         static extern int WaitForSingleObject(IntPtr token, uint timeInterval);
    129 
    130         [DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    131         static extern int WTSEnumerateSessions(System.IntPtr hServer, int Reserved, int Version, ref System.IntPtr ppSessionInfo, ref int pCount);
    132 
    133         [DllImport("userenv.dll", CharSet = CharSet.Auto, SetLastError = true)]
    134         static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
    135 
    136         [DllImport("wtsapi32.dll", ExactSpelling = true, SetLastError = false)]
    137         public static extern void WTSFreeMemory(IntPtr memory);
    138 
    139         [DllImport("userenv.dll", SetLastError = true)]
    140         [return: MarshalAs(UnmanagedType.Bool)]
    141         static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
    142 
    143         #endregion
    144 
    145         public ProcessStarter()
    146         {
    147 
    148         }
    149 
    150         public ProcessStarter(string processName, string fullExeName)
    151         {
    152             processName_ = processName;
    153             processPath_ = fullExeName;
    154         }
    155         public ProcessStarter(string processName, string fullExeName, string arguments)
    156         {
    157             processName_ = processName;
    158             processPath_ = fullExeName;
    159             arguments_ = arguments;
    160         }
    161 
    162         public static IntPtr GetCurrentUserToken()
    163         {
    164             IntPtr currentToken = IntPtr.Zero;
    165             IntPtr primaryToken = IntPtr.Zero;
    166             IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
    167 
    168             int dwSessionId = 0;
    169             IntPtr hUserToken = IntPtr.Zero;
    170             IntPtr hTokenDup = IntPtr.Zero;
    171 
    172             IntPtr pSessionInfo = IntPtr.Zero;
    173             int dwCount = 0;
    174 
    175             WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessionInfo, ref dwCount);
    176 
    177             Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
    178 
    179             Int32 current = (int)pSessionInfo;
    180             for (int i = 0; i < dwCount; i++)
    181             {
    182                 WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO));
    183                 if (WTS_CONNECTSTATE_CLASS.WTSActive == si.State)
    184                 {
    185                     dwSessionId = si.SessionID;
    186                     break;
    187                 }
    188 
    189                 current += dataSize;
    190             }
    191 
    192             WTSFreeMemory(pSessionInfo);
    193 
    194             bool bRet = WTSQueryUserToken(dwSessionId, out currentToken);
    195             if (bRet == false)
    196             {
    197                 return IntPtr.Zero;
    198             }
    199 
    200             bRet = DuplicateTokenEx(currentToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken);
    201             if (bRet == false)
    202             {
    203                 return IntPtr.Zero;
    204             }
    205 
    206             return primaryToken;
    207         }
    208 
    209         public void Run()
    210         {
    211 
    212             IntPtr primaryToken = GetCurrentUserToken();
    213             if (primaryToken == IntPtr.Zero)
    214             {
    215                 return;
    216             }
    217             STARTUPINFO StartupInfo = new STARTUPINFO();
    218             processInfo_ = new PROCESS_INFORMATION();
    219             StartupInfo.cb = Marshal.SizeOf(StartupInfo);
    220 
    221             SECURITY_ATTRIBUTES Security1 = new SECURITY_ATTRIBUTES();
    222             SECURITY_ATTRIBUTES Security2 = new SECURITY_ATTRIBUTES();
    223 
    224             string command = """ + processPath_ + """;
    225             if ((arguments_ != null) && (arguments_.Length != 0))
    226             {
    227                 command += " " + arguments_;
    228             }
    229 
    230             IntPtr lpEnvironment = IntPtr.Zero;
    231             bool resultEnv = CreateEnvironmentBlock(out lpEnvironment, primaryToken, false);
    232             if (resultEnv != true)
    233             {
    234                 int nError = GetLastError();
    235             }
    236 
    237             CreateProcessAsUser(primaryToken, null, command, ref Security1, ref Security2, false, CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT, lpEnvironment, null, ref StartupInfo, out processInfo_);
    238 
    239             DestroyEnvironmentBlock(lpEnvironment);
    240             CloseHandle(primaryToken);
    241         }
    242 
    243         public void Stop()
    244         {
    245             Process[] processes = Process.GetProcesses();
    246             foreach (Process current in processes)
    247             {
    248                 if (current.ProcessName == processName_)
    249                 {
    250                     current.Kill();
    251                 }
    252             }
    253         }
    254 
    255         public int WaitForExit()
    256         {
    257             WaitForSingleObject(processInfo_.hProcess, INFINITE);
    258             int errorcode = GetLastError();
    259             return errorcode;
    260         }
    261 
    262         #region IDisposable Members
    263 
    264         public void Dispose()
    265         {
    266         }
    267 
    268         #endregion
    269 
    270         private string processPath_ = string.Empty;
    271         private string processName_ = string.Empty;
    272         private string arguments_ = string.Empty;
    273         private PROCESS_INFORMATION processInfo_;
    274 
    275         public string ProcessPath
    276         {
    277             get
    278             {
    279                 return processPath_;
    280             }
    281             set
    282             {
    283                 processPath_ = value;
    284             }
    285         }
    286 
    287         public string ProcessName
    288         {
    289             get
    290             {
    291                 return processName_;
    292             }
    293             set
    294             {
    295                 processName_ = value;
    296             }
    297         }
    298 
    299         public string Arguments
    300         {
    301             get
    302             {
    303                 return arguments_;
    304             }
    305             set
    306             {
    307                 arguments_ = value;
    308             }
    309         }
    310     }
    View Code

    其调用方式,如下:

    1  ProcessStarter  ps = new ProcessStarter(RunProcessName, "Worker.exe");
    2                      ps.Run();
    View Code

    第一个参数,是外壳程序,也就是说,当系统登录的时候一定会存在的进程。也就是Login之后,当前用户一定会存在的进程。

    第二个参数,是我们需要运行的Application。

    这样就可以在windows service中Call到Application了。

    到了这里问题好像解决了。但是,我发现服务器必须需要一个用户登录进去,Office 才能转换为PDF。分析了很久的原因。后来突然有一天发现。以为没有Login之前。是没有UI界面的。在没有UI界面之前是不可能打开Office的。所以此路不通!!!

    于是乎,继续寻找解决办法。就在昨天,我发现了新的解决办法。但还没有去尝试。如果有人有现场的解决办法,希望能拿出来分享下。

    1、Aspose.words.dll 听说这玩意儿可以在不安装OFFICE的情况下将word转换为pdf。目前我没有验证。但,仅仅只能将word转换为pdf还是不够的,我们还有 ppt excel。再者版本问题也是个问题。是否支持 Office 2003 和 Office 2007以上版本。

    2、OpenOffice 这个家伙是阿帕奇搞的。听说可以不依靠office的情况下处理这些。但是太大了。我也没来得及去详细的查阅资料。

    最后,期待第二篇日志可以解决以上问题。让office文档能在脱离安装office的情况下完美转换。

  • 相关阅读:
    python 数字格式化
    Python字符串
    Nginx 深入-动静分离, 静态资源css, js 前端请求404问题
    Spring colud gateway 源码小计
    Nginx 场景应用
    Nginx valid_referer 防盗链
    Nginx 基础
    JNI 从零开始一次DEMO调用 IDEA 2018.2.5 + visual studio 2019
    Bitmap 图片说明
    HP激光打印机解密
  • 原文地址:https://www.cnblogs.com/LearningC/p/4843351.html
Copyright © 2011-2022 走看看