요즘 C#을 통해서 Application을 만드는 중인데, 데이터 처리해야 될 내용이 많아, Excel과 Access를 주로 사용하고 있다. 특히 Excel의 경우에는 직접 COM 개체를 활성화 시켜서 Cell 단위까지 찾아 데이터를 가져오는 방법보다,
마치 DB Access 한 것 처럼 OLEDB로 연결해서 가져오는 방법이 가장 효율적이였던 것 같다.

그런데, 문제는 설치 대상 PC안에 오피스 제품이 무엇이 깔렸는지에 따라 이 OLEDB를 사용할 수 있는 것이 전혀 다르다. 특히 2013 이후에는 x64 전용이 있어, 응용 프로그램이 x64에서 동작하게 되면 OLEDB 32bit 버전은 접근이 불가능했다. 그래서 매번 어떤 오피스가 깔렸는지, 32bit, 64bit 구분을 하기에는 너무 로직이 복잡해졌다.

그래서 구글링으로 찾아 다양한 테스트 후 적용했는데 지금은 큰 문제가 없어 보여서 블로깅을 시작한다.

 

문제

오피스 데이터를 DB 처럼 접근하기 위해서는 그에 맞는 Connection String을 구성해야 한다.

MS Access 같은 경우에는,

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\mydatabase.mdb;User Id=admin; Password=;"

라고 쓰고

MS Excel 같은 경우에는

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\MyExcel.xls; Extended Properties="Excel 8.0;HDR=Yes;IMEX=1";"

라고 쓴다.

그런데, 문제는 저 Provider다.
현재 설치되어 있는 오피스 버전에 따라 Microsoft.Jet.OLEDB.4.0 을 쓸수도 있고,
때론 Microsoft.ACE.OLEDB.12.0 라고 쓰기도 하고,
x64 Office 2013의 경우에는 Microsoft.ACE.OLEDB.15.0 라고 해야 동작한다.
그 이유는 설치한 Office 마다 설치되는 OLEDB Provider가 달라서 벌어지는 일이다.

일반적으로 Office 2000, XP, 2003 까지는 Microsoft.Jet.OLEDB.4.0 를,
Office 2007, 2010의 경우에는 Microsoft.ACE.OLEDB.12.0 를
Office 2013의 경우에는 Microsoft.ACE.OLEDB.15.0를 사용하게 된다.

그렇다면 이 Provider가 어떻게 설치되어 있는지 알 수 있을까?
맨 처음, 적용했던 방식은 Registry를 통한 방식이였다.
Registry 내에 설치되어 있는 Provider가 있는지 검색하는 방법인데,
이 방법으로 했을때는 그럭저럭 잘 동작 했다.

그런데, 왠걸... x64로 넘어가자 문제가 발생했다.
분명 해당 Provider는 설치되어 있었지만,
내 프로그램에서 해당 Provider를 찾지 못하는 문제가 발생했다.
즉 x86일 때와 x64일 때 제공되는 OLE DB Provider가 다르다는 사실을 그 때 처음 알았다.

결국 원점으로 돌아왔고, 근본적인 방법을 찾아야 겠다는 생각이 들어 수정하기 시작했다.

 

해결

구글링을 통해서 다양한 웹페이지들을 들락달락해 본 결과 다음과 같은 예제 소스를 볼 수 있었다.
대게의 경우 앞서 언급한 특정 레지스트릐의 값을 통해 등록되어 있는지 여부를 찾는 것이였는데,
애석하게도 실패를 맞봤기 대문에, 실질적인 방법이 필요했다.그러다가 단서를 하나 발견했다.

http://stackoverflow.com/questions/6570066/c-net-get-the-oledb-provider-version

내용을 대충 훝어 본 후, 적절한 예제로 담긴 MSDN 링크를 따라 들어갔다.

http://msdn.microsoft.com/en-us/library/system.data.oledb.oledbenumerator.getelements.aspx

OleDbEnumerator.GetElements 라는 메소드를 사용해보라는 것이였다.
예제의 내용은 아래와 같다.

using System;
using System.Data;
using System.Data.OleDb;

class Program
{
    static void Main()
    {
        OleDbEnumerator enumerator = new OleDbEnumerator();
        DataTable table = enumerator.GetElements();
        DisplayData(table);
        Console.WriteLine("Press any key to continue.");
        Console.ReadKey();
    }

    static void DisplayData(DataTable table)
    {
        foreach (DataRow row in table.Rows)
        {
            foreach (DataColumn col in table.Columns)
            {
                Console.WriteLine(" = ", col.ColumnName, row[col]);
            }
            Console.WriteLine("==================================");
        }
    }
}

즉 OleDbEnumerator 라는 개체를 만들고 그 메소드 중, GetElements 라는 메소드를 호출하면 현재 프로그램 안에서
사용가능한 모든 Provider를 담은 정보를 DataTable 형식으로 돌려주게 된다.

여기서 착안하여, 실제 Provider들 중, 최신 Provider 이름을 추출하도록 했다.

