반응형

MS Office Interop를 이용해서 개발한 Windows Service가 정상적으로 작동하지 않을 때..

환경 : Microsoft Office 2010, Visual Studio 2010, Windows 7, Windows 2008 Server
개요 : MS Office 2010 Interop (14version)을 이용해서 Powerpoint, Word, Excel 파일을
PDF로 변환하는 Windows Service Program을 개발하여 포팅하였으나 Program이 정상적으로 구동되지 않았다.
증상
1. 변환 프로그램을 개발하는 Visual Studio 2010에서 Test Program인 Console Application으로 작동을 시켜보면 정상적으로 Program이 기동되었다.
2. 1의 테스트를 확인하고 Windows Service로 배포하는 프로젝트를 생성하여 정상적으로 Windows Service에등록이 된 것을 확인하고, 구동을 시켜보니 정상적으로 작동하지 않았다.
3. Program에서 작동하는 로그을 확인해 보니, 
"개체 참조가 개체의 인스턴스로 설정되지 않았습니다."라는 메세지와
"'C:\temp\document\7.xlsx' 파일을 사용할 수 없습니다. 원인은 다음과 같습니다
해당 파일 이름이나 경로가 없습니다. 다른 프로그램에서 파일을 사용하고 있습니다.저장하려고 하는 통합 문서 이름이 현재 열려 있는 통합 문서의 이름과 같습니다."라는 메세지가 표시되었다.
4. Excel -> PDF, PPT -> PDF, Word -> PDF 모듈이 작동하지 않았다.
원인 분석
Windows 7, Vista, Windows Server 2008에서 Windows Service는 Session0라고 불리는 session (or something)에서 구동이 된다. Session0는 Desktop에서 구동되는 프로그램에 접근이 불가능한 영역(Desktop-less wasteland)인데 개발된 Windows Service는 Desktop Session에서 구동되는(Desktop-ed session) Office Program인 관계로 Windows Service가 정상적으로 작동되지 않았던 것이다.
(참고 URL : http://stackoverflow.com/questions/241190/vista-office-interop-not-working)
처리 방안
1. 첫 번째 처리 내용 : System Profile을 위한 desktop folder를 생성한다.
이 방법은 msdn에서 확인한 방법으로서 H.Ogawa가 제시한 방법이다
http://social.msdn.microsoft.com/Forums/en/innovateonoffice/thread/b81a3c4e-62db-488b-af06-44421818ef91

아래의 경로에서 볼 수 있듯이 systemprofile이라는 폴더에 Desktop이라는 폴더를 만들고 해당 폴더 권한에 Everyone을 추가하고 모든 권한을 주면 된다.

c:\Windows\SysWOW64\config\systemprofile\Desktop, or
c:\Windows\System32\config\systemprofile\Desktop

개발된 Windows Service 프로그램이 64bit로 빌드하였으면 SysWOW64에 Desktop을 등록하고 그렇지 않으면 System32에 등록하면 된다.

=> 처리 후 테스트 결과 : Excel, Word는 모두 정상적으로 작동을 하였으나 Powerpoint는 여전히 동작하지 않았다. 그래서 아래의 처리 방식을 추가로 처리하였다.

2. 두 번째 처리 내용 : 1의 방법에도 여전히 Powerpoint가 구동되지 않았다.
Powerpoint가 구동되기 위해서는 User Profile 정보가 필요한데 Windows Service로 구동을 하다 보니 충분한 User Profile 정보를 가져올 수 없어서 에러가 발생했던 것이다. (참고 URL : http://stackoverflow.com/questions/729609/powerpoint-interop-fails-in-a-windows-service-but-works-fine-in-a-windows-form-a)

이에 대한 처리를 위해서, Windows Service에 등록되어 있는 Program의 속성 창에서 "로그온(Logon)" Tab을 클릭하여 "서비스와 데스크톱 상호 작용 허용"을 선택하면 Powerpoint도 이상 없이 구동된다.


3. 추가 사항 : 1과 2의 방식을 통해서 Windows Service가 정상적으로 구동이 되었더니 다음과 같은 화면이 자꾸 표시되는 현상이 발생을 하였다.


Windows Service가 구동되는 Session0에서 Word, Powerpoint등의 프로그램이 메세지를 발생시켜서 위의 화면이 표시되는 것으로 추측이 되었다.

위의 메세지를 발생시키는 것은 다른 Windows Service에 의한 것으로서 Service 이름은 "Interactive Services Detection"이다. 해당 서비스는 "대화형 서비스에 대한 사용자 입력의 사용자 알림을 사용할 수 있도록 하는 서비스"로서 해당 서비스를 사용하지 않도록 Service 설정을 하면(사용안함으로 설정)된다.



출처 : http://kevinlovesu.blogspot.kr/2012/08/ms-office-interop-windows-service.html#comment-form








반응형


        string _xml = "";

        _xml += "<response>";

        _xml += "    <data>false</data>";

        _xml += "</response>";


        MemoryStream ms = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(_xml));

        XmlDocument xmldoc = new XmlDocument();

        try

        {

            xmldoc.Load(ms);

        }

        catch

        {

            ms.Close();

        }

        XmlElement root = xmldoc.DocumentElement;

        if (root.Name == "response")

        {

            XmlNodeList nodes = root.ChildNodes;

            nodes[0].InnerText;

        }


        ms.Close();

        ms.Dispose();


출처,참조 : http://ldaehyeon.tistory.com/5

---------------------------------------------------------------

xml형태로 작성된 String을 Xml객체로 전환하는 방법이다.

asp.net에서 jsp쪽으로 Return을 요구하는 질의를 날렸는데 xml형태로 되돌아온다.

여기에서 필요한 값은 <data></data>이기 때문에 string형태로 데이터를 가공하려하면 답이 없다.

차라리 XmlDocument로 변환해서 필요한 값만 읽어오는게 더 빠르다.

반응형

예를 들어 string val =  "abc,def,hij"라는 문자열을 ","로 구분해서 배열로 변경하려한다면

string[] tmp = val.Split(','); 이렇게 하면 된다. 그런데 배열 구분자가 1바이트가 아니라면?


다시 예를 들어본다면 string val =  "abc<br/>def<br/>hij" 이런형태의 문자열에서 "<br/>"을 split하려고 하면

불가능하다. 이를 split해주는 방법은 아래와같다.

string[] _tmp = System.Text.RegularExpressions.Regex.Split(val, "<br/>");


그러나... ↑ 요고로 해결이 안될경우도 있다. ㅡ,.ㅡ;;;

그래서 확실한 방법은 아래와 같다.


public static string[] SplitByString(string inVal, string split)

    {

        int offset = 0;

        int index = 0;

        int[] offsets = new int[inVal.Length + 1];

        while (index < inVal.Length)

        {

            int indexOf = inVal.IndexOf(split, index);

            if (indexOf != -1)

            {

                offsets[offset++] = indexOf;

                index = (indexOf + split.Length);

            }

            else

            {

                index = inVal.Length;

            }

        }

        string[] final = new string[offset + 1];

        if (offset == 0)

        {

            final[0] = inVal;

        }

        else

        {

            offset--;

            final[0] = inVal.Substring(0, offsets[0]);

            for (int i = 0; i < offset; i++)

            {

                final[i + 1] = inVal.Substring(offsets[i] + split.Length, offsets[i + 1] - offsets[i] - split.Length);

            }

            final[offset + 1] = inVal.Substring(offsets[offset] + split.Length);

        }

        return final;

    }


어디서 퍼왔는데 출처까먹음 ㅠㅠ

반응형

프로젝트 진행중에 Excel데이터를 생성하는 내용이 있었다.

로컬테스트 할때는 문제가 없었으나 외부접근테스트를 하게되니 바로 아래와 같은 에러가 발생했다.


80070005 액세스가 거부되었습니다. (예외가 발생한 HRESULT: 0x80070005 (E_ACCESSDENIED)) 오류로 인해 CLSID가 {00024500-0000-0000-C000-000000000046}인 구성 요소의 COM 클래스 팩터리를 검색하지 못했습니다.


해결법을 찾기 위해 하루종일 자료를 찾다가 우연히 해결법을 찾았다.

결론부터 말하자면 Web.Config에 <identity impersonate="true" userName="YourID" password="Password"/>

을 추가해 주면 된다.


웹관련 보안설정으로 DCOM구성ㅇ에 Excel권한이 어쩌고 저쩌고 하는 방법으로 해결하라는데 잘안된다.

보안설정에 as.pnet계정을 추가해줘야하는데 어찌된 영문인지 asp.net계정을 추가할 수가 없었다.


차선책을 찾다가 겨우 찾았다. 


출처는 : http://support.microsoft.com/?id=306158#2



반응형

itextsharp.dll


itextsharp.pdfa.dll


using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;


public partial class _Default : System.Web.UI.Page
{
 
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
 

        }
    }
 
    protected void Button1_Click(object sender, System.EventArgs e)
    {
        String htmlText = "<font  " +
         " color=\"#0000FF\"><b><i>Title One</i></b></font><font   " +
         " color=\"black\"><br><br>Some text here<br><br><br><font   " +
         " color=\"#0000FF\"><b><i>Another title here   " +
         " </i></b></font><font   " +
         " color=\"black\"><br><br>Text1<br>Text2<br><OL><LI><DIV Style='color:green'>Pham Duy Hoa</DIV></LI><LI>how are u</LI></OL><br/>"+
         "<table border='1'><tr><td style='color:red;text-align:right;width:20%'>123456</td><td style='color:green;width:60%'>78910</td><td style='color:red;width:20%'>ASFAFA</td></tr><tr><td style='color:red;text-align:right'>123456</td><td style='color:green;width:60%'>78910</td><td style='color:red;width:20%'>DAFSDGAFW</td></tr></table><br/>"+
         "<div><ol><li>123456</li><li>123456</li><li>123456</li><li>123456</li></ol></div>";
 

 
        HTMLToPdf(htmlText, "PDFfile.pdf");
    }
 
    public void HTMLToPdf(string HTML, string FilePath)
    {
        Document document = new Document();
 
        PdfWriter.GetInstance(document, new FileStream(Request.PhysicalApplicationPath + "\\Chap0101.pdf", FileMode.Create));
        document.Open();
        Image pdfImage = Image.GetInstance(Server.MapPath("logo.png"));
 
        pdfImage.ScaleToFit(100, 50);
 
        pdfImage.Alignment = iTextSharp.text.Image.UNDERLYING; pdfImage.SetAbsolutePosition(180, 760);
 
        document.Add(pdfImage);
        iTextSharp.text.html.simpleparser.StyleSheet styles = new iTextSharp.text.html.simpleparser.StyleSheet();
        iTextSharp.text.html.simpleparser.HTMLWorker hw = new iTextSharp.text.html.simpleparser.HTMLWorker(document);
        hw.Parse(new StringReader(HTML));
        document.Close();
        ShowPdf("Chap0101.pdf");
    }
    private void ShowPdf(string s)
    {
        Response.ClearContent();
        Response.ClearHeaders();
        Response.AddHeader("Content-Disposition", "inline;filename=" + s);
        Response.ContentType = "application/pdf";
        Response.WriteFile(s);
        Response.Flush();
        Response.Clear();
    }
}

