笔记——文档在线阅读的解决方案(未完待续)

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

    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的情况下完美转换。

原文地址:https://www.cnblogs.com/LearningC/p/4843351.html