OleDbEnumerator enumerator = new OleDbEnumerator();
DataTable table = enumerator.GetElements();
List aryProviders = new List();
foreach (DataRow row in table.Rows)
{
    aryProviders.Add(row[0].ToString());
}
table.Dispose();
aryProviders.Sort((p, n) => n.CompareTo(p));
string sFoundString = aryProviders.Find(m => m.StartsWith("Microsoft.ACE.OLEDB"));
if (string.IsNullOrEmpty(sFoundString))
    sFoundString = aryProviders.Find(m => m.StartsWith("Microsoft.Jet.OLEDB"));
g_sProviderName = sFoundString;

 

최종적으로 사용되는 값은 g_sProviderName 이라는 값으로, 이 값을 Connection String에 대입하기만 하면 된다.

string sConnectionString = string.Format("Provider=;Data Source=C:\MyExcel.xls; Extended Properties="Excel 8.0; HDR = Yes; IMEX = 1";", g_sProvider);

라고 하면 끝. 그러면 해당 Provider로 연결하게 된다.

Provider 검색하는 코드를 간단하게 설명하자면,  아래와 같다.

  1. 현재 가져올 수 있는 모든 Provider 정보를 DataTable로 가져온다.
  2. 가져온 Provider에서 Provider 이름만 모두 가져와 string array로 만든다.
  3. string array를 이름 별로 Sort 한다. - 최신 버전이 위로 갈 수 있도록 -
  4. 돌면서 최신 버전에 해당하는 것이 있는지 체크하면서 찾으면 해당 이름을 저장한다.
  5. Connection String을 만들 때, 저장한 Provider 이름을 사용한다.

간단하면서도 잘 알지 못하면, 참 어렵게 프로그램을 짤 번했던 기억이 든다.

참고로 Excel의 경우 "xsl" 파일은 Microsoft.Jet.OLEDB.4.0 만으로도 읽을 수 있지만, "xslx" 파일은 반드시 "Microsoft.ACE.OLEDB.12.0" 이상 버전의 Provider를 사용해야만 읽을 수 있다.

즉 위에서 필터링하는 방식에 따라, xlsx 파일을 읽을 수 있는지 없는지를 체크하는 방편이 될 수 있다.

728x90
아침에 사장님이 커피를 타면서 문득 던진 말씀이다.
흠. 뭐랄까?
옆옆집 사람이 빌딩을 샀는데, 애들 오락실을 성인용 게임방으로 바꿨다더라. 정도로 들리는 건 나만일까?
지금의 Outlook 개인적으로 볼 떄, 이미 Notes 클라이언트가 따라가기에는 이미 많이 늦고 늦어 버린 느낌이다.
과거의 영광속에서 허우적 대는 바보꼬라지 같은 모습이라,
지금의 Notes 클라이언트는, Outlook 뒤를 힘겹게 쫒아 다니고 있는 느낌이다.

시대도 변하고 환경도 변하고 요구사항도 변한다.

예전 영광속에서 파묻히면 별수 있나, 로마꼴이지.
조금이라도 더 나은 모습으로 더 발전된 모습으로 보이려고 노력하는 MS의 투쟁이 더 정겨워
보인다. (아마도 HARD CODE라는 책 때문인지도 모르겠지만.)