출처 : http://www.codeproject.com/Questions/203481/HTML-convert-to-PDF-using-itextsharp

html 내용을 pdf로 변환해야하는 상황이 생겼다.

iTextSharp가 탁월한 해결법이 되었다.

첨부된 두 dll파일을 참조해서 예제를 실행하면 된다.

참고로 이소스가 필요했던 이유는 그래프와 html table셑을 하나의 결과물로 받아보기를 원하는 고객의 요구에 부응하기 

위해서 였다. mschart를 써서 그래프를 그린후 이미지파일로 저장하고 이를 다시 PDF문서에 그래프 + <table></table>구조로

파싱하는 구조다. 이거 알아내는데 하루가 꼬박 걸렸다.

반응형

RadioButton을 2.0에서 서버컨트롤로 사용했다. <asp:DropDownList>의 선택값이 변할때 마다 RadioButton의 text값이 변하도록 

해야했으나 문제는 <asp:DropDownList>이 MasterPage상에 있어서 종속된 페이지에서 이를 서버코드로 제어할 수 없는 문제가 

있었던 것이다.


1.dropdownlist를 선택할때마다 radiobutton의 text를 변경

2.dropdownlist는 마스터페이지에 radiobutton은 종속페이지에 위치


이런 제약조건때문에 서버페이지에서 종속페이지의 컨트롤을 직접 제어할 수도 없는 난점때문에 자바스크립트로 해결하기로 했다.


$(document).ready(function(){

$('#dropdownlist').live('change',function(){

   var _chkcode = $('#dropdownlist_ClientID option:selected').val();

  var tags = document.getElementsByTagName('label');

  for(var i = 0; i < tags.length; i++){

if(tags[i].getAttribute('for') == 'RadioButton_ClientID'){

if(_chkcode == 'Code01'){

   tags[i].innerHTML = '텍스트1';

}

else if(_chkcode == 'Code02'){

   tags[i].innerHTML = '텍스트2';

}

}

}

});

});;


위와같은 방법으로 해결했다. 

<asp:RadioButton>은 html로 변환될경우 <input id='clientID' type='radio' value='serverID'/><label for='clientID'>텍스트</label> 로 

변환된다. 결국 Radio버튼의 text값은 <label for='clientID'의 값을 변경해야 하는 것이다. 그런데 <label은 id가 없기때문에

var tags = document.getElementsByTagName('label'); 이런식으로 label개체들을 for로 처리하여 해결한다.

tags[i].getAttribute('for') == 'RadioButton_ClientID' 이부분이 내가 원하는 label개체를 선별할 수 있도록 해준다. 


나머지는 일사천리~

반응형

asp.net2.0 용으로 만들어진 Open Flash Chart(이하 ofc)라이브러리를 사용하면서 생긴 몇가지 문제에 대한 팁이다.