728x90
  • 문자보내기루 이런거 자주쓰믄 문자구신 되는거 아닐까?(me2sms)2009-06-04 14:15:45
  • 올해들어 구매한 소프트비용 45만원.통신부가서비스 월평균 4.5만원(기본료제외)(me2sms)2009-06-04 14:31:34
  • 전혀 생각치도 못한 부분에서 걸렸다. 지금 내가 만드는 제품은 MS 계가 아닌지라, 다른 DBMS 서버도 생각해줘야 되는구나. 왜 MS SQL과 Oracle의 명령은 미묘하리 틀린거야…(제품차이 버전고려 짜증난다)2009-06-04 16:55:08
  • 오늘은 버스안에 사람이 넘많넹.앉아서가긴 틀린듯(me2mobile 출근버스 앉아가구 싶다)2009-06-05 08:40:26
  • 엠480들고 나와 무선인터넷 테스트 중 과연 이번전화요금 기대된다 쓰읍(me2mobile 데이터통신요금 도키도키 진짜 50만원나오면 X될듯)2009-06-05 08:46:17
  • 굥굥굥 하루의 시작이 또 되는군. 오늘만 지나면 주말인걸… 벌써.2009-06-05 09:30:59
  • 전번 강제 통합되믄 우짜지.. 010 으로 바뀌더라도, 국번은 유지됐으면 하는데, 원체 알 수 있어야지 원….(강제 통합 반대 정통부 갓뎀)2009-06-05 10:05:57
  • 자중하자, 자꾸 지름신이 왔다 갔다… 랩핏가지고 싶지만, 지금은 때가 아니다. 일단 기둘리자.. 조금더 기둘리자. 후덜덜덜(랩핏 지름신 듀얼모니터)2009-06-05 12:04:30
  • 내 전번으로 전화하면 이젠 M480으로 연결되게 착신 전환했심. 전화는 가급적 원래 폰으로 하지만, 받는거라면, M480으로…(착신전환 M480 와인폰 )2009-06-05 12:05:12
  • 점심 패스. 밥먹기 귀찮아지는데다, 피로도는 급상승 이래저래 식욕도 부진하고 몸도 피곤. 텐션을 올릴 수 있는 절호의 기회란 없을까?2009-06-05 12:07:27
  • 이전 회사가 조흥은행 거래 조흥은행 신한으로 먹힘. 신한이 주거래 은행으로 급상승. 회사 옮기니 국민은행. 오늘 잊지 않고 신한으로 월급 입금. 빨리 국민은행도 월급 통장으로 승격하면 자동 이체나 걸어야 겠다. 국민은행 大キライ!!!!!!!(국민은행은 나의 금융 이력에 오점을 남긴 아주 나쁜은행 싫은은행)2009-06-05 12:11:02
  • 이건 사진만들가면 딱인걸 멋짐 절라 멋지심(me2dayzm)2009-06-05 12:21:53
  • 미투 모바일 버젼은 생각보다 큰거 같네요. 오늘 미투하믄서 거의 200k 정도 썼네요.(me2dayzm 미투 모바일버젼 큼)2009-06-05 12:47:10
  • 시간의 흐름을 느끼는 순간 시간은 천천히 흐른다.(일 하기 싫다고 하지 그래)2009-06-05 14:14:20
  • 미투 APP 관련 메일링 리스트 걸었는데, 계속 떨어지는 메시지를 보면서 세상 참 빨리도 많이도 변하는 느낌.(무척이나 단편적인 사실을 모두의 진실로 변모시키려는 제멋대로의 생각)2009-06-05 14:15:39
  • C# 으로만 개발하는데, 세상은 Java도 있고, Perl도 있고, Ruby도 있고, PHP도 있고, 따라잡기 무척 힘든세상이 됐다.(뭔놈의 언어는 이렇게 무쟈게 찍어 대는겨)2009-06-05 14:21:32
  • C에서 C++로 C++에서 VBScript????로 VBScript에서 C#으로… 진화는 계속되어야 하는데, 왠지 지금까지 밟아온길이 MS 빠돌이네(MS 빠~ MS 종속적 오픈과는 거리가 먼건가?)2009-06-05 14:22:31
  • 코히(コーヒー,Coffee) 한잔 내려 노코, 담배 한대 빨믄서 JAZZ 선율에 코 흥얼거리며, 흔들거리는 안락의자에서 볼륨다 줄인 동영상을 바라보는 여유를 즐기고 싶다.(일하기 싫다는 표현의 또 다른 표현)2009-06-05 14:26:12
  • 살콤이 퇴근시간이 다가왔구나. 아니 지났구나. 이제 무거운 엉덩이를 들고 집으로 가야겠구나.(책상 정리중.)2009-06-05 18:28:36
  • GPS기능써볼려구 맵피도 알아보고 알맵도 알아 봤는데 아직은 M480은 지원하지 않는다넹 낭패…(me2dayzm)2009-06-05 19:03:55
  • 오늘은 밥을 머먹을까? 걍 집에가서 차려먹을까?(me2dayzm)2009-06-05 19:05:57
  • 도끼도끼 모드 중. 내 생애 최대 통신비를 기록헐거 같은디. 좋것네 SKT!!(me2dayzm)2009-06-05 19:07:21
  • 모바일로도 쓰기 시작허니깐 계속써지넹 시야와세~(me2dayzm)2009-06-05 20:02:14
  • 돈까스를 좋아하기에 일주일 평균 돈까스 먹는 양이 장난아님. 일주일 식사분의 2/3은 먹는거 같다(me2dayzm)2009-06-05 20:04:06
  • 합정역입니다 ㅋㅋ(me2dayzm)2009-06-05 20:04:33
  • 이거이 거의 스패머수준인뎅….(me2dayzm)2009-06-05 20:05:15
  • 소금구이 집이 왤캐많아!!!!(me2dayzm)2009-06-05 20:14:20
  • 로또샀다 대박나라~(me2dayzm)2009-06-05 20:16:01
  • 니마니마 매너 좀~~~~(me2dayzm)2009-06-05 20:17:45
  • 오웃 한가한 버스 하루 마무리가 좋은데!(me2dayzm)2009-06-05 20:19:20
  • 이거면 문자 보내는 스피드가 짱일듯.. 아 근디 메인폰에 미투SMS정액걸었는디.. 아까븐 느낌…(me2dayzm)2009-06-05 20:21:15
  • 오늘 묘하게 차막히넹 뭔일 있나… 아님 지금껏 쟈철타고 댕겨서 몰랐나?(me2dayzm)2009-06-05 20:23:10
  • 버스안에서 전화로 목청 테스트 하는넘 갓뎀이닷! 그래놓곤 딴사람이 목청테스트 하면 제일 지랄!(me2dayzm)2009-06-05 20:54:24

이 글은 하인도님의 2009년 6월 4일에서 2009년 6월 5일까지의 미투데이 내용입니다.

728x90

+ Recent posts

728x90