1. 한글이 깨지는 문제

asp.net프로젝트가 한글로 만들어져있고 실행에도 문제가 없음에도 불구하고 유독 ofc에서 한글이 깨지는 문제가 발생했다.

ofc로 만들어진 asp.net용 예제샘플을 실행해보면 한글이 문제없이 출력되는데 현제 내가 작업중인 프로젝트에서만 한글이 깨진다.

문제는 web.config에 있었다.  

<globalization requestEncoding="euc-kr" responseEncoding="euc-kr" />로 되어있던 부분이 문제였다.

<globalization requestEncoding="utf-8" responseEncoding="utf-8" /> 이렇게 utf-8로 변경하니 문제없이 출력이 된다.


2. LineChart에서 출력값중에 0 보다 작은 값(-값)이 있을 경우

마이너스 값을 설정할 경우 ofc가 응답을 하지 않는 경우가 있다.

ofc는 MaxY를 설정할 수 있다. 마찬가지로 MinY값을 설정할 수 있다. 최대값과 최소값을 설정할때 최소값에 마이너스 값중 

제일 작은 값을 설정하면 된다.


3. ofc X값들의 간격설정

x값들이 너무 많으면 차트의 x값들의 Y축 라인들이 너무 세밀하게 나와서 보기가 불편하다.

Chart.AxisStepsX = int value; 정수값으로 간격범위를 설정해주면 간단하게 해결된다.

반응형

Response.Expires = 0;

Response.Cache.SetNoStore();

Response.AppendHeader("Pragma", "no-cache");


OpenFlashChart를 asp.net2.0에 참조 하였더니 ie에서 문제가 발생했다.

Chart를 재생성할때마다 서버에 접근해야 하는데 캐쉬문제 때문인지 서버에 접근하지 않고 최초에 생성한 Chart가 반복되는 현상이 발생했다.

(크롬에서는 발생하지 않는 문제) 이를 해결하기 위해 해당 페이지에 상기의 코드를 추가 한다.


반응형
1. http://www.uploadify.com/ 에서 jQuery플러그인을 받는다.(asp.net)

 [Uploadify.htm]


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

    <title>파일업로드 : jQuery + Uploadify + ASP.NET</title>

    <link href="uploadify.css" rel="stylesheet" type="text/css" />

    <script src="../../js/jquery-1.3.2-vsdoc2.js" type="text/javascript"></script>

    <script src="jquery.uploadify.v2.1.0.js" type="text/javascript"></script>

    <script src="swfobject.js" type="text/javascript"></script>

    <script type="text/javascript">

        $(document).ready(function () {

        // Uploadify 파일 업로드 컨트롤 : Flash가 설치가 되어있어야 함

            $('#fileInput').uploadify({

                'uploader' : 'uploadify.swf'// Uploadify 컨트롤 지정

                'script' : 'Uploadify.ashx'// 서버측 스크립트, ASP.NET, ASP, PHP, JSP

                'cancelImg''cancel.png'// 취소 이미지

                'auto' : false// true면 파일선택시 바로 자동으로 업로드됨

                'folder''/Uploads'// 업로드할 폴더 : 가상디렉터리 + 업로드폴더

                // 업로드 완료시 처리 :

                //      주요 속성은 http://www.uploadify.com/documentation/ 참고

                'onComplete'function (event, queueID, fileObj, response, data) {

                    $('#lblFile').append('<a href=/WebJQuery' + fileObj.filePath + '>'

                    + fileObj.name + '</a><br>');

                }

            });

            // 버튼 클릭시 업로드

            $('#btn').click(function () { $('#fileInput').uploadifyUpload(); });

        });

    </script>

</head>

<body>

    <input id="fileInput" name="fileInput" type="file" />

    <input type="button" id="btn" value="업로드" />

    <div id="lblFile"></div>

</body>

</html>

 




-------------------------------------------------------------------------------------


 

[Uploadify.ashx]


<%@ WebHandler Language="C#" Class="Uploadify" %>

 

using System;

using System.Web;

 

public class Uploadify : IHttpHandler {

   

    public void ProcessRequest (HttpContext context) {

        // Filedata로 넘겨온 파일 값 받기

        HttpPostedFile file = context.Request.Files["Filedata"];

        // 저장할 폴더

        string targetDirectory = System.IO.Path.Combine(

        context.Request.PhysicalApplicationPath,

        context.Request["folder"].Replace("/"""));

        // 저장할 폴더 + 파일명

        string targetFilePath = System.IO.Path.Combine(

            targetDirectory, file.FileName);

        // 파일 저장(업로드)

        file.SaveAs(targetFilePath);

 

        context.Response.Write("RedPlus");

    }

 

    public bool IsReusable {

        get {

            return false;

        }

    }

 

}
[출처] : http://holland14.tistory.com/538
 

2. 파일을 업로드할경우 변수를 넘겨야하는 경우가 있다.
1)의 소스대로 하면 변수는 $(document).ready()상에 지정해야하는데 데이터를 미리 받아오기전에는
변수를 넘기기 힘들다. 
그래서 

            // 버튼 클릭시 업로드

            $('#btn').click(function () { $('#fileInput').uploadifyUpload(); });



이부분에 변수를 넘길 수 있는 처리를 추가해야한다.
var _obj = $('#fileInput');

_obj.uploadifySettings('scriptData', { 'code1': 'data01', 'code2': 'data02' });

_obj.uploadifyUpload();

이부분을 처리해주면 업로드 할때 변수(code1,code2)의 값을 전달할 수 있다.

반응형
                WebClient request = new WebClient();
                request.Credentials = new NetworkCredential(ftp_uid, ftp_upw);
                byte[] newFileData = request.DownloadData(ftp_url  + "/" + filecode);

                Response.ClearHeaders();
                Response.AddHeader("Content-Type", "application/vnd.ms-excel");
                Response.AddHeader("Content-Disposition", string.Format("attachment; filename=\"{0}\"", filename));
                Response.ContentType = "multipart/form-data";
                Response.BinaryWrite(newFileData);
                Response.End();

 원격FTP에 있는 데이터를 byte[]로 읽어서 저장하는 방법이다.

+ Recent posts